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, LanguageName, LanguageRegistry, LanguageScope, LocalFile, OffsetRangeExt,
  136    OutlineItem, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  137    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    auto_replace_emoji_shortcode: bool,
 1269    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1270    show_git_blame_gutter: bool,
 1271    show_git_blame_inline: bool,
 1272    show_git_blame_inline_delay_task: Option<Task<()>>,
 1273    git_blame_inline_enabled: bool,
 1274    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1275    buffer_serialization: Option<BufferSerialization>,
 1276    show_selection_menu: Option<bool>,
 1277    blame: Option<Entity<GitBlame>>,
 1278    blame_subscription: Option<Subscription>,
 1279    custom_context_menu: Option<
 1280        Box<
 1281            dyn 'static
 1282                + Fn(
 1283                    &mut Self,
 1284                    DisplayPoint,
 1285                    &mut Window,
 1286                    &mut Context<Self>,
 1287                ) -> Option<Entity<ui::ContextMenu>>,
 1288        >,
 1289    >,
 1290    last_bounds: Option<Bounds<Pixels>>,
 1291    last_position_map: Option<Rc<PositionMap>>,
 1292    expect_bounds_change: Option<Bounds<Pixels>>,
 1293    runnables: RunnableData,
 1294    breakpoint_store: Option<Entity<BreakpointStore>>,
 1295    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1296    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1297    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1298    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1299    /// when hunks have comments stored.
 1300    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1301    /// Stored review comments grouped by hunk.
 1302    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1303    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1304    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1305    /// Counter for generating unique comment IDs.
 1306    next_review_comment_id: usize,
 1307    hovered_diff_hunk_row: Option<DisplayRow>,
 1308    pull_diagnostics_task: Task<()>,
 1309    in_project_search: bool,
 1310    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1311    breadcrumb_header: Option<String>,
 1312    focused_block: Option<FocusedBlock>,
 1313    next_scroll_position: NextScrollCursorCenterTopBottom,
 1314    addons: HashMap<TypeId, Box<dyn Addon>>,
 1315    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1316    load_diff_task: Option<Shared<Task<()>>>,
 1317    /// Whether we are temporarily displaying a diff other than git's
 1318    temporary_diff_override: bool,
 1319    selection_mark_mode: bool,
 1320    toggle_fold_multiple_buffers: Task<()>,
 1321    _scroll_cursor_center_top_bottom_task: Task<()>,
 1322    serialize_selections: Task<()>,
 1323    serialize_folds: Task<()>,
 1324    mouse_cursor_hidden: bool,
 1325    minimap: Option<Entity<Self>>,
 1326    hide_mouse_mode: HideMouseMode,
 1327    pub change_list: ChangeList,
 1328    inline_value_cache: InlineValueCache,
 1329    number_deleted_lines: bool,
 1330
 1331    selection_drag_state: SelectionDragState,
 1332    colors: Option<LspColorData>,
 1333    post_scroll_update: Task<()>,
 1334    refresh_colors_task: Task<()>,
 1335    use_document_folding_ranges: bool,
 1336    refresh_folding_ranges_task: Task<()>,
 1337    inlay_hints: Option<LspInlayHintData>,
 1338    folding_newlines: Task<()>,
 1339    select_next_is_case_sensitive: Option<bool>,
 1340    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1341    on_local_selections_changed:
 1342        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1343    suppress_selection_callback: bool,
 1344    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1345    accent_data: Option<AccentData>,
 1346    bracket_fetched_tree_sitter_chunks: HashMap<Range<text::Anchor>, HashSet<Range<BufferRow>>>,
 1347    semantic_token_state: SemanticTokenState,
 1348    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1349    refresh_document_symbols_task: Shared<Task<()>>,
 1350    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1351    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1352    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1353    sticky_headers_task: Task<()>,
 1354    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1355    pub(crate) colorize_brackets_task: Task<()>,
 1356}
 1357
 1358#[derive(Debug, PartialEq)]
 1359struct AccentData {
 1360    colors: AccentColors,
 1361    overrides: Vec<SharedString>,
 1362}
 1363
 1364fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1365    if debounce_ms > 0 {
 1366        Some(Duration::from_millis(debounce_ms))
 1367    } else {
 1368        None
 1369    }
 1370}
 1371
 1372#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1373enum NextScrollCursorCenterTopBottom {
 1374    #[default]
 1375    Center,
 1376    Top,
 1377    Bottom,
 1378}
 1379
 1380impl NextScrollCursorCenterTopBottom {
 1381    fn next(&self) -> Self {
 1382        match self {
 1383            Self::Center => Self::Top,
 1384            Self::Top => Self::Bottom,
 1385            Self::Bottom => Self::Center,
 1386        }
 1387    }
 1388}
 1389
 1390#[derive(Clone)]
 1391pub struct EditorSnapshot {
 1392    pub mode: EditorMode,
 1393    show_gutter: bool,
 1394    offset_content: bool,
 1395    show_line_numbers: Option<bool>,
 1396    number_deleted_lines: bool,
 1397    show_git_diff_gutter: Option<bool>,
 1398    show_code_actions: Option<bool>,
 1399    show_runnables: Option<bool>,
 1400    show_breakpoints: Option<bool>,
 1401    git_blame_gutter_max_author_length: Option<usize>,
 1402    pub display_snapshot: DisplaySnapshot,
 1403    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1404    is_focused: bool,
 1405    scroll_anchor: SharedScrollAnchor,
 1406    ongoing_scroll: OngoingScroll,
 1407    current_line_highlight: CurrentLineHighlight,
 1408    gutter_hovered: bool,
 1409    semantic_tokens_enabled: bool,
 1410}
 1411
 1412#[derive(Default, Debug, Clone, Copy)]
 1413pub struct GutterDimensions {
 1414    pub left_padding: Pixels,
 1415    pub right_padding: Pixels,
 1416    pub width: Pixels,
 1417    pub margin: Pixels,
 1418    pub git_blame_entries_width: Option<Pixels>,
 1419}
 1420
 1421impl GutterDimensions {
 1422    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1423        Self {
 1424            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1425            ..Default::default()
 1426        }
 1427    }
 1428
 1429    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1430        -cx.text_system().descent(font_id, font_size)
 1431    }
 1432    /// The full width of the space taken up by the gutter.
 1433    pub fn full_width(&self) -> Pixels {
 1434        self.margin + self.width
 1435    }
 1436
 1437    /// The width of the space reserved for the fold indicators,
 1438    /// use alongside 'justify_end' and `gutter_width` to
 1439    /// right align content with the line numbers
 1440    pub fn fold_area_width(&self) -> Pixels {
 1441        self.margin + self.right_padding
 1442    }
 1443}
 1444
 1445struct CharacterDimensions {
 1446    em_width: Pixels,
 1447    em_advance: Pixels,
 1448    line_height: Pixels,
 1449}
 1450
 1451#[derive(Debug)]
 1452pub struct RemoteSelection {
 1453    pub replica_id: ReplicaId,
 1454    pub selection: Selection<Anchor>,
 1455    pub cursor_shape: CursorShape,
 1456    pub collaborator_id: CollaboratorId,
 1457    pub line_mode: bool,
 1458    pub user_name: Option<SharedString>,
 1459    pub color: PlayerColor,
 1460}
 1461
 1462#[derive(Clone, Debug)]
 1463struct SelectionHistoryEntry {
 1464    selections: Arc<[Selection<Anchor>]>,
 1465    select_next_state: Option<SelectNextState>,
 1466    select_prev_state: Option<SelectNextState>,
 1467    add_selections_state: Option<AddSelectionsState>,
 1468}
 1469
 1470#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1471enum SelectionHistoryMode {
 1472    #[default]
 1473    Normal,
 1474    Undoing,
 1475    Redoing,
 1476    Skipping,
 1477}
 1478
 1479#[derive(Clone, PartialEq, Eq, Hash)]
 1480struct HoveredCursor {
 1481    replica_id: ReplicaId,
 1482    selection_id: usize,
 1483}
 1484
 1485#[derive(Debug)]
 1486/// SelectionEffects controls the side-effects of updating the selection.
 1487///
 1488/// The default behaviour does "what you mostly want":
 1489/// - it pushes to the nav history if the cursor moved by >10 lines
 1490/// - it re-triggers completion requests
 1491/// - it scrolls to fit
 1492///
 1493/// You might want to modify these behaviours. For example when doing a "jump"
 1494/// like go to definition, we always want to add to nav history; but when scrolling
 1495/// in vim mode we never do.
 1496///
 1497/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1498/// move.
 1499#[derive(Clone)]
 1500pub struct SelectionEffects {
 1501    nav_history: Option<bool>,
 1502    completions: bool,
 1503    scroll: Option<Autoscroll>,
 1504}
 1505
 1506impl Default for SelectionEffects {
 1507    fn default() -> Self {
 1508        Self {
 1509            nav_history: None,
 1510            completions: true,
 1511            scroll: Some(Autoscroll::fit()),
 1512        }
 1513    }
 1514}
 1515impl SelectionEffects {
 1516    pub fn scroll(scroll: Autoscroll) -> Self {
 1517        Self {
 1518            scroll: Some(scroll),
 1519            ..Default::default()
 1520        }
 1521    }
 1522
 1523    pub fn no_scroll() -> Self {
 1524        Self {
 1525            scroll: None,
 1526            ..Default::default()
 1527        }
 1528    }
 1529
 1530    pub fn completions(self, completions: bool) -> Self {
 1531        Self {
 1532            completions,
 1533            ..self
 1534        }
 1535    }
 1536
 1537    pub fn nav_history(self, nav_history: bool) -> Self {
 1538        Self {
 1539            nav_history: Some(nav_history),
 1540            ..self
 1541        }
 1542    }
 1543}
 1544
 1545struct DeferredSelectionEffectsState {
 1546    changed: bool,
 1547    effects: SelectionEffects,
 1548    old_cursor_position: Anchor,
 1549    history_entry: SelectionHistoryEntry,
 1550}
 1551
 1552#[derive(Default)]
 1553struct SelectionHistory {
 1554    #[allow(clippy::type_complexity)]
 1555    selections_by_transaction:
 1556        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1557    mode: SelectionHistoryMode,
 1558    undo_stack: VecDeque<SelectionHistoryEntry>,
 1559    redo_stack: VecDeque<SelectionHistoryEntry>,
 1560}
 1561
 1562impl SelectionHistory {
 1563    #[track_caller]
 1564    fn insert_transaction(
 1565        &mut self,
 1566        transaction_id: TransactionId,
 1567        selections: Arc<[Selection<Anchor>]>,
 1568    ) {
 1569        if selections.is_empty() {
 1570            log::error!(
 1571                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1572                std::panic::Location::caller()
 1573            );
 1574            return;
 1575        }
 1576        self.selections_by_transaction
 1577            .insert(transaction_id, (selections, None));
 1578    }
 1579
 1580    #[allow(clippy::type_complexity)]
 1581    fn transaction(
 1582        &self,
 1583        transaction_id: TransactionId,
 1584    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1585        self.selections_by_transaction.get(&transaction_id)
 1586    }
 1587
 1588    #[allow(clippy::type_complexity)]
 1589    fn transaction_mut(
 1590        &mut self,
 1591        transaction_id: TransactionId,
 1592    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1593        self.selections_by_transaction.get_mut(&transaction_id)
 1594    }
 1595
 1596    fn push(&mut self, entry: SelectionHistoryEntry) {
 1597        if !entry.selections.is_empty() {
 1598            match self.mode {
 1599                SelectionHistoryMode::Normal => {
 1600                    self.push_undo(entry);
 1601                    self.redo_stack.clear();
 1602                }
 1603                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1604                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1605                SelectionHistoryMode::Skipping => {}
 1606            }
 1607        }
 1608    }
 1609
 1610    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1611        if self
 1612            .undo_stack
 1613            .back()
 1614            .is_none_or(|e| e.selections != entry.selections)
 1615        {
 1616            self.undo_stack.push_back(entry);
 1617            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1618                self.undo_stack.pop_front();
 1619            }
 1620        }
 1621    }
 1622
 1623    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1624        if self
 1625            .redo_stack
 1626            .back()
 1627            .is_none_or(|e| e.selections != entry.selections)
 1628        {
 1629            self.redo_stack.push_back(entry);
 1630            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1631                self.redo_stack.pop_front();
 1632            }
 1633        }
 1634    }
 1635}
 1636
 1637#[derive(Clone, Copy)]
 1638pub struct RowHighlightOptions {
 1639    pub autoscroll: bool,
 1640    pub include_gutter: bool,
 1641}
 1642
 1643impl Default for RowHighlightOptions {
 1644    fn default() -> Self {
 1645        Self {
 1646            autoscroll: Default::default(),
 1647            include_gutter: true,
 1648        }
 1649    }
 1650}
 1651
 1652struct RowHighlight {
 1653    index: usize,
 1654    range: Range<Anchor>,
 1655    color: Hsla,
 1656    options: RowHighlightOptions,
 1657    type_id: TypeId,
 1658}
 1659
 1660#[derive(Clone, Debug)]
 1661struct AddSelectionsState {
 1662    groups: Vec<AddSelectionsGroup>,
 1663}
 1664
 1665#[derive(Clone, Debug)]
 1666struct AddSelectionsGroup {
 1667    above: bool,
 1668    stack: Vec<usize>,
 1669}
 1670
 1671#[derive(Clone)]
 1672struct SelectNextState {
 1673    query: AhoCorasick,
 1674    wordwise: bool,
 1675    done: bool,
 1676}
 1677
 1678impl std::fmt::Debug for SelectNextState {
 1679    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1680        f.debug_struct(std::any::type_name::<Self>())
 1681            .field("wordwise", &self.wordwise)
 1682            .field("done", &self.done)
 1683            .finish()
 1684    }
 1685}
 1686
 1687#[derive(Debug)]
 1688struct AutocloseRegion {
 1689    selection_id: usize,
 1690    range: Range<Anchor>,
 1691    pair: BracketPair,
 1692}
 1693
 1694#[derive(Debug)]
 1695struct SnippetState {
 1696    ranges: Vec<Vec<Range<Anchor>>>,
 1697    active_index: usize,
 1698    choices: Vec<Option<Vec<String>>>,
 1699}
 1700
 1701#[doc(hidden)]
 1702pub struct RenameState {
 1703    pub range: Range<Anchor>,
 1704    pub old_name: Arc<str>,
 1705    pub editor: Entity<Editor>,
 1706    block_id: CustomBlockId,
 1707}
 1708
 1709struct InvalidationStack<T>(Vec<T>);
 1710
 1711struct RegisteredEditPredictionDelegate {
 1712    provider: Arc<dyn EditPredictionDelegateHandle>,
 1713    _subscription: Subscription,
 1714}
 1715
 1716#[derive(Debug, PartialEq, Eq)]
 1717pub struct ActiveDiagnosticGroup {
 1718    pub active_range: Range<Anchor>,
 1719    pub active_message: String,
 1720    pub group_id: usize,
 1721    pub blocks: HashSet<CustomBlockId>,
 1722}
 1723
 1724#[derive(Debug, PartialEq, Eq)]
 1725
 1726pub(crate) enum ActiveDiagnostic {
 1727    None,
 1728    All,
 1729    Group(ActiveDiagnosticGroup),
 1730}
 1731
 1732#[derive(Serialize, Deserialize, Clone, Debug)]
 1733pub struct ClipboardSelection {
 1734    /// The number of bytes in this selection.
 1735    pub len: usize,
 1736    /// Whether this was a full-line selection.
 1737    pub is_entire_line: bool,
 1738    /// The indentation of the first line when this content was originally copied.
 1739    pub first_line_indent: u32,
 1740    #[serde(default)]
 1741    pub file_path: Option<PathBuf>,
 1742    #[serde(default)]
 1743    pub line_range: Option<RangeInclusive<u32>>,
 1744}
 1745
 1746impl ClipboardSelection {
 1747    pub fn for_buffer(
 1748        len: usize,
 1749        is_entire_line: bool,
 1750        range: Range<Point>,
 1751        buffer: &MultiBufferSnapshot,
 1752        project: Option<&Entity<Project>>,
 1753        cx: &App,
 1754    ) -> Self {
 1755        let first_line_indent = buffer
 1756            .indent_size_for_line(MultiBufferRow(range.start.row))
 1757            .len;
 1758
 1759        let file_path = util::maybe!({
 1760            let project = project?.read(cx);
 1761            let file = buffer.file_at(range.start)?;
 1762            let project_path = ProjectPath {
 1763                worktree_id: file.worktree_id(cx),
 1764                path: file.path().clone(),
 1765            };
 1766            project.absolute_path(&project_path, cx)
 1767        });
 1768
 1769        let line_range = if file_path.is_some() {
 1770            buffer
 1771                .range_to_buffer_range(range)
 1772                .map(|(_, buffer_range)| buffer_range.start.row..=buffer_range.end.row)
 1773        } else {
 1774            None
 1775        };
 1776
 1777        Self {
 1778            len,
 1779            is_entire_line,
 1780            first_line_indent,
 1781            file_path,
 1782            line_range,
 1783        }
 1784    }
 1785}
 1786
 1787// selections, scroll behavior, was newest selection reversed
 1788type SelectSyntaxNodeHistoryState = (
 1789    Box<[Selection<Anchor>]>,
 1790    SelectSyntaxNodeScrollBehavior,
 1791    bool,
 1792);
 1793
 1794#[derive(Default)]
 1795struct SelectSyntaxNodeHistory {
 1796    stack: Vec<SelectSyntaxNodeHistoryState>,
 1797    // disable temporarily to allow changing selections without losing the stack
 1798    pub disable_clearing: bool,
 1799}
 1800
 1801impl SelectSyntaxNodeHistory {
 1802    pub fn try_clear(&mut self) {
 1803        if !self.disable_clearing {
 1804            self.stack.clear();
 1805        }
 1806    }
 1807
 1808    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1809        self.stack.push(selection);
 1810    }
 1811
 1812    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1813        self.stack.pop()
 1814    }
 1815}
 1816
 1817enum SelectSyntaxNodeScrollBehavior {
 1818    CursorTop,
 1819    FitSelection,
 1820    CursorBottom,
 1821}
 1822
 1823#[derive(Debug, Clone, Copy)]
 1824pub(crate) struct NavigationData {
 1825    cursor_anchor: Anchor,
 1826    cursor_position: Point,
 1827    scroll_anchor: ScrollAnchor,
 1828    scroll_top_row: u32,
 1829}
 1830
 1831#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1832pub enum GotoDefinitionKind {
 1833    Symbol,
 1834    Declaration,
 1835    Type,
 1836    Implementation,
 1837}
 1838
 1839pub enum FormatTarget {
 1840    Buffers(HashSet<Entity<Buffer>>),
 1841    Ranges(Vec<Range<MultiBufferPoint>>),
 1842}
 1843
 1844pub(crate) struct FocusedBlock {
 1845    id: BlockId,
 1846    focus_handle: WeakFocusHandle,
 1847}
 1848
 1849#[derive(Clone, Debug)]
 1850pub enum JumpData {
 1851    MultiBufferRow {
 1852        row: MultiBufferRow,
 1853        line_offset_from_top: u32,
 1854    },
 1855    MultiBufferPoint {
 1856        anchor: language::Anchor,
 1857        position: Point,
 1858        line_offset_from_top: u32,
 1859    },
 1860}
 1861
 1862pub enum MultibufferSelectionMode {
 1863    First,
 1864    All,
 1865}
 1866
 1867#[derive(Clone, Copy, Debug, Default)]
 1868pub struct RewrapOptions {
 1869    pub override_language_settings: bool,
 1870    pub preserve_existing_whitespace: bool,
 1871    pub line_length: Option<usize>,
 1872}
 1873
 1874impl Editor {
 1875    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1876        let buffer = cx.new(|cx| Buffer::local("", cx));
 1877        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1878        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1879    }
 1880
 1881    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1882        let buffer = cx.new(|cx| Buffer::local("", cx));
 1883        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1884        Self::new(EditorMode::full(), buffer, None, window, cx)
 1885    }
 1886
 1887    pub fn auto_height(
 1888        min_lines: usize,
 1889        max_lines: usize,
 1890        window: &mut Window,
 1891        cx: &mut Context<Self>,
 1892    ) -> Self {
 1893        let buffer = cx.new(|cx| Buffer::local("", cx));
 1894        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1895        Self::new(
 1896            EditorMode::AutoHeight {
 1897                min_lines,
 1898                max_lines: Some(max_lines),
 1899            },
 1900            buffer,
 1901            None,
 1902            window,
 1903            cx,
 1904        )
 1905    }
 1906
 1907    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1908    /// The editor grows as tall as needed to fit its content.
 1909    pub fn auto_height_unbounded(
 1910        min_lines: usize,
 1911        window: &mut Window,
 1912        cx: &mut Context<Self>,
 1913    ) -> Self {
 1914        let buffer = cx.new(|cx| Buffer::local("", cx));
 1915        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1916        Self::new(
 1917            EditorMode::AutoHeight {
 1918                min_lines,
 1919                max_lines: None,
 1920            },
 1921            buffer,
 1922            None,
 1923            window,
 1924            cx,
 1925        )
 1926    }
 1927
 1928    pub fn for_buffer(
 1929        buffer: Entity<Buffer>,
 1930        project: Option<Entity<Project>>,
 1931        window: &mut Window,
 1932        cx: &mut Context<Self>,
 1933    ) -> Self {
 1934        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1935        Self::new(EditorMode::full(), buffer, project, window, cx)
 1936    }
 1937
 1938    pub fn for_multibuffer(
 1939        buffer: Entity<MultiBuffer>,
 1940        project: Option<Entity<Project>>,
 1941        window: &mut Window,
 1942        cx: &mut Context<Self>,
 1943    ) -> Self {
 1944        Self::new(EditorMode::full(), buffer, project, window, cx)
 1945    }
 1946
 1947    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1948        let mut clone = Self::new(
 1949            self.mode.clone(),
 1950            self.buffer.clone(),
 1951            self.project.clone(),
 1952            window,
 1953            cx,
 1954        );
 1955        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1956            let snapshot = display_map.snapshot(cx);
 1957            clone.display_map.update(cx, |display_map, cx| {
 1958                display_map.set_state(&snapshot, cx);
 1959            });
 1960            snapshot
 1961        });
 1962        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1963        clone.folds_did_change(cx);
 1964        clone.selections.clone_state(&self.selections);
 1965        clone
 1966            .scroll_manager
 1967            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1968        clone.searchable = self.searchable;
 1969        clone.read_only = self.read_only;
 1970        clone.buffers_with_disabled_indent_guides =
 1971            self.buffers_with_disabled_indent_guides.clone();
 1972        clone
 1973    }
 1974
 1975    pub fn new(
 1976        mode: EditorMode,
 1977        buffer: Entity<MultiBuffer>,
 1978        project: Option<Entity<Project>>,
 1979        window: &mut Window,
 1980        cx: &mut Context<Self>,
 1981    ) -> Self {
 1982        Editor::new_internal(mode, buffer, project, None, window, cx)
 1983    }
 1984
 1985    pub fn refresh_sticky_headers(
 1986        &mut self,
 1987        display_snapshot: &DisplaySnapshot,
 1988        cx: &mut Context<Editor>,
 1989    ) {
 1990        if !self.mode.is_full() {
 1991            return;
 1992        }
 1993        let multi_buffer = display_snapshot.buffer_snapshot().clone();
 1994        let scroll_anchor = self
 1995            .scroll_manager
 1996            .native_anchor(display_snapshot, cx)
 1997            .anchor;
 1998        let Some(buffer_snapshot) = multi_buffer.as_singleton() else {
 1999            return;
 2000        };
 2001
 2002        let buffer = buffer_snapshot.clone();
 2003        let Some((buffer_visible_start, _)) = multi_buffer.anchor_to_buffer_anchor(scroll_anchor)
 2004        else {
 2005            return;
 2006        };
 2007        let buffer_visible_start = buffer_visible_start.to_point(&buffer);
 2008        let max_row = buffer.max_point().row;
 2009        let start_row = buffer_visible_start.row.min(max_row);
 2010        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2011
 2012        let syntax = self.style(cx).syntax.clone();
 2013        let background_task = cx.background_spawn(async move {
 2014            buffer
 2015                .outline_items_containing(
 2016                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2017                    true,
 2018                    Some(syntax.as_ref()),
 2019                )
 2020                .into_iter()
 2021                .filter_map(|outline_item| {
 2022                    Some(OutlineItem {
 2023                        depth: outline_item.depth,
 2024                        range: multi_buffer
 2025                            .buffer_anchor_range_to_anchor_range(outline_item.range)?,
 2026                        source_range_for_text: multi_buffer.buffer_anchor_range_to_anchor_range(
 2027                            outline_item.source_range_for_text,
 2028                        )?,
 2029                        text: outline_item.text,
 2030                        highlight_ranges: outline_item.highlight_ranges,
 2031                        name_ranges: outline_item.name_ranges,
 2032                        body_range: outline_item.body_range.and_then(|range| {
 2033                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2034                        }),
 2035                        annotation_range: outline_item.annotation_range.and_then(|range| {
 2036                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2037                        }),
 2038                    })
 2039                })
 2040                .collect()
 2041        });
 2042        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2043            let sticky_headers = background_task.await;
 2044            this.update(cx, |this, cx| {
 2045                this.sticky_headers = Some(sticky_headers);
 2046                cx.notify();
 2047            })
 2048            .ok();
 2049        });
 2050    }
 2051
 2052    fn new_internal(
 2053        mode: EditorMode,
 2054        multi_buffer: Entity<MultiBuffer>,
 2055        project: Option<Entity<Project>>,
 2056        display_map: Option<Entity<DisplayMap>>,
 2057        window: &mut Window,
 2058        cx: &mut Context<Self>,
 2059    ) -> Self {
 2060        debug_assert!(
 2061            display_map.is_none() || mode.is_minimap(),
 2062            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2063        );
 2064
 2065        let full_mode = mode.is_full();
 2066        let is_minimap = mode.is_minimap();
 2067        let diagnostics_max_severity = if full_mode {
 2068            EditorSettings::get_global(cx)
 2069                .diagnostics_max_severity
 2070                .unwrap_or(DiagnosticSeverity::Hint)
 2071        } else {
 2072            DiagnosticSeverity::Off
 2073        };
 2074        let style = window.text_style();
 2075        let font_size = style.font_size.to_pixels(window.rem_size());
 2076        let editor = cx.entity().downgrade();
 2077        let fold_placeholder = FoldPlaceholder {
 2078            constrain_width: false,
 2079            render: Arc::new(move |fold_id, fold_range, cx| {
 2080                let editor = editor.clone();
 2081                FoldPlaceholder::fold_element(fold_id, cx)
 2082                    .cursor_pointer()
 2083                    .child("")
 2084                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2085                    .on_click(move |_, _window, cx| {
 2086                        editor
 2087                            .update(cx, |editor, cx| {
 2088                                editor.unfold_ranges(
 2089                                    &[fold_range.start..fold_range.end],
 2090                                    true,
 2091                                    false,
 2092                                    cx,
 2093                                );
 2094                                cx.stop_propagation();
 2095                            })
 2096                            .ok();
 2097                    })
 2098                    .into_any()
 2099            }),
 2100            merge_adjacent: true,
 2101            ..FoldPlaceholder::default()
 2102        };
 2103        let display_map = display_map.unwrap_or_else(|| {
 2104            cx.new(|cx| {
 2105                DisplayMap::new(
 2106                    multi_buffer.clone(),
 2107                    style.font(),
 2108                    font_size,
 2109                    None,
 2110                    FILE_HEADER_HEIGHT,
 2111                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2112                    fold_placeholder,
 2113                    diagnostics_max_severity,
 2114                    cx,
 2115                )
 2116            })
 2117        });
 2118
 2119        let selections = SelectionsCollection::new();
 2120
 2121        let blink_manager = cx.new(|cx| {
 2122            let mut blink_manager = BlinkManager::new(
 2123                CURSOR_BLINK_INTERVAL,
 2124                |cx| EditorSettings::get_global(cx).cursor_blink,
 2125                cx,
 2126            );
 2127            if is_minimap {
 2128                blink_manager.disable(cx);
 2129            }
 2130            blink_manager
 2131        });
 2132
 2133        let soft_wrap_mode_override =
 2134            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2135
 2136        let mut project_subscriptions = Vec::new();
 2137        if full_mode && let Some(project) = project.as_ref() {
 2138            project_subscriptions.push(cx.subscribe_in(
 2139                project,
 2140                window,
 2141                |editor, _, event, window, cx| match event {
 2142                    project::Event::RefreshCodeLens => {
 2143                        // we always query lens with actions, without storing them, always refreshing them
 2144                    }
 2145                    project::Event::RefreshInlayHints {
 2146                        server_id,
 2147                        request_id,
 2148                    } => {
 2149                        editor.refresh_inlay_hints(
 2150                            InlayHintRefreshReason::RefreshRequested {
 2151                                server_id: *server_id,
 2152                                request_id: *request_id,
 2153                            },
 2154                            cx,
 2155                        );
 2156                    }
 2157                    project::Event::RefreshSemanticTokens {
 2158                        server_id,
 2159                        request_id,
 2160                    } => {
 2161                        editor.refresh_semantic_tokens(
 2162                            None,
 2163                            Some(RefreshForServer {
 2164                                server_id: *server_id,
 2165                                request_id: *request_id,
 2166                            }),
 2167                            cx,
 2168                        );
 2169                    }
 2170                    project::Event::LanguageServerRemoved(_) => {
 2171                        editor.registered_buffers.clear();
 2172                        editor.register_visible_buffers(cx);
 2173                        editor.invalidate_semantic_tokens(None);
 2174                        editor.refresh_runnables(None, window, cx);
 2175                        editor.update_lsp_data(None, window, cx);
 2176                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2177                    }
 2178                    project::Event::SnippetEdit(id, snippet_edits) => {
 2179                        // todo(lw): Non singletons
 2180                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2181                            let snapshot = buffer.read(cx).snapshot();
 2182                            let focus_handle = editor.focus_handle(cx);
 2183                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2184                                for (range, snippet) in snippet_edits {
 2185                                    let buffer_range =
 2186                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2187                                    editor
 2188                                        .insert_snippet(
 2189                                            &[MultiBufferOffset(buffer_range.start)
 2190                                                ..MultiBufferOffset(buffer_range.end)],
 2191                                            snippet.clone(),
 2192                                            window,
 2193                                            cx,
 2194                                        )
 2195                                        .ok();
 2196                                }
 2197                            }
 2198                        }
 2199                    }
 2200                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2201                        let buffer_id = *buffer_id;
 2202                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2203                            editor.register_buffer(buffer_id, cx);
 2204                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2205                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2206                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2207                            refresh_linked_ranges(editor, window, cx);
 2208                            editor.refresh_code_actions(window, cx);
 2209                            editor.refresh_document_highlights(cx);
 2210                        }
 2211                    }
 2212
 2213                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2214                        let Some(workspace) = editor.workspace() else {
 2215                            return;
 2216                        };
 2217                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2218                        else {
 2219                            return;
 2220                        };
 2221
 2222                        if active_editor.entity_id() == cx.entity_id() {
 2223                            let entity_id = cx.entity_id();
 2224                            workspace.update(cx, |this, cx| {
 2225                                this.panes_mut()
 2226                                    .iter_mut()
 2227                                    .filter(|pane| pane.entity_id() != entity_id)
 2228                                    .for_each(|p| {
 2229                                        p.update(cx, |pane, _| {
 2230                                            pane.nav_history_mut().rename_item(
 2231                                                entity_id,
 2232                                                project_path.clone(),
 2233                                                abs_path.clone().into(),
 2234                                            );
 2235                                        })
 2236                                    });
 2237                            });
 2238
 2239                            Self::open_transaction_for_hidden_buffers(
 2240                                workspace,
 2241                                transaction.clone(),
 2242                                "Rename".to_string(),
 2243                                window,
 2244                                cx,
 2245                            );
 2246                        }
 2247                    }
 2248
 2249                    project::Event::WorkspaceEditApplied(transaction) => {
 2250                        let Some(workspace) = editor.workspace() else {
 2251                            return;
 2252                        };
 2253                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2254                        else {
 2255                            return;
 2256                        };
 2257
 2258                        if active_editor.entity_id() == cx.entity_id() {
 2259                            Self::open_transaction_for_hidden_buffers(
 2260                                workspace,
 2261                                transaction.clone(),
 2262                                "LSP Edit".to_string(),
 2263                                window,
 2264                                cx,
 2265                            );
 2266                        }
 2267                    }
 2268
 2269                    _ => {}
 2270                },
 2271            ));
 2272            if let Some(task_inventory) = project
 2273                .read(cx)
 2274                .task_store()
 2275                .read(cx)
 2276                .task_inventory()
 2277                .cloned()
 2278            {
 2279                project_subscriptions.push(cx.observe_in(
 2280                    &task_inventory,
 2281                    window,
 2282                    |editor, _, window, cx| {
 2283                        editor.refresh_runnables(None, window, cx);
 2284                    },
 2285                ));
 2286            };
 2287
 2288            project_subscriptions.push(cx.subscribe_in(
 2289                &project.read(cx).breakpoint_store(),
 2290                window,
 2291                |editor, _, event, window, cx| match event {
 2292                    BreakpointStoreEvent::ClearDebugLines => {
 2293                        editor.clear_row_highlights::<ActiveDebugLine>();
 2294                        editor.refresh_inline_values(cx);
 2295                    }
 2296                    BreakpointStoreEvent::SetDebugLine => {
 2297                        if editor.go_to_active_debug_line(window, cx) {
 2298                            cx.stop_propagation();
 2299                        }
 2300
 2301                        editor.refresh_inline_values(cx);
 2302                    }
 2303                    _ => {}
 2304                },
 2305            ));
 2306            let git_store = project.read(cx).git_store().clone();
 2307            let project = project.clone();
 2308            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2309                if let GitStoreEvent::RepositoryAdded = event {
 2310                    this.load_diff_task = Some(
 2311                        update_uncommitted_diff_for_buffer(
 2312                            cx.entity(),
 2313                            &project,
 2314                            this.buffer.read(cx).all_buffers(),
 2315                            this.buffer.clone(),
 2316                            cx,
 2317                        )
 2318                        .shared(),
 2319                    );
 2320                }
 2321            }));
 2322        }
 2323
 2324        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2325
 2326        let inlay_hint_settings =
 2327            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2328        let focus_handle = cx.focus_handle();
 2329        if !is_minimap {
 2330            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2331                .detach();
 2332            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2333                .detach();
 2334            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2335                .detach();
 2336            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2337                .detach();
 2338            cx.observe_pending_input(window, Self::observe_pending_input)
 2339                .detach();
 2340        }
 2341
 2342        let show_indent_guides =
 2343            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2344                Some(false)
 2345            } else {
 2346                None
 2347            };
 2348
 2349        let breakpoint_store = match (&mode, project.as_ref()) {
 2350            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2351            _ => None,
 2352        };
 2353
 2354        let mut code_action_providers = Vec::new();
 2355        let mut load_uncommitted_diff = None;
 2356        if let Some(project) = project.clone() {
 2357            load_uncommitted_diff = Some(
 2358                update_uncommitted_diff_for_buffer(
 2359                    cx.entity(),
 2360                    &project,
 2361                    multi_buffer.read(cx).all_buffers(),
 2362                    multi_buffer.clone(),
 2363                    cx,
 2364                )
 2365                .shared(),
 2366            );
 2367            code_action_providers.push(Rc::new(project) as Rc<_>);
 2368        }
 2369
 2370        let mut editor = Self {
 2371            focus_handle,
 2372            show_cursor_when_unfocused: false,
 2373            last_focused_descendant: None,
 2374            buffer: multi_buffer.clone(),
 2375            display_map: display_map.clone(),
 2376            placeholder_display_map: None,
 2377            selections,
 2378            scroll_manager: ScrollManager::new(cx),
 2379            columnar_selection_state: None,
 2380            add_selections_state: None,
 2381            select_next_state: None,
 2382            select_prev_state: None,
 2383            selection_history: SelectionHistory::default(),
 2384            defer_selection_effects: false,
 2385            deferred_selection_effects_state: None,
 2386            autoclose_regions: Vec::new(),
 2387            snippet_stack: InvalidationStack::default(),
 2388            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2389            ime_transaction: None,
 2390            active_diagnostics: ActiveDiagnostic::None,
 2391            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2392            inline_diagnostics_update: Task::ready(()),
 2393            inline_diagnostics: Vec::new(),
 2394            soft_wrap_mode_override,
 2395            diagnostics_max_severity,
 2396            hard_wrap: None,
 2397            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2398            semantics_provider: project
 2399                .as_ref()
 2400                .map(|project| Rc::new(project.downgrade()) as _),
 2401            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2402            project,
 2403            blink_manager: blink_manager.clone(),
 2404            show_local_selections: true,
 2405            show_scrollbars: ScrollbarAxes {
 2406                horizontal: full_mode,
 2407                vertical: full_mode,
 2408            },
 2409            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2410            offset_content: !matches!(mode, EditorMode::SingleLine),
 2411            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2412            show_gutter: full_mode,
 2413            show_line_numbers: (!full_mode).then_some(false),
 2414            use_relative_line_numbers: None,
 2415            disable_expand_excerpt_buttons: !full_mode,
 2416            delegate_expand_excerpts: false,
 2417            delegate_stage_and_restore: false,
 2418            delegate_open_excerpts: false,
 2419            enable_lsp_data: true,
 2420            enable_runnables: true,
 2421            show_git_diff_gutter: None,
 2422            show_code_actions: None,
 2423            show_runnables: None,
 2424            show_breakpoints: None,
 2425            show_diff_review_button: false,
 2426            show_wrap_guides: None,
 2427            show_indent_guides,
 2428            buffers_with_disabled_indent_guides: HashSet::default(),
 2429            highlight_order: 0,
 2430            highlighted_rows: HashMap::default(),
 2431            background_highlights: HashMap::default(),
 2432            gutter_highlights: HashMap::default(),
 2433            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2434            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2435            nav_history: None,
 2436            context_menu: RefCell::new(None),
 2437            context_menu_options: None,
 2438            mouse_context_menu: None,
 2439            completion_tasks: Vec::new(),
 2440            inline_blame_popover: None,
 2441            inline_blame_popover_show_task: None,
 2442            signature_help_state: SignatureHelpState::default(),
 2443            auto_signature_help: None,
 2444            find_all_references_task_sources: Vec::new(),
 2445            next_completion_id: 0,
 2446            next_inlay_id: 0,
 2447            code_action_providers,
 2448            available_code_actions: None,
 2449            code_actions_task: None,
 2450            quick_selection_highlight_task: None,
 2451            debounced_selection_highlight_task: None,
 2452            debounced_selection_highlight_complete: false,
 2453            document_highlights_task: None,
 2454            linked_editing_range_task: None,
 2455            pending_rename: None,
 2456            searchable: !is_minimap,
 2457            cursor_shape: EditorSettings::get_global(cx)
 2458                .cursor_shape
 2459                .unwrap_or_default(),
 2460            cursor_offset_on_selection: false,
 2461            current_line_highlight: None,
 2462            autoindent_mode: Some(AutoindentMode::EachLine),
 2463            collapse_matches: false,
 2464            workspace: None,
 2465            input_enabled: !is_minimap,
 2466            expects_character_input: !is_minimap,
 2467            use_modal_editing: full_mode,
 2468            read_only: is_minimap,
 2469            use_autoclose: true,
 2470            use_auto_surround: true,
 2471            auto_replace_emoji_shortcode: false,
 2472            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2473            leader_id: None,
 2474            remote_id: None,
 2475            hover_state: HoverState::default(),
 2476            pending_mouse_down: None,
 2477            prev_pressure_stage: None,
 2478            hovered_link_state: None,
 2479            edit_prediction_provider: None,
 2480            active_edit_prediction: None,
 2481            stale_edit_prediction_in_menu: None,
 2482            edit_prediction_preview: EditPredictionPreview::Inactive {
 2483                released_too_fast: false,
 2484            },
 2485            inline_diagnostics_enabled: full_mode,
 2486            diagnostics_enabled: full_mode,
 2487            word_completions_enabled: full_mode,
 2488            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2489            gutter_hovered: false,
 2490            pixel_position_of_newest_cursor: None,
 2491            last_bounds: None,
 2492            last_position_map: None,
 2493            expect_bounds_change: None,
 2494            gutter_dimensions: GutterDimensions::default(),
 2495            style: None,
 2496            show_cursor_names: false,
 2497            hovered_cursors: HashMap::default(),
 2498            next_editor_action_id: EditorActionId::default(),
 2499            editor_actions: Rc::default(),
 2500            edit_predictions_hidden_for_vim_mode: false,
 2501            show_edit_predictions_override: None,
 2502            show_completions_on_input_override: None,
 2503            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2504            edit_prediction_settings: EditPredictionSettings::Disabled,
 2505            in_leading_whitespace: false,
 2506            custom_context_menu: None,
 2507            show_git_blame_gutter: false,
 2508            show_git_blame_inline: false,
 2509            show_selection_menu: None,
 2510            show_git_blame_inline_delay_task: None,
 2511            git_blame_inline_enabled: full_mode
 2512                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2513            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2514            buffer_serialization: is_minimap.not().then(|| {
 2515                BufferSerialization::new(
 2516                    ProjectSettings::get_global(cx)
 2517                        .session
 2518                        .restore_unsaved_buffers,
 2519                )
 2520            }),
 2521            blame: None,
 2522            blame_subscription: None,
 2523
 2524            breakpoint_store,
 2525            gutter_breakpoint_indicator: (None, None),
 2526            gutter_diff_review_indicator: (None, None),
 2527            diff_review_drag_state: None,
 2528            diff_review_overlays: Vec::new(),
 2529            stored_review_comments: Vec::new(),
 2530            next_review_comment_id: 0,
 2531            hovered_diff_hunk_row: None,
 2532            _subscriptions: (!is_minimap)
 2533                .then(|| {
 2534                    vec![
 2535                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2536                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2537                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2538                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2539                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2540                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2541                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2542                        cx.observe_window_activation(window, |editor, window, cx| {
 2543                            let active = window.is_window_active();
 2544                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2545                                if active {
 2546                                    blink_manager.enable(cx);
 2547                                } else {
 2548                                    blink_manager.disable(cx);
 2549                                }
 2550                            });
 2551                            if active {
 2552                                editor.show_mouse_cursor(cx);
 2553                            }
 2554                        }),
 2555                    ]
 2556                })
 2557                .unwrap_or_default(),
 2558            runnables: RunnableData::new(),
 2559            pull_diagnostics_task: Task::ready(()),
 2560            colors: None,
 2561            refresh_colors_task: Task::ready(()),
 2562            use_document_folding_ranges: false,
 2563            refresh_folding_ranges_task: Task::ready(()),
 2564            inlay_hints: None,
 2565            next_color_inlay_id: 0,
 2566            post_scroll_update: Task::ready(()),
 2567            linked_edit_ranges: Default::default(),
 2568            in_project_search: false,
 2569            previous_search_ranges: None,
 2570            breadcrumb_header: None,
 2571            focused_block: None,
 2572            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2573            addons: HashMap::default(),
 2574            registered_buffers: HashMap::default(),
 2575            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2576            selection_mark_mode: false,
 2577            toggle_fold_multiple_buffers: Task::ready(()),
 2578            serialize_selections: Task::ready(()),
 2579            serialize_folds: Task::ready(()),
 2580            text_style_refinement: None,
 2581            load_diff_task: load_uncommitted_diff,
 2582            temporary_diff_override: false,
 2583            mouse_cursor_hidden: false,
 2584            minimap: None,
 2585            hide_mouse_mode: EditorSettings::get_global(cx)
 2586                .hide_mouse
 2587                .unwrap_or_default(),
 2588            change_list: ChangeList::new(),
 2589            mode,
 2590            selection_drag_state: SelectionDragState::None,
 2591            folding_newlines: Task::ready(()),
 2592            lookup_key: None,
 2593            select_next_is_case_sensitive: None,
 2594            on_local_selections_changed: None,
 2595            suppress_selection_callback: false,
 2596            applicable_language_settings: HashMap::default(),
 2597            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2598            accent_data: None,
 2599            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2600            number_deleted_lines: false,
 2601            refresh_matching_bracket_highlights_task: Task::ready(()),
 2602            refresh_document_symbols_task: Task::ready(()).shared(),
 2603            lsp_document_symbols: HashMap::default(),
 2604            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2605            outline_symbols_at_cursor: None,
 2606            sticky_headers_task: Task::ready(()),
 2607            sticky_headers: None,
 2608            colorize_brackets_task: Task::ready(()),
 2609        };
 2610
 2611        if is_minimap {
 2612            return editor;
 2613        }
 2614
 2615        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2616        editor.accent_data = editor.fetch_accent_data(cx);
 2617
 2618        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2619            editor
 2620                ._subscriptions
 2621                .push(cx.observe(breakpoints, |_, _, cx| {
 2622                    cx.notify();
 2623                }));
 2624        }
 2625        editor._subscriptions.extend(project_subscriptions);
 2626
 2627        editor._subscriptions.push(cx.subscribe_in(
 2628            &cx.entity(),
 2629            window,
 2630            |editor, _, e: &EditorEvent, window, cx| match e {
 2631                EditorEvent::ScrollPositionChanged { local, .. } => {
 2632                    if *local {
 2633                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2634                        editor.inline_blame_popover.take();
 2635                        let snapshot = editor.snapshot(window, cx);
 2636                        let new_anchor = editor
 2637                            .scroll_manager
 2638                            .native_anchor(&snapshot.display_snapshot, cx);
 2639                        editor.update_restoration_data(cx, move |data| {
 2640                            data.scroll_position = (
 2641                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2642                                new_anchor.offset,
 2643                            );
 2644                        });
 2645
 2646                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2647                            cx.background_executor()
 2648                                .timer(Duration::from_millis(50))
 2649                                .await;
 2650                            editor
 2651                                .update_in(cx, |editor, window, cx| {
 2652                                    editor.update_data_on_scroll(window, cx)
 2653                                })
 2654                                .ok();
 2655                        });
 2656                    }
 2657                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2658                }
 2659                EditorEvent::Edited { .. } => {
 2660                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2661                        .map(|vim_mode| vim_mode.0)
 2662                        .unwrap_or(false);
 2663                    if !vim_mode {
 2664                        let display_map = editor.display_snapshot(cx);
 2665                        let selections = editor.selections.all_adjusted_display(&display_map);
 2666                        let pop_state = editor
 2667                            .change_list
 2668                            .last()
 2669                            .map(|previous| {
 2670                                previous.len() == selections.len()
 2671                                    && previous.iter().enumerate().all(|(ix, p)| {
 2672                                        p.to_display_point(&display_map).row()
 2673                                            == selections[ix].head().row()
 2674                                    })
 2675                            })
 2676                            .unwrap_or(false);
 2677                        let new_positions = selections
 2678                            .into_iter()
 2679                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2680                            .collect();
 2681                        editor
 2682                            .change_list
 2683                            .push_to_change_list(pop_state, new_positions);
 2684                    }
 2685                }
 2686                _ => (),
 2687            },
 2688        ));
 2689
 2690        if let Some(dap_store) = editor
 2691            .project
 2692            .as_ref()
 2693            .map(|project| project.read(cx).dap_store())
 2694        {
 2695            let weak_editor = cx.weak_entity();
 2696
 2697            editor
 2698                ._subscriptions
 2699                .push(
 2700                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2701                        let session_entity = cx.entity();
 2702                        weak_editor
 2703                            .update(cx, |editor, cx| {
 2704                                editor._subscriptions.push(
 2705                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2706                                );
 2707                            })
 2708                            .ok();
 2709                    }),
 2710                );
 2711
 2712            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2713                editor
 2714                    ._subscriptions
 2715                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2716            }
 2717        }
 2718
 2719        // skip adding the initial selection to selection history
 2720        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2721        editor.end_selection(window, cx);
 2722        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2723
 2724        editor.scroll_manager.show_scrollbars(window, cx);
 2725        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2726
 2727        if full_mode {
 2728            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2729            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2730
 2731            if editor.git_blame_inline_enabled {
 2732                editor.start_git_blame_inline(false, window, cx);
 2733            }
 2734
 2735            editor.go_to_active_debug_line(window, cx);
 2736
 2737            editor.minimap =
 2738                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2739            editor.colors = Some(LspColorData::new(cx));
 2740            editor.use_document_folding_ranges = true;
 2741            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2742
 2743            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2744                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2745            }
 2746            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2747        }
 2748
 2749        editor
 2750    }
 2751
 2752    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2753        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2754    }
 2755
 2756    pub fn deploy_mouse_context_menu(
 2757        &mut self,
 2758        position: gpui::Point<Pixels>,
 2759        context_menu: Entity<ContextMenu>,
 2760        window: &mut Window,
 2761        cx: &mut Context<Self>,
 2762    ) {
 2763        self.mouse_context_menu = Some(MouseContextMenu::new(
 2764            self,
 2765            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2766            context_menu,
 2767            window,
 2768            cx,
 2769        ));
 2770    }
 2771
 2772    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2773        self.mouse_context_menu
 2774            .as_ref()
 2775            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2776    }
 2777
 2778    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2779        if self
 2780            .selections
 2781            .pending_anchor()
 2782            .is_some_and(|pending_selection| {
 2783                let snapshot = self.buffer().read(cx).snapshot(cx);
 2784                pending_selection.range().includes(range, &snapshot)
 2785            })
 2786        {
 2787            return true;
 2788        }
 2789
 2790        self.selections
 2791            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2792            .into_iter()
 2793            .any(|selection| {
 2794                // This is needed to cover a corner case, if we just check for an existing
 2795                // selection in the fold range, having a cursor at the start of the fold
 2796                // marks it as selected. Non-empty selections don't cause this.
 2797                let length = selection.end - selection.start;
 2798                length > 0
 2799            })
 2800    }
 2801
 2802    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2803        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2804    }
 2805
 2806    fn key_context_internal(
 2807        &self,
 2808        has_active_edit_prediction: bool,
 2809        window: &mut Window,
 2810        cx: &mut App,
 2811    ) -> KeyContext {
 2812        let mut key_context = KeyContext::new_with_defaults();
 2813        key_context.add("Editor");
 2814        let mode = match self.mode {
 2815            EditorMode::SingleLine => "single_line",
 2816            EditorMode::AutoHeight { .. } => "auto_height",
 2817            EditorMode::Minimap { .. } => "minimap",
 2818            EditorMode::Full { .. } => "full",
 2819        };
 2820
 2821        if EditorSettings::jupyter_enabled(cx) {
 2822            key_context.add("jupyter");
 2823        }
 2824
 2825        key_context.set("mode", mode);
 2826        if self.pending_rename.is_some() {
 2827            key_context.add("renaming");
 2828        }
 2829
 2830        if let Some(snippet_stack) = self.snippet_stack.last() {
 2831            key_context.add("in_snippet");
 2832
 2833            if snippet_stack.active_index > 0 {
 2834                key_context.add("has_previous_tabstop");
 2835            }
 2836
 2837            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2838                key_context.add("has_next_tabstop");
 2839            }
 2840        }
 2841
 2842        match self.context_menu.borrow().as_ref() {
 2843            Some(CodeContextMenu::Completions(menu)) => {
 2844                if menu.visible() {
 2845                    key_context.add("menu");
 2846                    key_context.add("showing_completions");
 2847                }
 2848            }
 2849            Some(CodeContextMenu::CodeActions(menu)) => {
 2850                if menu.visible() {
 2851                    key_context.add("menu");
 2852                    key_context.add("showing_code_actions")
 2853                }
 2854            }
 2855            None => {}
 2856        }
 2857
 2858        if self.signature_help_state.has_multiple_signatures() {
 2859            key_context.add("showing_signature_help");
 2860        }
 2861
 2862        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2863        if !self.focus_handle(cx).contains_focused(window, cx)
 2864            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2865        {
 2866            for addon in self.addons.values() {
 2867                addon.extend_key_context(&mut key_context, cx)
 2868            }
 2869        }
 2870
 2871        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2872            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2873                Some(
 2874                    file.full_path(cx)
 2875                        .extension()?
 2876                        .to_string_lossy()
 2877                        .to_lowercase(),
 2878                )
 2879            }) {
 2880                key_context.set("extension", extension);
 2881            }
 2882        } else {
 2883            key_context.add("multibuffer");
 2884        }
 2885
 2886        if has_active_edit_prediction {
 2887            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2888            key_context.add("copilot_suggestion");
 2889        }
 2890
 2891        if self.in_leading_whitespace {
 2892            key_context.add("in_leading_whitespace");
 2893        }
 2894        if self.edit_prediction_requires_modifier() {
 2895            key_context.set("edit_prediction_mode", "subtle")
 2896        } else {
 2897            key_context.set("edit_prediction_mode", "eager");
 2898        }
 2899
 2900        if self.selection_mark_mode {
 2901            key_context.add("selection_mode");
 2902        }
 2903
 2904        let disjoint = self.selections.disjoint_anchors();
 2905        if matches!(
 2906            &self.mode,
 2907            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2908        ) && let [selection] = disjoint
 2909            && selection.start == selection.end
 2910        {
 2911            let snapshot = self.snapshot(window, cx);
 2912            let snapshot = snapshot.buffer_snapshot();
 2913            let caret_offset = selection.end.to_offset(snapshot);
 2914
 2915            if caret_offset == MultiBufferOffset(0) {
 2916                key_context.add("start_of_input");
 2917            }
 2918
 2919            if caret_offset == snapshot.len() {
 2920                key_context.add("end_of_input");
 2921            }
 2922        }
 2923
 2924        if self.has_any_expanded_diff_hunks(cx) {
 2925            key_context.add("diffs_expanded");
 2926        }
 2927
 2928        key_context
 2929    }
 2930
 2931    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2932        self.last_bounds.as_ref()
 2933    }
 2934
 2935    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2936        if self.mouse_cursor_hidden {
 2937            self.mouse_cursor_hidden = false;
 2938            cx.notify();
 2939        }
 2940    }
 2941
 2942    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2943        let hide_mouse_cursor = match origin {
 2944            HideMouseCursorOrigin::TypingAction => {
 2945                matches!(
 2946                    self.hide_mouse_mode,
 2947                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2948                )
 2949            }
 2950            HideMouseCursorOrigin::MovementAction => {
 2951                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2952            }
 2953        };
 2954        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2955            self.mouse_cursor_hidden = hide_mouse_cursor;
 2956            cx.notify();
 2957        }
 2958    }
 2959
 2960    fn accept_edit_prediction_keystroke(
 2961        &self,
 2962        granularity: EditPredictionGranularity,
 2963        window: &mut Window,
 2964        cx: &mut App,
 2965    ) -> Option<gpui::KeybindingKeystroke> {
 2966        let key_context = self.key_context_internal(true, window, cx);
 2967
 2968        let bindings =
 2969            match granularity {
 2970                EditPredictionGranularity::Word => window
 2971                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2972                EditPredictionGranularity::Line => window
 2973                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2974                EditPredictionGranularity::Full => {
 2975                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2976                }
 2977            };
 2978
 2979        bindings
 2980            .into_iter()
 2981            .rev()
 2982            .find_map(|binding| match binding.keystrokes() {
 2983                [keystroke, ..] => Some(keystroke.clone()),
 2984                _ => None,
 2985            })
 2986    }
 2987
 2988    fn preview_edit_prediction_keystroke(
 2989        &self,
 2990        window: &mut Window,
 2991        cx: &mut App,
 2992    ) -> Option<gpui::KeybindingKeystroke> {
 2993        let key_context = self.key_context_internal(true, window, cx);
 2994        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 2995        bindings
 2996            .into_iter()
 2997            .rev()
 2998            .find_map(|binding| match binding.keystrokes() {
 2999                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 3000                _ => None,
 3001            })
 3002    }
 3003
 3004    fn edit_prediction_preview_modifiers_held(
 3005        &self,
 3006        modifiers: &Modifiers,
 3007        window: &mut Window,
 3008        cx: &mut App,
 3009    ) -> bool {
 3010        let key_context = self.key_context_internal(true, window, cx);
 3011        let actions: [&dyn Action; 3] = [
 3012            &AcceptEditPrediction,
 3013            &AcceptNextWordEditPrediction,
 3014            &AcceptNextLineEditPrediction,
 3015        ];
 3016
 3017        actions.into_iter().any(|action| {
 3018            window
 3019                .bindings_for_action_in_context(action, key_context.clone())
 3020                .into_iter()
 3021                .rev()
 3022                .any(|binding| {
 3023                    binding.keystrokes().first().is_some_and(|keystroke| {
 3024                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3025                    })
 3026                })
 3027        })
 3028    }
 3029
 3030    fn edit_prediction_cursor_popover_prefers_preview(
 3031        &self,
 3032        completion: &EditPredictionState,
 3033        cx: &App,
 3034    ) -> bool {
 3035        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 3036
 3037        match &completion.completion {
 3038            EditPrediction::Edit {
 3039                edits, snapshot, ..
 3040            } => {
 3041                let mut start_row: Option<u32> = None;
 3042                let mut end_row: Option<u32> = None;
 3043
 3044                for (range, text) in edits {
 3045                    let Some((_, range)) =
 3046                        multibuffer_snapshot.anchor_range_to_buffer_anchor_range(range.clone())
 3047                    else {
 3048                        continue;
 3049                    };
 3050                    let edit_start_row = range.start.to_point(snapshot).row;
 3051                    let old_end_row = range.end.to_point(snapshot).row;
 3052                    let inserted_newline_count = text
 3053                        .as_ref()
 3054                        .chars()
 3055                        .filter(|character| *character == '\n')
 3056                        .count() as u32;
 3057                    let deleted_newline_count = old_end_row - edit_start_row;
 3058                    let preview_end_row = edit_start_row + inserted_newline_count;
 3059
 3060                    start_row =
 3061                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3062                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3063
 3064                    if deleted_newline_count > 1 {
 3065                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3066                    }
 3067                }
 3068
 3069                start_row
 3070                    .zip(end_row)
 3071                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3072            }
 3073            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3074        }
 3075    }
 3076
 3077    fn edit_prediction_keybind_display(
 3078        &self,
 3079        surface: EditPredictionKeybindSurface,
 3080        window: &mut Window,
 3081        cx: &mut App,
 3082    ) -> EditPredictionKeybindDisplay {
 3083        let accept_keystroke =
 3084            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3085        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3086
 3087        let action = match surface {
 3088            EditPredictionKeybindSurface::Inline
 3089            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3090                if self.edit_prediction_requires_modifier() {
 3091                    EditPredictionKeybindAction::Preview
 3092                } else {
 3093                    EditPredictionKeybindAction::Accept
 3094                }
 3095            }
 3096            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3097                .active_edit_prediction
 3098                .as_ref()
 3099                .filter(|completion| {
 3100                    self.edit_prediction_cursor_popover_prefers_preview(completion, cx)
 3101                })
 3102                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3103                    EditPredictionKeybindAction::Preview
 3104                }),
 3105        };
 3106        #[cfg(test)]
 3107        let preview_copy = preview_keystroke.clone();
 3108        #[cfg(test)]
 3109        let accept_copy = accept_keystroke.clone();
 3110
 3111        let displayed_keystroke = match surface {
 3112            EditPredictionKeybindSurface::Inline => match action {
 3113                EditPredictionKeybindAction::Accept => accept_keystroke,
 3114                EditPredictionKeybindAction::Preview => preview_keystroke,
 3115            },
 3116            EditPredictionKeybindSurface::CursorPopoverCompact
 3117            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3118                EditPredictionKeybindAction::Accept => accept_keystroke,
 3119                EditPredictionKeybindAction::Preview => {
 3120                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3121                }
 3122            },
 3123        };
 3124
 3125        let missing_accept_keystroke = displayed_keystroke.is_none();
 3126
 3127        EditPredictionKeybindDisplay {
 3128            #[cfg(test)]
 3129            accept_keystroke: accept_copy,
 3130            #[cfg(test)]
 3131            preview_keystroke: preview_copy,
 3132            displayed_keystroke,
 3133            action,
 3134            missing_accept_keystroke,
 3135            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3136                && self.edit_prediction_preview.released_too_fast(),
 3137        }
 3138    }
 3139
 3140    pub fn new_file(
 3141        workspace: &mut Workspace,
 3142        _: &workspace::NewFile,
 3143        window: &mut Window,
 3144        cx: &mut Context<Workspace>,
 3145    ) {
 3146        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3147            "Failed to create buffer",
 3148            window,
 3149            cx,
 3150            |e, _, _| match e.error_code() {
 3151                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3152                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3153                e.error_tag("required").unwrap_or("the latest version")
 3154            )),
 3155                _ => None,
 3156            },
 3157        );
 3158    }
 3159
 3160    pub fn new_in_workspace(
 3161        workspace: &mut Workspace,
 3162        window: &mut Window,
 3163        cx: &mut Context<Workspace>,
 3164    ) -> Task<Result<Entity<Editor>>> {
 3165        let project = workspace.project().clone();
 3166        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3167
 3168        cx.spawn_in(window, async move |workspace, cx| {
 3169            let buffer = create.await?;
 3170            workspace.update_in(cx, |workspace, window, cx| {
 3171                let editor =
 3172                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3173                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3174                editor
 3175            })
 3176        })
 3177    }
 3178
 3179    fn new_file_vertical(
 3180        workspace: &mut Workspace,
 3181        _: &workspace::NewFileSplitVertical,
 3182        window: &mut Window,
 3183        cx: &mut Context<Workspace>,
 3184    ) {
 3185        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3186    }
 3187
 3188    fn new_file_horizontal(
 3189        workspace: &mut Workspace,
 3190        _: &workspace::NewFileSplitHorizontal,
 3191        window: &mut Window,
 3192        cx: &mut Context<Workspace>,
 3193    ) {
 3194        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3195    }
 3196
 3197    fn new_file_split(
 3198        workspace: &mut Workspace,
 3199        action: &workspace::NewFileSplit,
 3200        window: &mut Window,
 3201        cx: &mut Context<Workspace>,
 3202    ) {
 3203        Self::new_file_in_direction(workspace, action.0, window, cx)
 3204    }
 3205
 3206    fn new_file_in_direction(
 3207        workspace: &mut Workspace,
 3208        direction: SplitDirection,
 3209        window: &mut Window,
 3210        cx: &mut Context<Workspace>,
 3211    ) {
 3212        let project = workspace.project().clone();
 3213        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3214
 3215        cx.spawn_in(window, async move |workspace, cx| {
 3216            let buffer = create.await?;
 3217            workspace.update_in(cx, move |workspace, window, cx| {
 3218                workspace.split_item(
 3219                    direction,
 3220                    Box::new(
 3221                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3222                    ),
 3223                    window,
 3224                    cx,
 3225                )
 3226            })?;
 3227            anyhow::Ok(())
 3228        })
 3229        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3230            match e.error_code() {
 3231                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3232                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3233                e.error_tag("required").unwrap_or("the latest version")
 3234            )),
 3235                _ => None,
 3236            }
 3237        });
 3238    }
 3239
 3240    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3241        self.leader_id
 3242    }
 3243
 3244    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3245        &self.buffer
 3246    }
 3247
 3248    pub fn project(&self) -> Option<&Entity<Project>> {
 3249        self.project.as_ref()
 3250    }
 3251
 3252    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3253        self.workspace.as_ref()?.0.upgrade()
 3254    }
 3255
 3256    /// Detaches a task and shows an error notification in the workspace if available,
 3257    /// otherwise just logs the error.
 3258    pub fn detach_and_notify_err<R, E>(
 3259        &self,
 3260        task: Task<Result<R, E>>,
 3261        window: &mut Window,
 3262        cx: &mut App,
 3263    ) where
 3264        E: std::fmt::Debug + std::fmt::Display + 'static,
 3265        R: 'static,
 3266    {
 3267        if let Some(workspace) = self.workspace() {
 3268            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3269        } else {
 3270            task.detach_and_log_err(cx);
 3271        }
 3272    }
 3273
 3274    /// Returns the workspace serialization ID if this editor should be serialized.
 3275    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3276        self.workspace
 3277            .as_ref()
 3278            .filter(|_| self.should_serialize_buffer())
 3279            .and_then(|workspace| workspace.1)
 3280    }
 3281
 3282    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3283        self.buffer().read(cx).title(cx)
 3284    }
 3285
 3286    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3287        let git_blame_gutter_max_author_length = self
 3288            .render_git_blame_gutter(cx)
 3289            .then(|| {
 3290                if let Some(blame) = self.blame.as_ref() {
 3291                    let max_author_length =
 3292                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3293                    Some(max_author_length)
 3294                } else {
 3295                    None
 3296                }
 3297            })
 3298            .flatten();
 3299
 3300        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3301
 3302        EditorSnapshot {
 3303            mode: self.mode.clone(),
 3304            show_gutter: self.show_gutter,
 3305            offset_content: self.offset_content,
 3306            show_line_numbers: self.show_line_numbers,
 3307            number_deleted_lines: self.number_deleted_lines,
 3308            show_git_diff_gutter: self.show_git_diff_gutter,
 3309            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3310            show_code_actions: self.show_code_actions,
 3311            show_runnables: self.show_runnables,
 3312            show_breakpoints: self.show_breakpoints,
 3313            git_blame_gutter_max_author_length,
 3314            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3315            display_snapshot,
 3316            placeholder_display_snapshot: self
 3317                .placeholder_display_map
 3318                .as_ref()
 3319                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3320            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3321            is_focused: self.focus_handle.is_focused(window),
 3322            current_line_highlight: self
 3323                .current_line_highlight
 3324                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3325            gutter_hovered: self.gutter_hovered,
 3326        }
 3327    }
 3328
 3329    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3330        self.buffer.read(cx).language_at(point, cx)
 3331    }
 3332
 3333    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3334        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3335    }
 3336
 3337    pub fn active_buffer(&self, cx: &App) -> Option<Entity<Buffer>> {
 3338        let multibuffer = self.buffer.read(cx);
 3339        let snapshot = multibuffer.snapshot(cx);
 3340        let (anchor, _) =
 3341            snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())?;
 3342        multibuffer.buffer(anchor.buffer_id)
 3343    }
 3344
 3345    pub fn mode(&self) -> &EditorMode {
 3346        &self.mode
 3347    }
 3348
 3349    pub fn set_mode(&mut self, mode: EditorMode) {
 3350        self.mode = mode;
 3351    }
 3352
 3353    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3354        self.collaboration_hub.as_deref()
 3355    }
 3356
 3357    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3358        self.collaboration_hub = Some(hub);
 3359    }
 3360
 3361    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3362        self.in_project_search = in_project_search;
 3363    }
 3364
 3365    pub fn set_custom_context_menu(
 3366        &mut self,
 3367        f: impl 'static
 3368        + Fn(
 3369            &mut Self,
 3370            DisplayPoint,
 3371            &mut Window,
 3372            &mut Context<Self>,
 3373        ) -> Option<Entity<ui::ContextMenu>>,
 3374    ) {
 3375        self.custom_context_menu = Some(Box::new(f))
 3376    }
 3377
 3378    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3379        self.completion_provider = provider;
 3380    }
 3381
 3382    #[cfg(any(test, feature = "test-support"))]
 3383    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3384        self.completion_provider.clone()
 3385    }
 3386
 3387    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3388        self.semantics_provider.clone()
 3389    }
 3390
 3391    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3392        self.semantics_provider = provider;
 3393    }
 3394
 3395    pub fn set_edit_prediction_provider<T>(
 3396        &mut self,
 3397        provider: Option<Entity<T>>,
 3398        window: &mut Window,
 3399        cx: &mut Context<Self>,
 3400    ) where
 3401        T: EditPredictionDelegate,
 3402    {
 3403        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3404            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3405                if this.focus_handle.is_focused(window) {
 3406                    this.update_visible_edit_prediction(window, cx);
 3407                }
 3408            }),
 3409            provider: Arc::new(provider),
 3410        });
 3411        self.update_edit_prediction_settings(cx);
 3412        self.refresh_edit_prediction(false, false, window, cx);
 3413    }
 3414
 3415    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3416        self.placeholder_display_map
 3417            .as_ref()
 3418            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3419    }
 3420
 3421    pub fn set_placeholder_text(
 3422        &mut self,
 3423        placeholder_text: &str,
 3424        window: &mut Window,
 3425        cx: &mut Context<Self>,
 3426    ) {
 3427        let multibuffer = cx
 3428            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3429
 3430        let style = window.text_style();
 3431
 3432        self.placeholder_display_map = Some(cx.new(|cx| {
 3433            DisplayMap::new(
 3434                multibuffer,
 3435                style.font(),
 3436                style.font_size.to_pixels(window.rem_size()),
 3437                None,
 3438                FILE_HEADER_HEIGHT,
 3439                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3440                Default::default(),
 3441                DiagnosticSeverity::Off,
 3442                cx,
 3443            )
 3444        }));
 3445        cx.notify();
 3446    }
 3447
 3448    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3449        self.cursor_shape = cursor_shape;
 3450
 3451        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3452        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3453
 3454        cx.notify();
 3455    }
 3456
 3457    pub fn cursor_shape(&self) -> CursorShape {
 3458        self.cursor_shape
 3459    }
 3460
 3461    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3462        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3463    }
 3464
 3465    pub fn set_current_line_highlight(
 3466        &mut self,
 3467        current_line_highlight: Option<CurrentLineHighlight>,
 3468    ) {
 3469        self.current_line_highlight = current_line_highlight;
 3470    }
 3471
 3472    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3473        self.collapse_matches = collapse_matches;
 3474    }
 3475
 3476    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3477        if self.collapse_matches {
 3478            return range.start..range.start;
 3479        }
 3480        range.clone()
 3481    }
 3482
 3483    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3484        self.display_map.read(cx).clip_at_line_ends
 3485    }
 3486
 3487    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3488        if self.display_map.read(cx).clip_at_line_ends != clip {
 3489            self.display_map
 3490                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3491        }
 3492    }
 3493
 3494    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3495        self.input_enabled = input_enabled;
 3496    }
 3497
 3498    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3499        self.expects_character_input = expects_character_input;
 3500    }
 3501
 3502    pub fn set_edit_predictions_hidden_for_vim_mode(
 3503        &mut self,
 3504        hidden: bool,
 3505        window: &mut Window,
 3506        cx: &mut Context<Self>,
 3507    ) {
 3508        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3509            self.edit_predictions_hidden_for_vim_mode = hidden;
 3510            if hidden {
 3511                self.update_visible_edit_prediction(window, cx);
 3512            } else {
 3513                self.refresh_edit_prediction(true, false, window, cx);
 3514            }
 3515        }
 3516    }
 3517
 3518    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3519        self.menu_edit_predictions_policy = value;
 3520    }
 3521
 3522    pub fn set_autoindent(&mut self, autoindent: bool) {
 3523        if autoindent {
 3524            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3525        } else {
 3526            self.autoindent_mode = None;
 3527        }
 3528    }
 3529
 3530    pub fn capability(&self, cx: &App) -> Capability {
 3531        if self.read_only {
 3532            Capability::ReadOnly
 3533        } else {
 3534            self.buffer.read(cx).capability()
 3535        }
 3536    }
 3537
 3538    pub fn read_only(&self, cx: &App) -> bool {
 3539        self.read_only || self.buffer.read(cx).read_only()
 3540    }
 3541
 3542    pub fn set_read_only(&mut self, read_only: bool) {
 3543        self.read_only = read_only;
 3544    }
 3545
 3546    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3547        self.use_autoclose = autoclose;
 3548    }
 3549
 3550    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3551        self.use_auto_surround = auto_surround;
 3552    }
 3553
 3554    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3555        self.auto_replace_emoji_shortcode = auto_replace;
 3556    }
 3557
 3558    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3559        self.buffer_serialization = should_serialize.then(|| {
 3560            BufferSerialization::new(
 3561                ProjectSettings::get_global(cx)
 3562                    .session
 3563                    .restore_unsaved_buffers,
 3564            )
 3565        })
 3566    }
 3567
 3568    fn should_serialize_buffer(&self) -> bool {
 3569        self.buffer_serialization.is_some()
 3570    }
 3571
 3572    pub fn toggle_edit_predictions(
 3573        &mut self,
 3574        _: &ToggleEditPrediction,
 3575        window: &mut Window,
 3576        cx: &mut Context<Self>,
 3577    ) {
 3578        if self.show_edit_predictions_override.is_some() {
 3579            self.set_show_edit_predictions(None, window, cx);
 3580        } else {
 3581            let show_edit_predictions = !self.edit_predictions_enabled();
 3582            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3583        }
 3584    }
 3585
 3586    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3587        self.show_completions_on_input_override = show_completions_on_input;
 3588    }
 3589
 3590    pub fn set_show_edit_predictions(
 3591        &mut self,
 3592        show_edit_predictions: Option<bool>,
 3593        window: &mut Window,
 3594        cx: &mut Context<Self>,
 3595    ) {
 3596        self.show_edit_predictions_override = show_edit_predictions;
 3597        self.update_edit_prediction_settings(cx);
 3598
 3599        if let Some(false) = show_edit_predictions {
 3600            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3601        } else {
 3602            self.refresh_edit_prediction(false, true, window, cx);
 3603        }
 3604    }
 3605
 3606    fn edit_predictions_disabled_in_scope(
 3607        &self,
 3608        buffer: &Entity<Buffer>,
 3609        buffer_position: language::Anchor,
 3610        cx: &App,
 3611    ) -> bool {
 3612        let snapshot = buffer.read(cx).snapshot();
 3613        let settings = snapshot.settings_at(buffer_position, cx);
 3614
 3615        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3616            return false;
 3617        };
 3618
 3619        scope.override_name().is_some_and(|scope_name| {
 3620            settings
 3621                .edit_predictions_disabled_in
 3622                .iter()
 3623                .any(|s| s == scope_name)
 3624        })
 3625    }
 3626
 3627    pub fn set_use_modal_editing(&mut self, to: bool) {
 3628        self.use_modal_editing = to;
 3629    }
 3630
 3631    pub fn use_modal_editing(&self) -> bool {
 3632        self.use_modal_editing
 3633    }
 3634
 3635    fn selections_did_change(
 3636        &mut self,
 3637        local: bool,
 3638        old_cursor_position: &Anchor,
 3639        effects: SelectionEffects,
 3640        window: &mut Window,
 3641        cx: &mut Context<Self>,
 3642    ) {
 3643        window.invalidate_character_coordinates();
 3644
 3645        // Copy selections to primary selection buffer
 3646        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3647        if local {
 3648            let selections = self
 3649                .selections
 3650                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3651            let buffer_handle = self.buffer.read(cx).read(cx);
 3652
 3653            let mut text = String::new();
 3654            for (index, selection) in selections.iter().enumerate() {
 3655                let text_for_selection = buffer_handle
 3656                    .text_for_range(selection.start..selection.end)
 3657                    .collect::<String>();
 3658
 3659                text.push_str(&text_for_selection);
 3660                if index != selections.len() - 1 {
 3661                    text.push('\n');
 3662                }
 3663            }
 3664
 3665            if !text.is_empty() {
 3666                cx.write_to_primary(ClipboardItem::new_string(text));
 3667            }
 3668        }
 3669
 3670        let selection_anchors = self.selections.disjoint_anchors_arc();
 3671
 3672        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3673            self.buffer.update(cx, |buffer, cx| {
 3674                buffer.set_active_selections(
 3675                    &selection_anchors,
 3676                    self.selections.line_mode(),
 3677                    self.cursor_shape,
 3678                    cx,
 3679                )
 3680            });
 3681        }
 3682        let display_map = self
 3683            .display_map
 3684            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3685        let buffer = display_map.buffer_snapshot();
 3686        if self.selections.count() == 1 {
 3687            self.add_selections_state = None;
 3688        }
 3689        self.select_next_state = None;
 3690        self.select_prev_state = None;
 3691        self.select_syntax_node_history.try_clear();
 3692        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3693        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3694        self.take_rename(false, window, cx);
 3695
 3696        let newest_selection = self.selections.newest_anchor();
 3697        let new_cursor_position = newest_selection.head();
 3698        let selection_start = newest_selection.start;
 3699
 3700        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3701            self.push_to_nav_history(
 3702                *old_cursor_position,
 3703                Some(new_cursor_position.to_point(buffer)),
 3704                false,
 3705                effects.nav_history == Some(true),
 3706                cx,
 3707            );
 3708        }
 3709
 3710        if local {
 3711            if let Some((anchor, _)) = buffer.anchor_to_buffer_anchor(new_cursor_position) {
 3712                self.register_buffer(anchor.buffer_id, cx);
 3713            }
 3714
 3715            let mut context_menu = self.context_menu.borrow_mut();
 3716            let completion_menu = match context_menu.as_ref() {
 3717                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3718                Some(CodeContextMenu::CodeActions(_)) => {
 3719                    *context_menu = None;
 3720                    None
 3721                }
 3722                None => None,
 3723            };
 3724            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3725            drop(context_menu);
 3726
 3727            if effects.completions
 3728                && let Some(completion_position) = completion_position
 3729            {
 3730                let start_offset = selection_start.to_offset(buffer);
 3731                let position_matches = start_offset == completion_position.to_offset(buffer);
 3732                let continue_showing = if let Some((snap, ..)) =
 3733                    buffer.point_to_buffer_offset(completion_position)
 3734                    && !snap.capability.editable()
 3735                {
 3736                    false
 3737                } else if position_matches {
 3738                    if self.snippet_stack.is_empty() {
 3739                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3740                            == Some(CharKind::Word)
 3741                    } else {
 3742                        // Snippet choices can be shown even when the cursor is in whitespace.
 3743                        // Dismissing the menu with actions like backspace is handled by
 3744                        // invalidation regions.
 3745                        true
 3746                    }
 3747                } else {
 3748                    false
 3749                };
 3750
 3751                if continue_showing {
 3752                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3753                } else {
 3754                    self.hide_context_menu(window, cx);
 3755                }
 3756            }
 3757
 3758            hide_hover(self, cx);
 3759
 3760            if old_cursor_position.to_display_point(&display_map).row()
 3761                != new_cursor_position.to_display_point(&display_map).row()
 3762            {
 3763                self.available_code_actions.take();
 3764            }
 3765            self.refresh_code_actions(window, cx);
 3766            self.refresh_document_highlights(cx);
 3767            refresh_linked_ranges(self, window, cx);
 3768
 3769            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3770            self.refresh_matching_bracket_highlights(&display_map, cx);
 3771            self.refresh_outline_symbols_at_cursor(cx);
 3772            self.update_visible_edit_prediction(window, cx);
 3773            self.inline_blame_popover.take();
 3774            if self.git_blame_inline_enabled {
 3775                self.start_inline_blame_timer(window, cx);
 3776            }
 3777        }
 3778
 3779        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3780
 3781        if local && !self.suppress_selection_callback {
 3782            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3783                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3784                callback(cursor_position, window, cx);
 3785            }
 3786        }
 3787
 3788        cx.emit(EditorEvent::SelectionsChanged { local });
 3789
 3790        let selections = &self.selections.disjoint_anchors_arc();
 3791        if selections.len() == 1 {
 3792            cx.emit(SearchEvent::ActiveMatchChanged)
 3793        }
 3794        if local && let Some(buffer_snapshot) = buffer.as_singleton() {
 3795            let inmemory_selections = selections
 3796                .iter()
 3797                .map(|s| {
 3798                    let start = s.range().start.text_anchor_in(buffer_snapshot);
 3799                    let end = s.range().end.text_anchor_in(buffer_snapshot);
 3800                    (start..end).to_point(buffer_snapshot)
 3801                })
 3802                .collect();
 3803            self.update_restoration_data(cx, |data| {
 3804                data.selections = inmemory_selections;
 3805            });
 3806
 3807            if WorkspaceSettings::get(None, cx).restore_on_startup
 3808                != RestoreOnStartupBehavior::EmptyTab
 3809                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3810            {
 3811                let snapshot = self.buffer().read(cx).snapshot(cx);
 3812                let selections = selections.clone();
 3813                let background_executor = cx.background_executor().clone();
 3814                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3815                let db = EditorDb::global(cx);
 3816                self.serialize_selections = cx.background_spawn(async move {
 3817                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3818                    let db_selections = selections
 3819                        .iter()
 3820                        .map(|selection| {
 3821                            (
 3822                                selection.start.to_offset(&snapshot).0,
 3823                                selection.end.to_offset(&snapshot).0,
 3824                            )
 3825                        })
 3826                        .collect();
 3827
 3828                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3829                        .await
 3830                        .with_context(|| {
 3831                            format!(
 3832                                "persisting editor selections for editor {editor_id}, \
 3833                                workspace {workspace_id:?}"
 3834                            )
 3835                        })
 3836                        .log_err();
 3837                });
 3838            }
 3839        }
 3840
 3841        cx.notify();
 3842    }
 3843
 3844    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3845        use text::ToOffset as _;
 3846
 3847        if self.mode.is_minimap()
 3848            || WorkspaceSettings::get(None, cx).restore_on_startup
 3849                == RestoreOnStartupBehavior::EmptyTab
 3850        {
 3851            return;
 3852        }
 3853
 3854        let display_snapshot = self
 3855            .display_map
 3856            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3857        let Some(buffer_snapshot) = display_snapshot.buffer_snapshot().as_singleton() else {
 3858            return;
 3859        };
 3860        let inmemory_folds = display_snapshot
 3861            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3862            .map(|fold| {
 3863                let start = fold.range.start.text_anchor_in(buffer_snapshot);
 3864                let end = fold.range.end.text_anchor_in(buffer_snapshot);
 3865                (start..end).to_point(buffer_snapshot)
 3866            })
 3867            .collect();
 3868        self.update_restoration_data(cx, |data| {
 3869            data.folds = inmemory_folds;
 3870        });
 3871
 3872        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3873            return;
 3874        };
 3875
 3876        // Get file path for path-based fold storage (survives tab close)
 3877        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3878            project::File::from_dyn(buffer.read(cx).file())
 3879                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3880        }) else {
 3881            return;
 3882        };
 3883
 3884        let background_executor = cx.background_executor().clone();
 3885        const FINGERPRINT_LEN: usize = 32;
 3886        let db_folds = display_snapshot
 3887            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3888            .map(|fold| {
 3889                let start = fold
 3890                    .range
 3891                    .start
 3892                    .text_anchor_in(buffer_snapshot)
 3893                    .to_offset(buffer_snapshot);
 3894                let end = fold
 3895                    .range
 3896                    .end
 3897                    .text_anchor_in(buffer_snapshot)
 3898                    .to_offset(buffer_snapshot);
 3899
 3900                // Extract fingerprints - content at fold boundaries for validation on restore
 3901                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3902                // content that might change independently.
 3903                // start_fp: first min(32, fold_len) bytes of fold content
 3904                // end_fp: last min(32, fold_len) bytes of fold content
 3905                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3906                let fold_len = end - start;
 3907                let start_fp_end = buffer_snapshot
 3908                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3909                let start_fp: String = buffer_snapshot
 3910                    .text_for_range(start..start_fp_end)
 3911                    .collect();
 3912                let end_fp_start = buffer_snapshot
 3913                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3914                let end_fp: String = buffer_snapshot.text_for_range(end_fp_start..end).collect();
 3915
 3916                (start, end, start_fp, end_fp)
 3917            })
 3918            .collect::<Vec<_>>();
 3919        let db = EditorDb::global(cx);
 3920        self.serialize_folds = cx.background_spawn(async move {
 3921            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3922            if db_folds.is_empty() {
 3923                // No folds - delete any persisted folds for this file
 3924                db.delete_file_folds(workspace_id, file_path)
 3925                    .await
 3926                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3927                    .log_err();
 3928            } else {
 3929                db.save_file_folds(workspace_id, file_path, db_folds)
 3930                    .await
 3931                    .with_context(|| {
 3932                        format!("persisting file folds for workspace {workspace_id:?}")
 3933                    })
 3934                    .log_err();
 3935            }
 3936        });
 3937    }
 3938
 3939    pub fn sync_selections(
 3940        &mut self,
 3941        other: Entity<Editor>,
 3942        cx: &mut Context<Self>,
 3943    ) -> gpui::Subscription {
 3944        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3945        if !other_selections.is_empty() {
 3946            self.selections
 3947                .change_with(&self.display_snapshot(cx), |selections| {
 3948                    selections.select_anchors(other_selections);
 3949                });
 3950        }
 3951
 3952        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3953            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3954                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3955                if other_selections.is_empty() {
 3956                    return;
 3957                }
 3958                let snapshot = this.display_snapshot(cx);
 3959                this.selections.change_with(&snapshot, |selections| {
 3960                    selections.select_anchors(other_selections);
 3961                });
 3962            }
 3963        });
 3964
 3965        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3966            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3967                let these_selections = this.selections.disjoint_anchors().to_vec();
 3968                if these_selections.is_empty() {
 3969                    return;
 3970                }
 3971                other.update(cx, |other_editor, cx| {
 3972                    let snapshot = other_editor.display_snapshot(cx);
 3973                    other_editor
 3974                        .selections
 3975                        .change_with(&snapshot, |selections| {
 3976                            selections.select_anchors(these_selections);
 3977                        })
 3978                });
 3979            }
 3980        });
 3981
 3982        Subscription::join(other_subscription, this_subscription)
 3983    }
 3984
 3985    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3986        if self.buffer().read(cx).is_singleton() {
 3987            return;
 3988        }
 3989        let snapshot = self.buffer.read(cx).snapshot(cx);
 3990        let buffer_ids: HashSet<BufferId> = self
 3991            .selections
 3992            .disjoint_anchor_ranges()
 3993            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3994            .collect();
 3995        for buffer_id in buffer_ids {
 3996            self.unfold_buffer(buffer_id, cx);
 3997        }
 3998    }
 3999
 4000    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 4001    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 4002    /// effects of selection change occur at the end of the transaction.
 4003    pub fn change_selections<R>(
 4004        &mut self,
 4005        effects: SelectionEffects,
 4006        window: &mut Window,
 4007        cx: &mut Context<Self>,
 4008        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 4009    ) -> R {
 4010        let snapshot = self.display_snapshot(cx);
 4011        if let Some(state) = &mut self.deferred_selection_effects_state {
 4012            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 4013            state.effects.completions = effects.completions;
 4014            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 4015            let (changed, result) = self.selections.change_with(&snapshot, change);
 4016            state.changed |= changed;
 4017            return result;
 4018        }
 4019        let mut state = DeferredSelectionEffectsState {
 4020            changed: false,
 4021            effects,
 4022            old_cursor_position: self.selections.newest_anchor().head(),
 4023            history_entry: SelectionHistoryEntry {
 4024                selections: self.selections.disjoint_anchors_arc(),
 4025                select_next_state: self.select_next_state.clone(),
 4026                select_prev_state: self.select_prev_state.clone(),
 4027                add_selections_state: self.add_selections_state.clone(),
 4028            },
 4029        };
 4030        let (changed, result) = self.selections.change_with(&snapshot, change);
 4031        state.changed = state.changed || changed;
 4032        if self.defer_selection_effects {
 4033            self.deferred_selection_effects_state = Some(state);
 4034        } else {
 4035            self.apply_selection_effects(state, window, cx);
 4036        }
 4037        result
 4038    }
 4039
 4040    /// Defers the effects of selection change, so that the effects of multiple calls to
 4041    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4042    /// to selection history and the state of popovers based on selection position aren't
 4043    /// erroneously updated.
 4044    pub fn with_selection_effects_deferred<R>(
 4045        &mut self,
 4046        window: &mut Window,
 4047        cx: &mut Context<Self>,
 4048        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4049    ) -> R {
 4050        let already_deferred = self.defer_selection_effects;
 4051        self.defer_selection_effects = true;
 4052        let result = update(self, window, cx);
 4053        if !already_deferred {
 4054            self.defer_selection_effects = false;
 4055            if let Some(state) = self.deferred_selection_effects_state.take() {
 4056                self.apply_selection_effects(state, window, cx);
 4057            }
 4058        }
 4059        result
 4060    }
 4061
 4062    fn apply_selection_effects(
 4063        &mut self,
 4064        state: DeferredSelectionEffectsState,
 4065        window: &mut Window,
 4066        cx: &mut Context<Self>,
 4067    ) {
 4068        if state.changed {
 4069            self.selection_history.push(state.history_entry);
 4070
 4071            if let Some(autoscroll) = state.effects.scroll {
 4072                self.request_autoscroll(autoscroll, cx);
 4073            }
 4074
 4075            let old_cursor_position = &state.old_cursor_position;
 4076
 4077            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4078
 4079            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4080                self.show_signature_help_auto(window, cx);
 4081            }
 4082        }
 4083    }
 4084
 4085    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4086    where
 4087        I: IntoIterator<Item = (Range<S>, T)>,
 4088        S: ToOffset,
 4089        T: Into<Arc<str>>,
 4090    {
 4091        if self.read_only(cx) {
 4092            return;
 4093        }
 4094
 4095        self.buffer
 4096            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4097    }
 4098
 4099    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4100    where
 4101        I: IntoIterator<Item = (Range<S>, T)>,
 4102        S: ToOffset,
 4103        T: Into<Arc<str>>,
 4104    {
 4105        if self.read_only(cx) {
 4106            return;
 4107        }
 4108
 4109        self.buffer.update(cx, |buffer, cx| {
 4110            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4111        });
 4112    }
 4113
 4114    pub fn edit_with_block_indent<I, S, T>(
 4115        &mut self,
 4116        edits: I,
 4117        original_indent_columns: Vec<Option<u32>>,
 4118        cx: &mut Context<Self>,
 4119    ) where
 4120        I: IntoIterator<Item = (Range<S>, T)>,
 4121        S: ToOffset,
 4122        T: Into<Arc<str>>,
 4123    {
 4124        if self.read_only(cx) {
 4125            return;
 4126        }
 4127
 4128        self.buffer.update(cx, |buffer, cx| {
 4129            buffer.edit(
 4130                edits,
 4131                Some(AutoindentMode::Block {
 4132                    original_indent_columns,
 4133                }),
 4134                cx,
 4135            )
 4136        });
 4137    }
 4138
 4139    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4140        self.hide_context_menu(window, cx);
 4141
 4142        match phase {
 4143            SelectPhase::Begin {
 4144                position,
 4145                add,
 4146                click_count,
 4147            } => self.begin_selection(position, add, click_count, window, cx),
 4148            SelectPhase::BeginColumnar {
 4149                position,
 4150                goal_column,
 4151                reset,
 4152                mode,
 4153            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4154            SelectPhase::Extend {
 4155                position,
 4156                click_count,
 4157            } => self.extend_selection(position, click_count, window, cx),
 4158            SelectPhase::Update {
 4159                position,
 4160                goal_column,
 4161                scroll_delta,
 4162            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4163            SelectPhase::End => self.end_selection(window, cx),
 4164        }
 4165    }
 4166
 4167    fn extend_selection(
 4168        &mut self,
 4169        position: DisplayPoint,
 4170        click_count: usize,
 4171        window: &mut Window,
 4172        cx: &mut Context<Self>,
 4173    ) {
 4174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4175        let tail = self
 4176            .selections
 4177            .newest::<MultiBufferOffset>(&display_map)
 4178            .tail();
 4179        let click_count = click_count.max(match self.selections.select_mode() {
 4180            SelectMode::Character => 1,
 4181            SelectMode::Word(_) => 2,
 4182            SelectMode::Line(_) => 3,
 4183            SelectMode::All => 4,
 4184        });
 4185        self.begin_selection(position, false, click_count, window, cx);
 4186
 4187        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4188
 4189        let current_selection = match self.selections.select_mode() {
 4190            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4191            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4192        };
 4193
 4194        let mut pending_selection = self
 4195            .selections
 4196            .pending_anchor()
 4197            .cloned()
 4198            .expect("extend_selection not called with pending selection");
 4199
 4200        if pending_selection
 4201            .start
 4202            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4203            == Ordering::Greater
 4204        {
 4205            pending_selection.start = current_selection.start;
 4206        }
 4207        if pending_selection
 4208            .end
 4209            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4210            == Ordering::Less
 4211        {
 4212            pending_selection.end = current_selection.end;
 4213            pending_selection.reversed = true;
 4214        }
 4215
 4216        let mut pending_mode = self.selections.pending_mode().unwrap();
 4217        match &mut pending_mode {
 4218            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4219            _ => {}
 4220        }
 4221
 4222        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4223            SelectionEffects::scroll(Autoscroll::fit())
 4224        } else {
 4225            SelectionEffects::no_scroll()
 4226        };
 4227
 4228        self.change_selections(effects, window, cx, |s| {
 4229            s.set_pending(pending_selection.clone(), pending_mode);
 4230            s.set_is_extending(true);
 4231        });
 4232    }
 4233
 4234    fn begin_selection(
 4235        &mut self,
 4236        position: DisplayPoint,
 4237        add: bool,
 4238        click_count: usize,
 4239        window: &mut Window,
 4240        cx: &mut Context<Self>,
 4241    ) {
 4242        if !self.focus_handle.is_focused(window) {
 4243            self.last_focused_descendant = None;
 4244            window.focus(&self.focus_handle, cx);
 4245        }
 4246
 4247        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4248        let buffer = display_map.buffer_snapshot();
 4249        let position = display_map.clip_point(position, Bias::Left);
 4250
 4251        let start;
 4252        let end;
 4253        let mode;
 4254        let mut auto_scroll;
 4255        match click_count {
 4256            1 => {
 4257                start = buffer.anchor_before(position.to_point(&display_map));
 4258                end = start;
 4259                mode = SelectMode::Character;
 4260                auto_scroll = true;
 4261            }
 4262            2 => {
 4263                let position = display_map
 4264                    .clip_point(position, Bias::Left)
 4265                    .to_offset(&display_map, Bias::Left);
 4266                let (range, _) = buffer.surrounding_word(position, None);
 4267                start = buffer.anchor_before(range.start);
 4268                end = buffer.anchor_before(range.end);
 4269                mode = SelectMode::Word(start..end);
 4270                auto_scroll = true;
 4271            }
 4272            3 => {
 4273                let position = display_map
 4274                    .clip_point(position, Bias::Left)
 4275                    .to_point(&display_map);
 4276                let line_start = display_map.prev_line_boundary(position).0;
 4277                let next_line_start = buffer.clip_point(
 4278                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4279                    Bias::Left,
 4280                );
 4281                start = buffer.anchor_before(line_start);
 4282                end = buffer.anchor_before(next_line_start);
 4283                mode = SelectMode::Line(start..end);
 4284                auto_scroll = true;
 4285            }
 4286            _ => {
 4287                start = buffer.anchor_before(MultiBufferOffset(0));
 4288                end = buffer.anchor_before(buffer.len());
 4289                mode = SelectMode::All;
 4290                auto_scroll = false;
 4291            }
 4292        }
 4293        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4294
 4295        let point_to_delete: Option<usize> = {
 4296            let selected_points: Vec<Selection<Point>> =
 4297                self.selections.disjoint_in_range(start..end, &display_map);
 4298
 4299            if !add || click_count > 1 {
 4300                None
 4301            } else if !selected_points.is_empty() {
 4302                Some(selected_points[0].id)
 4303            } else {
 4304                let clicked_point_already_selected =
 4305                    self.selections.disjoint_anchors().iter().find(|selection| {
 4306                        selection.start.to_point(buffer) == start.to_point(buffer)
 4307                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4308                    });
 4309
 4310                clicked_point_already_selected.map(|selection| selection.id)
 4311            }
 4312        };
 4313
 4314        let selections_count = self.selections.count();
 4315        let effects = if auto_scroll {
 4316            SelectionEffects::default()
 4317        } else {
 4318            SelectionEffects::no_scroll()
 4319        };
 4320
 4321        self.change_selections(effects, window, cx, |s| {
 4322            if let Some(point_to_delete) = point_to_delete {
 4323                s.delete(point_to_delete);
 4324
 4325                if selections_count == 1 {
 4326                    s.set_pending_anchor_range(start..end, mode);
 4327                }
 4328            } else {
 4329                if !add {
 4330                    s.clear_disjoint();
 4331                }
 4332
 4333                s.set_pending_anchor_range(start..end, mode);
 4334            }
 4335        });
 4336    }
 4337
 4338    fn begin_columnar_selection(
 4339        &mut self,
 4340        position: DisplayPoint,
 4341        goal_column: u32,
 4342        reset: bool,
 4343        mode: ColumnarMode,
 4344        window: &mut Window,
 4345        cx: &mut Context<Self>,
 4346    ) {
 4347        if !self.focus_handle.is_focused(window) {
 4348            self.last_focused_descendant = None;
 4349            window.focus(&self.focus_handle, cx);
 4350        }
 4351
 4352        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4353
 4354        if reset {
 4355            let pointer_position = display_map
 4356                .buffer_snapshot()
 4357                .anchor_before(position.to_point(&display_map));
 4358
 4359            self.change_selections(
 4360                SelectionEffects::scroll(Autoscroll::newest()),
 4361                window,
 4362                cx,
 4363                |s| {
 4364                    s.clear_disjoint();
 4365                    s.set_pending_anchor_range(
 4366                        pointer_position..pointer_position,
 4367                        SelectMode::Character,
 4368                    );
 4369                },
 4370            );
 4371        };
 4372
 4373        let tail = self.selections.newest::<Point>(&display_map).tail();
 4374        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4375        self.columnar_selection_state = match mode {
 4376            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4377                selection_tail: selection_anchor,
 4378                display_point: if reset {
 4379                    if position.column() != goal_column {
 4380                        Some(DisplayPoint::new(position.row(), goal_column))
 4381                    } else {
 4382                        None
 4383                    }
 4384                } else {
 4385                    None
 4386                },
 4387            }),
 4388            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4389                selection_tail: selection_anchor,
 4390            }),
 4391        };
 4392
 4393        if !reset {
 4394            self.select_columns(position, goal_column, &display_map, window, cx);
 4395        }
 4396    }
 4397
 4398    fn update_selection(
 4399        &mut self,
 4400        position: DisplayPoint,
 4401        goal_column: u32,
 4402        scroll_delta: gpui::Point<f32>,
 4403        window: &mut Window,
 4404        cx: &mut Context<Self>,
 4405    ) {
 4406        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4407
 4408        if self.columnar_selection_state.is_some() {
 4409            self.select_columns(position, goal_column, &display_map, window, cx);
 4410        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4411            let buffer = display_map.buffer_snapshot();
 4412            let head;
 4413            let tail;
 4414            let mode = self.selections.pending_mode().unwrap();
 4415            match &mode {
 4416                SelectMode::Character => {
 4417                    head = position.to_point(&display_map);
 4418                    tail = pending.tail().to_point(buffer);
 4419                }
 4420                SelectMode::Word(original_range) => {
 4421                    let offset = display_map
 4422                        .clip_point(position, Bias::Left)
 4423                        .to_offset(&display_map, Bias::Left);
 4424                    let original_range = original_range.to_offset(buffer);
 4425
 4426                    let head_offset = if buffer.is_inside_word(offset, None)
 4427                        || original_range.contains(&offset)
 4428                    {
 4429                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4430                        if word_range.start < original_range.start {
 4431                            word_range.start
 4432                        } else {
 4433                            word_range.end
 4434                        }
 4435                    } else {
 4436                        offset
 4437                    };
 4438
 4439                    head = head_offset.to_point(buffer);
 4440                    if head_offset <= original_range.start {
 4441                        tail = original_range.end.to_point(buffer);
 4442                    } else {
 4443                        tail = original_range.start.to_point(buffer);
 4444                    }
 4445                }
 4446                SelectMode::Line(original_range) => {
 4447                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4448
 4449                    let position = display_map
 4450                        .clip_point(position, Bias::Left)
 4451                        .to_point(&display_map);
 4452                    let line_start = display_map.prev_line_boundary(position).0;
 4453                    let next_line_start = buffer.clip_point(
 4454                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4455                        Bias::Left,
 4456                    );
 4457
 4458                    if line_start < original_range.start {
 4459                        head = line_start
 4460                    } else {
 4461                        head = next_line_start
 4462                    }
 4463
 4464                    if head <= original_range.start {
 4465                        tail = original_range.end;
 4466                    } else {
 4467                        tail = original_range.start;
 4468                    }
 4469                }
 4470                SelectMode::All => {
 4471                    return;
 4472                }
 4473            };
 4474
 4475            if head < tail {
 4476                pending.start = buffer.anchor_before(head);
 4477                pending.end = buffer.anchor_before(tail);
 4478                pending.reversed = true;
 4479            } else {
 4480                pending.start = buffer.anchor_before(tail);
 4481                pending.end = buffer.anchor_before(head);
 4482                pending.reversed = false;
 4483            }
 4484
 4485            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4486                s.set_pending(pending.clone(), mode);
 4487            });
 4488        } else {
 4489            log::error!("update_selection dispatched with no pending selection");
 4490            return;
 4491        }
 4492
 4493        self.apply_scroll_delta(scroll_delta, window, cx);
 4494        cx.notify();
 4495    }
 4496
 4497    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4498        self.columnar_selection_state.take();
 4499        if let Some(pending_mode) = self.selections.pending_mode() {
 4500            let selections = self
 4501                .selections
 4502                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4503            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4504                s.select(selections);
 4505                s.clear_pending();
 4506                if s.is_extending() {
 4507                    s.set_is_extending(false);
 4508                } else {
 4509                    s.set_select_mode(pending_mode);
 4510                }
 4511            });
 4512        }
 4513    }
 4514
 4515    fn select_columns(
 4516        &mut self,
 4517        head: DisplayPoint,
 4518        goal_column: u32,
 4519        display_map: &DisplaySnapshot,
 4520        window: &mut Window,
 4521        cx: &mut Context<Self>,
 4522    ) {
 4523        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4524            return;
 4525        };
 4526
 4527        let tail = match columnar_state {
 4528            ColumnarSelectionState::FromMouse {
 4529                selection_tail,
 4530                display_point,
 4531            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4532            ColumnarSelectionState::FromSelection { selection_tail } => {
 4533                selection_tail.to_display_point(display_map)
 4534            }
 4535        };
 4536
 4537        let start_row = cmp::min(tail.row(), head.row());
 4538        let end_row = cmp::max(tail.row(), head.row());
 4539        let start_column = cmp::min(tail.column(), goal_column);
 4540        let end_column = cmp::max(tail.column(), goal_column);
 4541        let reversed = start_column < tail.column();
 4542
 4543        let selection_ranges = (start_row.0..=end_row.0)
 4544            .map(DisplayRow)
 4545            .filter_map(|row| {
 4546                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4547                    || start_column <= display_map.line_len(row))
 4548                    && !display_map.is_block_line(row)
 4549                {
 4550                    let start = display_map
 4551                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4552                        .to_point(display_map);
 4553                    let end = display_map
 4554                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4555                        .to_point(display_map);
 4556                    if reversed {
 4557                        Some(end..start)
 4558                    } else {
 4559                        Some(start..end)
 4560                    }
 4561                } else {
 4562                    None
 4563                }
 4564            })
 4565            .collect::<Vec<_>>();
 4566        if selection_ranges.is_empty() {
 4567            return;
 4568        }
 4569
 4570        let ranges = match columnar_state {
 4571            ColumnarSelectionState::FromMouse { .. } => {
 4572                let mut non_empty_ranges = selection_ranges
 4573                    .iter()
 4574                    .filter(|selection_range| selection_range.start != selection_range.end)
 4575                    .peekable();
 4576                if non_empty_ranges.peek().is_some() {
 4577                    non_empty_ranges.cloned().collect()
 4578                } else {
 4579                    selection_ranges
 4580                }
 4581            }
 4582            _ => selection_ranges,
 4583        };
 4584
 4585        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4586            s.select_ranges(ranges);
 4587        });
 4588        cx.notify();
 4589    }
 4590
 4591    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4592        self.selections
 4593            .all_adjusted(snapshot)
 4594            .iter()
 4595            .any(|selection| !selection.is_empty())
 4596    }
 4597
 4598    pub fn has_pending_nonempty_selection(&self) -> bool {
 4599        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4600            Some(Selection { start, end, .. }) => start != end,
 4601            None => false,
 4602        };
 4603
 4604        pending_nonempty_selection
 4605            || (self.columnar_selection_state.is_some()
 4606                && self.selections.disjoint_anchors().len() > 1)
 4607    }
 4608
 4609    pub fn has_pending_selection(&self) -> bool {
 4610        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4611    }
 4612
 4613    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4614        self.selection_mark_mode = false;
 4615        self.selection_drag_state = SelectionDragState::None;
 4616
 4617        if self.dismiss_menus_and_popups(true, window, cx) {
 4618            cx.notify();
 4619            return;
 4620        }
 4621        if self.clear_expanded_diff_hunks(cx) {
 4622            cx.notify();
 4623            return;
 4624        }
 4625        if self.show_git_blame_gutter {
 4626            self.show_git_blame_gutter = false;
 4627            cx.notify();
 4628            return;
 4629        }
 4630
 4631        if self.mode.is_full()
 4632            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4633        {
 4634            cx.notify();
 4635            return;
 4636        }
 4637
 4638        cx.propagate();
 4639    }
 4640
 4641    pub fn dismiss_menus_and_popups(
 4642        &mut self,
 4643        is_user_requested: bool,
 4644        window: &mut Window,
 4645        cx: &mut Context<Self>,
 4646    ) -> bool {
 4647        let mut dismissed = false;
 4648
 4649        dismissed |= self.take_rename(false, window, cx).is_some();
 4650        dismissed |= self.hide_blame_popover(true, cx);
 4651        dismissed |= hide_hover(self, cx);
 4652        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4653        dismissed |= self.hide_context_menu(window, cx).is_some();
 4654        dismissed |= self.mouse_context_menu.take().is_some();
 4655        dismissed |= is_user_requested
 4656            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4657        dismissed |= self.snippet_stack.pop().is_some();
 4658        if self.diff_review_drag_state.is_some() {
 4659            self.cancel_diff_review_drag(cx);
 4660            dismissed = true;
 4661        }
 4662        if !self.diff_review_overlays.is_empty() {
 4663            self.dismiss_all_diff_review_overlays(cx);
 4664            dismissed = true;
 4665        }
 4666
 4667        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4668            self.dismiss_diagnostics(cx);
 4669            dismissed = true;
 4670        }
 4671
 4672        dismissed
 4673    }
 4674
 4675    fn linked_editing_ranges_for(
 4676        &self,
 4677        query_range: Range<text::Anchor>,
 4678        cx: &App,
 4679    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4680        use text::ToOffset as TO;
 4681
 4682        if self.linked_edit_ranges.is_empty() {
 4683            return None;
 4684        }
 4685        if query_range.start.buffer_id != query_range.end.buffer_id {
 4686            return None;
 4687        };
 4688        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 4689        let buffer = self.buffer.read(cx).buffer(query_range.end.buffer_id)?;
 4690        let buffer_snapshot = buffer.read(cx).snapshot();
 4691        let (base_range, linked_ranges) = self.linked_edit_ranges.get(
 4692            buffer_snapshot.remote_id(),
 4693            query_range.clone(),
 4694            &buffer_snapshot,
 4695        )?;
 4696        // find offset from the start of current range to current cursor position
 4697        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4698
 4699        let start_offset = TO::to_offset(&query_range.start, &buffer_snapshot);
 4700        let start_difference = start_offset - start_byte_offset;
 4701        let end_offset = TO::to_offset(&query_range.end, &buffer_snapshot);
 4702        let end_difference = end_offset - start_byte_offset;
 4703
 4704        // Current range has associated linked ranges.
 4705        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4706        for range in linked_ranges.iter() {
 4707            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4708            let end_offset = start_offset + end_difference;
 4709            let start_offset = start_offset + start_difference;
 4710            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4711                continue;
 4712            }
 4713            if self.selections.disjoint_anchor_ranges().any(|s| {
 4714                let Some((selection_start, _)) =
 4715                    multibuffer_snapshot.anchor_to_buffer_anchor(s.start)
 4716                else {
 4717                    return false;
 4718                };
 4719                let Some((selection_end, _)) = multibuffer_snapshot.anchor_to_buffer_anchor(s.end)
 4720                else {
 4721                    return false;
 4722                };
 4723                if selection_start.buffer_id != query_range.start.buffer_id
 4724                    || selection_end.buffer_id != query_range.end.buffer_id
 4725                {
 4726                    return false;
 4727                }
 4728                TO::to_offset(&selection_start, &buffer_snapshot) <= end_offset
 4729                    && TO::to_offset(&selection_end, &buffer_snapshot) >= start_offset
 4730            }) {
 4731                continue;
 4732            }
 4733            let start = buffer_snapshot.anchor_after(start_offset);
 4734            let end = buffer_snapshot.anchor_after(end_offset);
 4735            linked_edits
 4736                .entry(buffer.clone())
 4737                .or_default()
 4738                .push(start..end);
 4739        }
 4740        Some(linked_edits)
 4741    }
 4742
 4743    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4744        let text: Arc<str> = text.into();
 4745
 4746        if self.read_only(cx) {
 4747            return;
 4748        }
 4749
 4750        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4751
 4752        self.unfold_buffers_with_selections(cx);
 4753
 4754        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4755        let mut bracket_inserted = false;
 4756        let mut edits = Vec::new();
 4757        let mut linked_edits = LinkedEdits::new();
 4758        let mut new_selections = Vec::with_capacity(selections.len());
 4759        let mut new_autoclose_regions = Vec::new();
 4760        let snapshot = self.buffer.read(cx).read(cx);
 4761        let mut clear_linked_edit_ranges = false;
 4762        let mut all_selections_read_only = true;
 4763        let mut has_adjacent_edits = false;
 4764        let mut in_adjacent_group = false;
 4765
 4766        let mut regions = self
 4767            .selections_with_autoclose_regions(selections, &snapshot)
 4768            .peekable();
 4769
 4770        while let Some((selection, autoclose_region)) = regions.next() {
 4771            if snapshot
 4772                .point_to_buffer_point(selection.head())
 4773                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4774            {
 4775                continue;
 4776            }
 4777            if snapshot
 4778                .point_to_buffer_point(selection.tail())
 4779                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4780            {
 4781                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4782                continue;
 4783            }
 4784            all_selections_read_only = false;
 4785
 4786            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4787                // Determine if the inserted text matches the opening or closing
 4788                // bracket of any of this language's bracket pairs.
 4789                let mut bracket_pair = None;
 4790                let mut is_bracket_pair_start = false;
 4791                let mut is_bracket_pair_end = false;
 4792                if !text.is_empty() {
 4793                    let mut bracket_pair_matching_end = None;
 4794                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4795                    //  and they are removing the character that triggered IME popup.
 4796                    for (pair, enabled) in scope.brackets() {
 4797                        if !pair.close && !pair.surround {
 4798                            continue;
 4799                        }
 4800
 4801                        if enabled && pair.start.ends_with(text.as_ref()) {
 4802                            let prefix_len = pair.start.len() - text.len();
 4803                            let preceding_text_matches_prefix = prefix_len == 0
 4804                                || (selection.start.column >= (prefix_len as u32)
 4805                                    && snapshot.contains_str_at(
 4806                                        Point::new(
 4807                                            selection.start.row,
 4808                                            selection.start.column - (prefix_len as u32),
 4809                                        ),
 4810                                        &pair.start[..prefix_len],
 4811                                    ));
 4812                            if preceding_text_matches_prefix {
 4813                                bracket_pair = Some(pair.clone());
 4814                                is_bracket_pair_start = true;
 4815                                break;
 4816                            }
 4817                        }
 4818                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4819                        {
 4820                            // take first bracket pair matching end, but don't break in case a later bracket
 4821                            // pair matches start
 4822                            bracket_pair_matching_end = Some(pair.clone());
 4823                        }
 4824                    }
 4825                    if let Some(end) = bracket_pair_matching_end
 4826                        && bracket_pair.is_none()
 4827                    {
 4828                        bracket_pair = Some(end);
 4829                        is_bracket_pair_end = true;
 4830                    }
 4831                }
 4832
 4833                if let Some(bracket_pair) = bracket_pair {
 4834                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4835                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4836                    let auto_surround =
 4837                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4838                    if selection.is_empty() {
 4839                        if is_bracket_pair_start {
 4840                            // If the inserted text is a suffix of an opening bracket and the
 4841                            // selection is preceded by the rest of the opening bracket, then
 4842                            // insert the closing bracket.
 4843                            let following_text_allows_autoclose = snapshot
 4844                                .chars_at(selection.start)
 4845                                .next()
 4846                                .is_none_or(|c| scope.should_autoclose_before(c));
 4847
 4848                            let preceding_text_allows_autoclose = selection.start.column == 0
 4849                                || snapshot
 4850                                    .reversed_chars_at(selection.start)
 4851                                    .next()
 4852                                    .is_none_or(|c| {
 4853                                        bracket_pair.start != bracket_pair.end
 4854                                            || !snapshot
 4855                                                .char_classifier_at(selection.start)
 4856                                                .is_word(c)
 4857                                    });
 4858
 4859                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4860                                && bracket_pair.start.len() == 1
 4861                            {
 4862                                let target = bracket_pair.start.chars().next().unwrap();
 4863                                let mut byte_offset = 0u32;
 4864                                let current_line_count = snapshot
 4865                                    .reversed_chars_at(selection.start)
 4866                                    .take_while(|&c| c != '\n')
 4867                                    .filter(|c| {
 4868                                        byte_offset += c.len_utf8() as u32;
 4869                                        if *c != target {
 4870                                            return false;
 4871                                        }
 4872
 4873                                        let point = Point::new(
 4874                                            selection.start.row,
 4875                                            selection.start.column.saturating_sub(byte_offset),
 4876                                        );
 4877
 4878                                        let is_enabled = snapshot
 4879                                            .language_scope_at(point)
 4880                                            .and_then(|scope| {
 4881                                                scope
 4882                                                    .brackets()
 4883                                                    .find(|(pair, _)| {
 4884                                                        pair.start == bracket_pair.start
 4885                                                    })
 4886                                                    .map(|(_, enabled)| enabled)
 4887                                            })
 4888                                            .unwrap_or(true);
 4889
 4890                                        let is_delimiter = snapshot
 4891                                            .language_scope_at(Point::new(
 4892                                                point.row,
 4893                                                point.column + 1,
 4894                                            ))
 4895                                            .and_then(|scope| {
 4896                                                scope
 4897                                                    .brackets()
 4898                                                    .find(|(pair, _)| {
 4899                                                        pair.start == bracket_pair.start
 4900                                                    })
 4901                                                    .map(|(_, enabled)| !enabled)
 4902                                            })
 4903                                            .unwrap_or(false);
 4904
 4905                                        is_enabled && !is_delimiter
 4906                                    })
 4907                                    .count();
 4908                                current_line_count % 2 == 1
 4909                            } else {
 4910                                false
 4911                            };
 4912
 4913                            if autoclose
 4914                                && bracket_pair.close
 4915                                && following_text_allows_autoclose
 4916                                && preceding_text_allows_autoclose
 4917                                && !is_closing_quote
 4918                            {
 4919                                let anchor = snapshot.anchor_before(selection.end);
 4920                                new_selections.push((selection.map(|_| anchor), text.len()));
 4921                                new_autoclose_regions.push((
 4922                                    anchor,
 4923                                    text.len(),
 4924                                    selection.id,
 4925                                    bracket_pair.clone(),
 4926                                ));
 4927                                edits.push((
 4928                                    selection.range(),
 4929                                    format!("{}{}", text, bracket_pair.end).into(),
 4930                                ));
 4931                                bracket_inserted = true;
 4932                                continue;
 4933                            }
 4934                        }
 4935
 4936                        if let Some(region) = autoclose_region {
 4937                            // If the selection is followed by an auto-inserted closing bracket,
 4938                            // then don't insert that closing bracket again; just move the selection
 4939                            // past the closing bracket.
 4940                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4941                                && text.as_ref() == region.pair.end.as_str()
 4942                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4943                            if should_skip {
 4944                                let anchor = snapshot.anchor_after(selection.end);
 4945                                new_selections
 4946                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4947                                continue;
 4948                            }
 4949                        }
 4950
 4951                        let always_treat_brackets_as_autoclosed = snapshot
 4952                            .language_settings_at(selection.start, cx)
 4953                            .always_treat_brackets_as_autoclosed;
 4954                        if always_treat_brackets_as_autoclosed
 4955                            && is_bracket_pair_end
 4956                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4957                        {
 4958                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4959                            // and the inserted text is a closing bracket and the selection is followed
 4960                            // by the closing bracket then move the selection past the closing bracket.
 4961                            let anchor = snapshot.anchor_after(selection.end);
 4962                            new_selections.push((selection.map(|_| anchor), text.len()));
 4963                            continue;
 4964                        }
 4965                    }
 4966                    // If an opening bracket is 1 character long and is typed while
 4967                    // text is selected, then surround that text with the bracket pair.
 4968                    else if auto_surround
 4969                        && bracket_pair.surround
 4970                        && is_bracket_pair_start
 4971                        && bracket_pair.start.chars().count() == 1
 4972                    {
 4973                        edits.push((selection.start..selection.start, text.clone()));
 4974                        edits.push((
 4975                            selection.end..selection.end,
 4976                            bracket_pair.end.as_str().into(),
 4977                        ));
 4978                        bracket_inserted = true;
 4979                        new_selections.push((
 4980                            Selection {
 4981                                id: selection.id,
 4982                                start: snapshot.anchor_after(selection.start),
 4983                                end: snapshot.anchor_before(selection.end),
 4984                                reversed: selection.reversed,
 4985                                goal: selection.goal,
 4986                            },
 4987                            0,
 4988                        ));
 4989                        continue;
 4990                    }
 4991                }
 4992            }
 4993
 4994            if self.auto_replace_emoji_shortcode
 4995                && selection.is_empty()
 4996                && text.as_ref().ends_with(':')
 4997                && let Some(possible_emoji_short_code) =
 4998                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4999                && !possible_emoji_short_code.is_empty()
 5000                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 5001            {
 5002                let emoji_shortcode_start = Point::new(
 5003                    selection.start.row,
 5004                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 5005                );
 5006
 5007                // Remove shortcode from buffer
 5008                edits.push((
 5009                    emoji_shortcode_start..selection.start,
 5010                    "".to_string().into(),
 5011                ));
 5012                new_selections.push((
 5013                    Selection {
 5014                        id: selection.id,
 5015                        start: snapshot.anchor_after(emoji_shortcode_start),
 5016                        end: snapshot.anchor_before(selection.start),
 5017                        reversed: selection.reversed,
 5018                        goal: selection.goal,
 5019                    },
 5020                    0,
 5021                ));
 5022
 5023                // Insert emoji
 5024                let selection_start_anchor = snapshot.anchor_after(selection.start);
 5025                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 5026                edits.push((selection.start..selection.end, emoji.to_string().into()));
 5027
 5028                continue;
 5029            }
 5030
 5031            let next_is_adjacent = regions
 5032                .peek()
 5033                .is_some_and(|(next, _)| selection.end == next.start);
 5034
 5035            // If not handling any auto-close operation, then just replace the selected
 5036            // text with the given input and move the selection to the end of the
 5037            // newly inserted text.
 5038            let anchor = if in_adjacent_group || next_is_adjacent {
 5039                // After edits the right bias would shift those anchor to the next visible fragment
 5040                // but we want to resolve to the previous one
 5041                snapshot.anchor_before(selection.end)
 5042            } else {
 5043                snapshot.anchor_after(selection.end)
 5044            };
 5045
 5046            if !self.linked_edit_ranges.is_empty() {
 5047                let start_anchor = snapshot.anchor_before(selection.start);
 5048                let classifier = snapshot
 5049                    .char_classifier_at(start_anchor)
 5050                    .scope_context(Some(CharScopeContext::LinkedEdit));
 5051
 5052                if let Some((_, anchor_range)) =
 5053                    snapshot.anchor_range_to_buffer_anchor_range(start_anchor..anchor)
 5054                {
 5055                    let is_word_char = text
 5056                        .chars()
 5057                        .next()
 5058                        .is_none_or(|char| classifier.is_word(char));
 5059
 5060                    let is_dot = text.as_ref() == ".";
 5061                    let should_apply_linked_edit = is_word_char || is_dot;
 5062
 5063                    if should_apply_linked_edit {
 5064                        linked_edits.push(&self, anchor_range, text.clone(), cx);
 5065                    } else {
 5066                        clear_linked_edit_ranges = true;
 5067                    }
 5068                }
 5069            }
 5070
 5071            new_selections.push((selection.map(|_| anchor), 0));
 5072            edits.push((selection.start..selection.end, text.clone()));
 5073
 5074            has_adjacent_edits |= next_is_adjacent;
 5075            in_adjacent_group = next_is_adjacent;
 5076        }
 5077
 5078        if all_selections_read_only {
 5079            return;
 5080        }
 5081
 5082        drop(regions);
 5083        drop(snapshot);
 5084
 5085        self.transact(window, cx, |this, window, cx| {
 5086            if clear_linked_edit_ranges {
 5087                this.linked_edit_ranges.clear();
 5088            }
 5089            let initial_buffer_versions =
 5090                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5091
 5092            this.buffer.update(cx, |buffer, cx| {
 5093                if has_adjacent_edits {
 5094                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5095                } else {
 5096                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5097                }
 5098            });
 5099            linked_edits.apply(cx);
 5100            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5101            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5102            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5103            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5104                new_anchor_selections,
 5105                &map,
 5106            )
 5107            .zip(new_selection_deltas)
 5108            .map(|(selection, delta)| Selection {
 5109                id: selection.id,
 5110                start: selection.start + delta,
 5111                end: selection.end + delta,
 5112                reversed: selection.reversed,
 5113                goal: SelectionGoal::None,
 5114            })
 5115            .collect::<Vec<_>>();
 5116
 5117            let mut i = 0;
 5118            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5119                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5120                let start = map.buffer_snapshot().anchor_before(position);
 5121                let end = map.buffer_snapshot().anchor_after(position);
 5122                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5123                    match existing_state
 5124                        .range
 5125                        .start
 5126                        .cmp(&start, map.buffer_snapshot())
 5127                    {
 5128                        Ordering::Less => i += 1,
 5129                        Ordering::Greater => break,
 5130                        Ordering::Equal => {
 5131                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5132                                Ordering::Less => i += 1,
 5133                                Ordering::Equal => break,
 5134                                Ordering::Greater => break,
 5135                            }
 5136                        }
 5137                    }
 5138                }
 5139                this.autoclose_regions.insert(
 5140                    i,
 5141                    AutocloseRegion {
 5142                        selection_id,
 5143                        range: start..end,
 5144                        pair,
 5145                    },
 5146                );
 5147            }
 5148
 5149            let had_active_edit_prediction = this.has_active_edit_prediction();
 5150            this.change_selections(
 5151                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5152                window,
 5153                cx,
 5154                |s| s.select(new_selections),
 5155            );
 5156
 5157            if !bracket_inserted
 5158                && let Some(on_type_format_task) =
 5159                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5160            {
 5161                on_type_format_task.detach_and_log_err(cx);
 5162            }
 5163
 5164            let editor_settings = EditorSettings::get_global(cx);
 5165            if bracket_inserted
 5166                && (editor_settings.auto_signature_help
 5167                    || editor_settings.show_signature_help_after_edits)
 5168            {
 5169                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5170            }
 5171
 5172            let trigger_in_words =
 5173                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5174            if this.hard_wrap.is_some() {
 5175                let latest: Range<Point> = this.selections.newest(&map).range();
 5176                if latest.is_empty()
 5177                    && this
 5178                        .buffer()
 5179                        .read(cx)
 5180                        .snapshot(cx)
 5181                        .line_len(MultiBufferRow(latest.start.row))
 5182                        == latest.start.column
 5183                {
 5184                    this.rewrap_impl(
 5185                        RewrapOptions {
 5186                            override_language_settings: true,
 5187                            preserve_existing_whitespace: true,
 5188                            line_length: None,
 5189                        },
 5190                        cx,
 5191                    )
 5192                }
 5193            }
 5194            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5195            refresh_linked_ranges(this, window, cx);
 5196            this.refresh_edit_prediction(true, false, window, cx);
 5197            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5198        });
 5199    }
 5200
 5201    fn find_possible_emoji_shortcode_at_position(
 5202        snapshot: &MultiBufferSnapshot,
 5203        position: Point,
 5204    ) -> Option<String> {
 5205        let mut chars = Vec::new();
 5206        let mut found_colon = false;
 5207        for char in snapshot.reversed_chars_at(position).take(100) {
 5208            // Found a possible emoji shortcode in the middle of the buffer
 5209            if found_colon {
 5210                if char.is_whitespace() {
 5211                    chars.reverse();
 5212                    return Some(chars.iter().collect());
 5213                }
 5214                // If the previous character is not a whitespace, we are in the middle of a word
 5215                // and we only want to complete the shortcode if the word is made up of other emojis
 5216                let mut containing_word = String::new();
 5217                for ch in snapshot
 5218                    .reversed_chars_at(position)
 5219                    .skip(chars.len() + 1)
 5220                    .take(100)
 5221                {
 5222                    if ch.is_whitespace() {
 5223                        break;
 5224                    }
 5225                    containing_word.push(ch);
 5226                }
 5227                let containing_word = containing_word.chars().rev().collect::<String>();
 5228                if util::word_consists_of_emojis(containing_word.as_str()) {
 5229                    chars.reverse();
 5230                    return Some(chars.iter().collect());
 5231                }
 5232            }
 5233
 5234            if char.is_whitespace() || !char.is_ascii() {
 5235                return None;
 5236            }
 5237            if char == ':' {
 5238                found_colon = true;
 5239            } else {
 5240                chars.push(char);
 5241            }
 5242        }
 5243        // Found a possible emoji shortcode at the beginning of the buffer
 5244        chars.reverse();
 5245        Some(chars.iter().collect())
 5246    }
 5247
 5248    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5249        if self.read_only(cx) {
 5250            return;
 5251        }
 5252
 5253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5254        self.transact(window, cx, |this, window, cx| {
 5255            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5256                let selections = this
 5257                    .selections
 5258                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5259                let multi_buffer = this.buffer.read(cx);
 5260                let buffer = multi_buffer.snapshot(cx);
 5261                selections
 5262                    .iter()
 5263                    .map(|selection| {
 5264                        let start_point = selection.start.to_point(&buffer);
 5265                        let mut existing_indent =
 5266                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5267                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5268                        let start = selection.start;
 5269                        let end = selection.end;
 5270                        let selection_is_empty = start == end;
 5271                        let language_scope = buffer.language_scope_at(start);
 5272                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5273                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5274                                &buffer,
 5275                                start..end,
 5276                                language,
 5277                            )
 5278                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5279                                    &buffer,
 5280                                    start..end,
 5281                                );
 5282
 5283                            let mut newline_config = NewlineConfig::Newline {
 5284                                additional_indent: IndentSize::spaces(0),
 5285                                extra_line_additional_indent: if needs_extra_newline {
 5286                                    Some(IndentSize::spaces(0))
 5287                                } else {
 5288                                    None
 5289                                },
 5290                                prevent_auto_indent: false,
 5291                            };
 5292
 5293                            let comment_delimiter = maybe!({
 5294                                if !selection_is_empty {
 5295                                    return None;
 5296                                }
 5297
 5298                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5299                                    return None;
 5300                                }
 5301
 5302                                return comment_delimiter_for_newline(
 5303                                    &start_point,
 5304                                    &buffer,
 5305                                    language,
 5306                                );
 5307                            });
 5308
 5309                            let doc_delimiter = maybe!({
 5310                                if !selection_is_empty {
 5311                                    return None;
 5312                                }
 5313
 5314                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5315                                    return None;
 5316                                }
 5317
 5318                                return documentation_delimiter_for_newline(
 5319                                    &start_point,
 5320                                    &buffer,
 5321                                    language,
 5322                                    &mut newline_config,
 5323                                );
 5324                            });
 5325
 5326                            let list_delimiter = maybe!({
 5327                                if !selection_is_empty {
 5328                                    return None;
 5329                                }
 5330
 5331                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5332                                    return None;
 5333                                }
 5334
 5335                                return list_delimiter_for_newline(
 5336                                    &start_point,
 5337                                    &buffer,
 5338                                    language,
 5339                                    &mut newline_config,
 5340                                );
 5341                            });
 5342
 5343                            (
 5344                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5345                                newline_config,
 5346                            )
 5347                        } else {
 5348                            (
 5349                                None,
 5350                                NewlineConfig::Newline {
 5351                                    additional_indent: IndentSize::spaces(0),
 5352                                    extra_line_additional_indent: None,
 5353                                    prevent_auto_indent: false,
 5354                                },
 5355                            )
 5356                        };
 5357
 5358                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5359                            NewlineConfig::ClearCurrentLine => {
 5360                                let row_start =
 5361                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5362                                (row_start, String::new(), false)
 5363                            }
 5364                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5365                                let row_start =
 5366                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5367                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5368                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5369                                let reduced_indent =
 5370                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5371                                let mut new_text = String::new();
 5372                                new_text.extend(reduced_indent.chars());
 5373                                new_text.push_str(continuation);
 5374                                (row_start, new_text, true)
 5375                            }
 5376                            NewlineConfig::Newline {
 5377                                additional_indent,
 5378                                extra_line_additional_indent,
 5379                                prevent_auto_indent,
 5380                            } => {
 5381                                let auto_indent_mode =
 5382                                    buffer.language_settings_at(start, cx).auto_indent;
 5383                                let preserve_indent =
 5384                                    auto_indent_mode != language::AutoIndentMode::None;
 5385                                let apply_syntax_indent =
 5386                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5387                                let capacity_for_delimiter =
 5388                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5389                                let existing_indent_len = if preserve_indent {
 5390                                    existing_indent.len as usize
 5391                                } else {
 5392                                    0
 5393                                };
 5394                                let extra_line_len = extra_line_additional_indent
 5395                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5396                                    .unwrap_or(0);
 5397                                let mut new_text = String::with_capacity(
 5398                                    1 + capacity_for_delimiter
 5399                                        + existing_indent_len
 5400                                        + additional_indent.len as usize
 5401                                        + extra_line_len,
 5402                                );
 5403                                new_text.push('\n');
 5404                                if preserve_indent {
 5405                                    new_text.extend(existing_indent.chars());
 5406                                }
 5407                                new_text.extend(additional_indent.chars());
 5408                                if let Some(delimiter) = &delimiter {
 5409                                    new_text.push_str(delimiter);
 5410                                }
 5411                                if let Some(extra_indent) = extra_line_additional_indent {
 5412                                    new_text.push('\n');
 5413                                    if preserve_indent {
 5414                                        new_text.extend(existing_indent.chars());
 5415                                    }
 5416                                    new_text.extend(extra_indent.chars());
 5417                                }
 5418                                (
 5419                                    start,
 5420                                    new_text,
 5421                                    *prevent_auto_indent || !apply_syntax_indent,
 5422                                )
 5423                            }
 5424                        };
 5425
 5426                        let anchor = buffer.anchor_after(end);
 5427                        let new_selection = selection.map(|_| anchor);
 5428                        (
 5429                            ((edit_start..end, new_text), prevent_auto_indent),
 5430                            (newline_config.has_extra_line(), new_selection),
 5431                        )
 5432                    })
 5433                    .unzip()
 5434            };
 5435
 5436            let mut auto_indent_edits = Vec::new();
 5437            let mut edits = Vec::new();
 5438            for (edit, prevent_auto_indent) in edits_with_flags {
 5439                if prevent_auto_indent {
 5440                    edits.push(edit);
 5441                } else {
 5442                    auto_indent_edits.push(edit);
 5443                }
 5444            }
 5445            if !edits.is_empty() {
 5446                this.edit(edits, cx);
 5447            }
 5448            if !auto_indent_edits.is_empty() {
 5449                this.edit_with_autoindent(auto_indent_edits, cx);
 5450            }
 5451
 5452            let buffer = this.buffer.read(cx).snapshot(cx);
 5453            let new_selections = selection_info
 5454                .into_iter()
 5455                .map(|(extra_newline_inserted, new_selection)| {
 5456                    let mut cursor = new_selection.end.to_point(&buffer);
 5457                    if extra_newline_inserted {
 5458                        cursor.row -= 1;
 5459                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5460                    }
 5461                    new_selection.map(|_| cursor)
 5462                })
 5463                .collect();
 5464
 5465            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5466            this.refresh_edit_prediction(true, false, window, cx);
 5467            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5468                task.detach_and_log_err(cx);
 5469            }
 5470        });
 5471    }
 5472
 5473    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5474        if self.read_only(cx) {
 5475            return;
 5476        }
 5477
 5478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5479
 5480        let buffer = self.buffer.read(cx);
 5481        let snapshot = buffer.snapshot(cx);
 5482
 5483        let mut edits = Vec::new();
 5484        let mut rows = Vec::new();
 5485
 5486        for (rows_inserted, selection) in self
 5487            .selections
 5488            .all_adjusted(&self.display_snapshot(cx))
 5489            .into_iter()
 5490            .enumerate()
 5491        {
 5492            let cursor = selection.head();
 5493            let row = cursor.row;
 5494
 5495            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5496
 5497            let newline = "\n".to_string();
 5498            edits.push((start_of_line..start_of_line, newline));
 5499
 5500            rows.push(row + rows_inserted as u32);
 5501        }
 5502
 5503        self.transact(window, cx, |editor, window, cx| {
 5504            editor.edit(edits, cx);
 5505
 5506            editor.change_selections(Default::default(), window, cx, |s| {
 5507                let mut index = 0;
 5508                s.move_cursors_with(&mut |map, _, _| {
 5509                    let row = rows[index];
 5510                    index += 1;
 5511
 5512                    let point = Point::new(row, 0);
 5513                    let boundary = map.next_line_boundary(point).1;
 5514                    let clipped = map.clip_point(boundary, Bias::Left);
 5515
 5516                    (clipped, SelectionGoal::None)
 5517                });
 5518            });
 5519
 5520            let mut indent_edits = Vec::new();
 5521            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5522            for row in rows {
 5523                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5524                for (row, indent) in indents {
 5525                    if indent.len == 0 {
 5526                        continue;
 5527                    }
 5528
 5529                    let text = match indent.kind {
 5530                        IndentKind::Space => " ".repeat(indent.len as usize),
 5531                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5532                    };
 5533                    let point = Point::new(row.0, 0);
 5534                    indent_edits.push((point..point, text));
 5535                }
 5536            }
 5537            editor.edit(indent_edits, cx);
 5538            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5539                format.detach_and_log_err(cx);
 5540            }
 5541        });
 5542    }
 5543
 5544    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5545        if self.read_only(cx) {
 5546            return;
 5547        }
 5548
 5549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5550
 5551        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5552        let mut rows = Vec::new();
 5553        let mut rows_inserted = 0;
 5554
 5555        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5556            let cursor = selection.head();
 5557            let row = cursor.row;
 5558
 5559            let point = Point::new(row, 0);
 5560            let Some((buffer_handle, buffer_point)) =
 5561                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5562            else {
 5563                continue;
 5564            };
 5565
 5566            buffer_edits
 5567                .entry(buffer_handle.entity_id())
 5568                .or_insert_with(|| (buffer_handle, Vec::new()))
 5569                .1
 5570                .push(buffer_point);
 5571
 5572            rows_inserted += 1;
 5573            rows.push(row + rows_inserted);
 5574        }
 5575
 5576        self.transact(window, cx, |editor, window, cx| {
 5577            for (_, (buffer_handle, points)) in &buffer_edits {
 5578                buffer_handle.update(cx, |buffer, cx| {
 5579                    let edits: Vec<_> = points
 5580                        .iter()
 5581                        .map(|point| {
 5582                            let target = Point::new(point.row + 1, 0);
 5583                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5584                            (start_of_line..start_of_line, "\n")
 5585                        })
 5586                        .collect();
 5587                    buffer.edit(edits, None, cx);
 5588                });
 5589            }
 5590
 5591            editor.change_selections(Default::default(), window, cx, |s| {
 5592                let mut index = 0;
 5593                s.move_cursors_with(&mut |map, _, _| {
 5594                    let row = rows[index];
 5595                    index += 1;
 5596
 5597                    let point = Point::new(row, 0);
 5598                    let boundary = map.next_line_boundary(point).1;
 5599                    let clipped = map.clip_point(boundary, Bias::Left);
 5600
 5601                    (clipped, SelectionGoal::None)
 5602                });
 5603            });
 5604
 5605            let mut indent_edits = Vec::new();
 5606            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5607            for row in rows {
 5608                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5609                for (row, indent) in indents {
 5610                    if indent.len == 0 {
 5611                        continue;
 5612                    }
 5613
 5614                    let text = match indent.kind {
 5615                        IndentKind::Space => " ".repeat(indent.len as usize),
 5616                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5617                    };
 5618                    let point = Point::new(row.0, 0);
 5619                    indent_edits.push((point..point, text));
 5620                }
 5621            }
 5622            editor.edit(indent_edits, cx);
 5623            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5624                format.detach_and_log_err(cx);
 5625            }
 5626        });
 5627    }
 5628
 5629    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5630        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5631            original_indent_columns: Vec::new(),
 5632        });
 5633        self.replace_selections(text, autoindent, window, cx, false);
 5634    }
 5635
 5636    /// Replaces the editor's selections with the provided `text`, applying the
 5637    /// given `autoindent_mode` (`None` will skip autoindentation).
 5638    ///
 5639    /// Early returns if the editor is in read-only mode, without applying any
 5640    /// edits.
 5641    fn replace_selections(
 5642        &mut self,
 5643        text: &str,
 5644        autoindent_mode: Option<AutoindentMode>,
 5645        window: &mut Window,
 5646        cx: &mut Context<Self>,
 5647        apply_linked_edits: bool,
 5648    ) {
 5649        if self.read_only(cx) {
 5650            return;
 5651        }
 5652
 5653        let text: Arc<str> = text.into();
 5654        self.transact(window, cx, |this, window, cx| {
 5655            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5656            let linked_edits = if apply_linked_edits {
 5657                this.linked_edits_for_selections(text.clone(), cx)
 5658            } else {
 5659                LinkedEdits::new()
 5660            };
 5661
 5662            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5663                let anchors = {
 5664                    let snapshot = buffer.read(cx);
 5665                    old_selections
 5666                        .iter()
 5667                        .map(|s| {
 5668                            let anchor = snapshot.anchor_after(s.head());
 5669                            s.map(|_| anchor)
 5670                        })
 5671                        .collect::<Vec<_>>()
 5672                };
 5673                buffer.edit(
 5674                    old_selections
 5675                        .iter()
 5676                        .map(|s| (s.start..s.end, text.clone())),
 5677                    autoindent_mode,
 5678                    cx,
 5679                );
 5680                anchors
 5681            });
 5682
 5683            linked_edits.apply(cx);
 5684
 5685            this.change_selections(Default::default(), window, cx, |s| {
 5686                s.select_anchors(selection_anchors);
 5687            });
 5688
 5689            if apply_linked_edits {
 5690                refresh_linked_ranges(this, window, cx);
 5691            }
 5692
 5693            cx.notify();
 5694        });
 5695    }
 5696
 5697    /// Collects linked edits for the current selections, pairing each linked
 5698    /// range with `text`.
 5699    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5700        let multibuffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5701        let mut linked_edits = LinkedEdits::new();
 5702        if !self.linked_edit_ranges.is_empty() {
 5703            for selection in self.selections.disjoint_anchors() {
 5704                let Some((_, range)) =
 5705                    multibuffer_snapshot.anchor_range_to_buffer_anchor_range(selection.range())
 5706                else {
 5707                    continue;
 5708                };
 5709                linked_edits.push(self, range, text.clone(), cx);
 5710            }
 5711        }
 5712        linked_edits
 5713    }
 5714
 5715    /// Deletes the content covered by the current selections and applies
 5716    /// linked edits.
 5717    pub fn delete_selections_with_linked_edits(
 5718        &mut self,
 5719        window: &mut Window,
 5720        cx: &mut Context<Self>,
 5721    ) {
 5722        self.replace_selections("", None, window, cx, true);
 5723    }
 5724
 5725    #[cfg(any(test, feature = "test-support"))]
 5726    pub fn set_linked_edit_ranges_for_testing(
 5727        &mut self,
 5728        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5729        cx: &mut Context<Self>,
 5730    ) -> Option<()> {
 5731        let Some((buffer, _)) = self
 5732            .buffer
 5733            .read(cx)
 5734            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5735        else {
 5736            return None;
 5737        };
 5738        let buffer = buffer.read(cx);
 5739        let buffer_id = buffer.remote_id();
 5740        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5741        for (base_range, linked_ranges_points) in ranges {
 5742            let base_anchor =
 5743                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5744            let linked_anchors = linked_ranges_points
 5745                .into_iter()
 5746                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5747                .collect();
 5748            linked_ranges.push((base_anchor, linked_anchors));
 5749        }
 5750        let mut map = HashMap::default();
 5751        map.insert(buffer_id, linked_ranges);
 5752        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5753        Some(())
 5754    }
 5755
 5756    fn trigger_completion_on_input(
 5757        &mut self,
 5758        text: &str,
 5759        trigger_in_words: bool,
 5760        window: &mut Window,
 5761        cx: &mut Context<Self>,
 5762    ) {
 5763        let completions_source = self
 5764            .context_menu
 5765            .borrow()
 5766            .as_ref()
 5767            .and_then(|menu| match menu {
 5768                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5769                CodeContextMenu::CodeActions(_) => None,
 5770            });
 5771
 5772        match completions_source {
 5773            Some(CompletionsMenuSource::Words { .. }) => {
 5774                self.open_or_update_completions_menu(
 5775                    Some(CompletionsMenuSource::Words {
 5776                        ignore_threshold: false,
 5777                    }),
 5778                    None,
 5779                    trigger_in_words,
 5780                    window,
 5781                    cx,
 5782                );
 5783            }
 5784            _ => self.open_or_update_completions_menu(
 5785                None,
 5786                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5787                true,
 5788                window,
 5789                cx,
 5790            ),
 5791        }
 5792    }
 5793
 5794    /// If any empty selections is touching the start of its innermost containing autoclose
 5795    /// region, expand it to select the brackets.
 5796    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5797        let selections = self
 5798            .selections
 5799            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5800        let buffer = self.buffer.read(cx).read(cx);
 5801        let new_selections = self
 5802            .selections_with_autoclose_regions(selections, &buffer)
 5803            .map(|(mut selection, region)| {
 5804                if !selection.is_empty() {
 5805                    return selection;
 5806                }
 5807
 5808                if let Some(region) = region {
 5809                    let mut range = region.range.to_offset(&buffer);
 5810                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5811                        range.start -= region.pair.start.len();
 5812                        if buffer.contains_str_at(range.start, &region.pair.start)
 5813                            && buffer.contains_str_at(range.end, &region.pair.end)
 5814                        {
 5815                            range.end += region.pair.end.len();
 5816                            selection.start = range.start;
 5817                            selection.end = range.end;
 5818
 5819                            return selection;
 5820                        }
 5821                    }
 5822                }
 5823
 5824                let always_treat_brackets_as_autoclosed = buffer
 5825                    .language_settings_at(selection.start, cx)
 5826                    .always_treat_brackets_as_autoclosed;
 5827
 5828                if !always_treat_brackets_as_autoclosed {
 5829                    return selection;
 5830                }
 5831
 5832                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5833                    for (pair, enabled) in scope.brackets() {
 5834                        if !enabled || !pair.close {
 5835                            continue;
 5836                        }
 5837
 5838                        if buffer.contains_str_at(selection.start, &pair.end) {
 5839                            let pair_start_len = pair.start.len();
 5840                            if buffer.contains_str_at(
 5841                                selection.start.saturating_sub_usize(pair_start_len),
 5842                                &pair.start,
 5843                            ) {
 5844                                selection.start -= pair_start_len;
 5845                                selection.end += pair.end.len();
 5846
 5847                                return selection;
 5848                            }
 5849                        }
 5850                    }
 5851                }
 5852
 5853                selection
 5854            })
 5855            .collect();
 5856
 5857        drop(buffer);
 5858        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5859            selections.select(new_selections)
 5860        });
 5861    }
 5862
 5863    /// Iterate the given selections, and for each one, find the smallest surrounding
 5864    /// autoclose region. This uses the ordering of the selections and the autoclose
 5865    /// regions to avoid repeated comparisons.
 5866    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5867        &'a self,
 5868        selections: impl IntoIterator<Item = Selection<D>>,
 5869        buffer: &'a MultiBufferSnapshot,
 5870    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5871        let mut i = 0;
 5872        let mut regions = self.autoclose_regions.as_slice();
 5873        selections.into_iter().map(move |selection| {
 5874            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5875
 5876            let mut enclosing = None;
 5877            while let Some(pair_state) = regions.get(i) {
 5878                if pair_state.range.end.to_offset(buffer) < range.start {
 5879                    regions = &regions[i + 1..];
 5880                    i = 0;
 5881                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5882                    break;
 5883                } else {
 5884                    if pair_state.selection_id == selection.id {
 5885                        enclosing = Some(pair_state);
 5886                    }
 5887                    i += 1;
 5888                }
 5889            }
 5890
 5891            (selection, enclosing)
 5892        })
 5893    }
 5894
 5895    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5896    fn invalidate_autoclose_regions(
 5897        &mut self,
 5898        mut selections: &[Selection<Anchor>],
 5899        buffer: &MultiBufferSnapshot,
 5900    ) {
 5901        self.autoclose_regions.retain(|state| {
 5902            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5903                return false;
 5904            }
 5905
 5906            let mut i = 0;
 5907            while let Some(selection) = selections.get(i) {
 5908                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5909                    selections = &selections[1..];
 5910                    continue;
 5911                }
 5912                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5913                    break;
 5914                }
 5915                if selection.id == state.selection_id {
 5916                    return true;
 5917                } else {
 5918                    i += 1;
 5919                }
 5920            }
 5921            false
 5922        });
 5923    }
 5924
 5925    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5926        let offset = position.to_offset(buffer);
 5927        let (word_range, kind) =
 5928            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5929        if offset > word_range.start && kind == Some(CharKind::Word) {
 5930            Some(
 5931                buffer
 5932                    .text_for_range(word_range.start..offset)
 5933                    .collect::<String>(),
 5934            )
 5935        } else {
 5936            None
 5937        }
 5938    }
 5939
 5940    pub fn is_lsp_relevant(&self, file: Option<&Arc<dyn language::File>>, cx: &App) -> bool {
 5941        let Some(project) = self.project() else {
 5942            return false;
 5943        };
 5944        let Some(buffer_file) = project::File::from_dyn(file) else {
 5945            return false;
 5946        };
 5947        let Some(entry_id) = buffer_file.project_entry_id() else {
 5948            return false;
 5949        };
 5950        let project = project.read(cx);
 5951        let Some(buffer_worktree) = project.worktree_for_id(buffer_file.worktree_id(cx), cx) else {
 5952            return false;
 5953        };
 5954        let Some(worktree_entry) = buffer_worktree.read(cx).entry_for_id(entry_id) else {
 5955            return false;
 5956        };
 5957        !worktree_entry.is_ignored
 5958    }
 5959
 5960    pub fn visible_buffers(&self, cx: &mut Context<Editor>) -> Vec<Entity<Buffer>> {
 5961        let display_snapshot = self.display_snapshot(cx);
 5962        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5963        let multi_buffer = self.buffer().read(cx);
 5964        display_snapshot
 5965            .buffer_snapshot()
 5966            .range_to_buffer_ranges(visible_range)
 5967            .into_iter()
 5968            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5969            .filter_map(|(buffer_snapshot, _, _)| multi_buffer.buffer(buffer_snapshot.remote_id()))
 5970            .collect()
 5971    }
 5972
 5973    pub fn visible_buffer_ranges(
 5974        &self,
 5975        cx: &mut Context<Editor>,
 5976    ) -> Vec<(
 5977        BufferSnapshot,
 5978        Range<BufferOffset>,
 5979        ExcerptRange<text::Anchor>,
 5980    )> {
 5981        let display_snapshot = self.display_snapshot(cx);
 5982        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5983        display_snapshot
 5984            .buffer_snapshot()
 5985            .range_to_buffer_ranges(visible_range)
 5986            .into_iter()
 5987            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5988            .collect()
 5989    }
 5990
 5991    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5992        TextLayoutDetails {
 5993            text_system: window.text_system().clone(),
 5994            editor_style: self.style.clone().unwrap(),
 5995            rem_size: window.rem_size(),
 5996            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 5997            visible_rows: self.visible_line_count(),
 5998            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5999        }
 6000    }
 6001
 6002    fn trigger_on_type_formatting(
 6003        &self,
 6004        input: String,
 6005        window: &mut Window,
 6006        cx: &mut Context<Self>,
 6007    ) -> Option<Task<Result<()>>> {
 6008        if input.chars().count() != 1 {
 6009            return None;
 6010        }
 6011
 6012        let project = self.project()?;
 6013        let position = self.selections.newest_anchor().head();
 6014        let (buffer, buffer_position) = self
 6015            .buffer
 6016            .read(cx)
 6017            .text_anchor_for_position(position, cx)?;
 6018
 6019        let settings = LanguageSettings::for_buffer_at(&buffer.read(cx), buffer_position, cx);
 6020        if !settings.use_on_type_format {
 6021            return None;
 6022        }
 6023
 6024        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 6025        // hence we do LSP request & edit on host side only — add formats to host's history.
 6026        let push_to_lsp_host_history = true;
 6027        // If this is not the host, append its history with new edits.
 6028        let push_to_client_history = project.read(cx).is_via_collab();
 6029
 6030        let on_type_formatting = project.update(cx, |project, cx| {
 6031            project.on_type_format(
 6032                buffer.clone(),
 6033                buffer_position,
 6034                input,
 6035                push_to_lsp_host_history,
 6036                cx,
 6037            )
 6038        });
 6039        Some(cx.spawn_in(window, async move |editor, cx| {
 6040            if let Some(transaction) = on_type_formatting.await? {
 6041                if push_to_client_history {
 6042                    buffer.update(cx, |buffer, _| {
 6043                        buffer.push_transaction(transaction, Instant::now());
 6044                        buffer.finalize_last_transaction();
 6045                    });
 6046                }
 6047                editor.update(cx, |editor, cx| {
 6048                    editor.refresh_document_highlights(cx);
 6049                })?;
 6050            }
 6051            Ok(())
 6052        }))
 6053    }
 6054
 6055    pub fn show_word_completions(
 6056        &mut self,
 6057        _: &ShowWordCompletions,
 6058        window: &mut Window,
 6059        cx: &mut Context<Self>,
 6060    ) {
 6061        self.open_or_update_completions_menu(
 6062            Some(CompletionsMenuSource::Words {
 6063                ignore_threshold: true,
 6064            }),
 6065            None,
 6066            false,
 6067            window,
 6068            cx,
 6069        );
 6070    }
 6071
 6072    pub fn show_completions(
 6073        &mut self,
 6074        _: &ShowCompletions,
 6075        window: &mut Window,
 6076        cx: &mut Context<Self>,
 6077    ) {
 6078        self.open_or_update_completions_menu(None, None, false, window, cx);
 6079    }
 6080
 6081    fn open_or_update_completions_menu(
 6082        &mut self,
 6083        requested_source: Option<CompletionsMenuSource>,
 6084        trigger: Option<String>,
 6085        trigger_in_words: bool,
 6086        window: &mut Window,
 6087        cx: &mut Context<Self>,
 6088    ) {
 6089        if self.pending_rename.is_some() {
 6090            return;
 6091        }
 6092
 6093        let completions_source = self
 6094            .context_menu
 6095            .borrow()
 6096            .as_ref()
 6097            .and_then(|menu| match menu {
 6098                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6099                CodeContextMenu::CodeActions(_) => None,
 6100            });
 6101
 6102        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6103
 6104        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6105        // inserted and selected. To handle that case, the start of the selection is used so that
 6106        // the menu starts with all choices.
 6107        let position = self
 6108            .selections
 6109            .newest_anchor()
 6110            .start
 6111            .bias_right(&multibuffer_snapshot);
 6112
 6113        if position.diff_base_anchor().is_some() {
 6114            return;
 6115        }
 6116        let multibuffer_position = multibuffer_snapshot.anchor_before(position);
 6117        let Some((buffer_position, _)) =
 6118            multibuffer_snapshot.anchor_to_buffer_anchor(multibuffer_position)
 6119        else {
 6120            return;
 6121        };
 6122        let Some(buffer) = self.buffer.read(cx).buffer(buffer_position.buffer_id) else {
 6123            return;
 6124        };
 6125        let buffer_snapshot = buffer.read(cx).snapshot();
 6126
 6127        let menu_is_open = matches!(
 6128            self.context_menu.borrow().as_ref(),
 6129            Some(CodeContextMenu::Completions(_))
 6130        );
 6131
 6132        let language = buffer_snapshot
 6133            .language_at(buffer_position)
 6134            .map(|language| language.name());
 6135        let language_settings = multibuffer_snapshot.language_settings_at(multibuffer_position, cx);
 6136        let completion_settings = language_settings.completions.clone();
 6137
 6138        let show_completions_on_input = self
 6139            .show_completions_on_input_override
 6140            .unwrap_or(language_settings.show_completions_on_input);
 6141        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6142            return;
 6143        }
 6144
 6145        let query: Option<Arc<String>> =
 6146            Self::completion_query(&multibuffer_snapshot, multibuffer_position)
 6147                .map(|query| query.into());
 6148
 6149        drop(multibuffer_snapshot);
 6150
 6151        // Hide the current completions menu when query is empty. Without this, cached
 6152        // completions from before the trigger char may be reused (#32774).
 6153        if query.is_none() && menu_is_open {
 6154            self.hide_context_menu(window, cx);
 6155        }
 6156
 6157        let mut ignore_word_threshold = false;
 6158        let provider = match requested_source {
 6159            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6160            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6161                ignore_word_threshold = ignore_threshold;
 6162                None
 6163            }
 6164            Some(CompletionsMenuSource::SnippetChoices)
 6165            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6166                log::error!("bug: SnippetChoices requested_source is not handled");
 6167                None
 6168            }
 6169        };
 6170
 6171        let sort_completions = provider
 6172            .as_ref()
 6173            .is_some_and(|provider| provider.sort_completions());
 6174
 6175        let filter_completions = provider
 6176            .as_ref()
 6177            .is_none_or(|provider| provider.filter_completions());
 6178
 6179        let was_snippets_only = matches!(
 6180            completions_source,
 6181            Some(CompletionsMenuSource::SnippetsOnly)
 6182        );
 6183
 6184        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6185            if filter_completions {
 6186                menu.filter(
 6187                    query.clone().unwrap_or_default(),
 6188                    buffer_position,
 6189                    &buffer,
 6190                    provider.clone(),
 6191                    window,
 6192                    cx,
 6193                );
 6194            }
 6195            // When `is_incomplete` is false, no need to re-query completions when the current query
 6196            // is a suffix of the initial query.
 6197            let was_complete = !menu.is_incomplete;
 6198            if was_complete && !was_snippets_only {
 6199                // If the new query is a suffix of the old query (typing more characters) and
 6200                // the previous result was complete, the existing completions can be filtered.
 6201                //
 6202                // Note that snippet completions are always complete.
 6203                let query_matches = match (&menu.initial_query, &query) {
 6204                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6205                    (None, _) => true,
 6206                    _ => false,
 6207                };
 6208                if query_matches {
 6209                    let position_matches = if menu.initial_position == position {
 6210                        true
 6211                    } else {
 6212                        let snapshot = self.buffer.read(cx).read(cx);
 6213                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6214                    };
 6215                    if position_matches {
 6216                        return;
 6217                    }
 6218                }
 6219            }
 6220        };
 6221
 6222        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6223            buffer_snapshot.surrounding_word(buffer_position, None)
 6224        {
 6225            let word_to_exclude = buffer_snapshot
 6226                .text_for_range(word_range.clone())
 6227                .collect::<String>();
 6228            (
 6229                buffer_snapshot.anchor_before(word_range.start)
 6230                    ..buffer_snapshot.anchor_after(buffer_position),
 6231                Some(word_to_exclude),
 6232            )
 6233        } else {
 6234            (buffer_position..buffer_position, None)
 6235        };
 6236
 6237        let show_completion_documentation = buffer_snapshot
 6238            .settings_at(buffer_position, cx)
 6239            .show_completion_documentation;
 6240
 6241        // The document can be large, so stay in reasonable bounds when searching for words,
 6242        // otherwise completion pop-up might be slow to appear.
 6243        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6244        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6245        let min_word_search = buffer_snapshot.clip_point(
 6246            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6247            Bias::Left,
 6248        );
 6249        let max_word_search = buffer_snapshot.clip_point(
 6250            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6251            Bias::Right,
 6252        );
 6253        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6254            ..buffer_snapshot.point_to_offset(max_word_search);
 6255
 6256        let skip_digits = query
 6257            .as_ref()
 6258            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6259
 6260        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6261            trigger.as_ref().is_none_or(|trigger| {
 6262                provider.is_completion_trigger(
 6263                    &buffer,
 6264                    buffer_position,
 6265                    trigger,
 6266                    trigger_in_words,
 6267                    cx,
 6268                )
 6269            })
 6270        });
 6271
 6272        let provider_responses = if let Some(provider) = &provider
 6273            && load_provider_completions
 6274        {
 6275            let trigger_character =
 6276                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6277            let completion_context = CompletionContext {
 6278                trigger_kind: match &trigger_character {
 6279                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6280                    None => CompletionTriggerKind::INVOKED,
 6281                },
 6282                trigger_character,
 6283            };
 6284
 6285            provider.completions(&buffer, buffer_position, completion_context, window, cx)
 6286        } else {
 6287            Task::ready(Ok(Vec::new()))
 6288        };
 6289
 6290        let load_word_completions = if !self.word_completions_enabled {
 6291            false
 6292        } else if requested_source
 6293            == Some(CompletionsMenuSource::Words {
 6294                ignore_threshold: true,
 6295            })
 6296        {
 6297            true
 6298        } else {
 6299            load_provider_completions
 6300                && completion_settings.words != WordsCompletionMode::Disabled
 6301                && (ignore_word_threshold || {
 6302                    let words_min_length = completion_settings.words_min_length;
 6303                    // check whether word has at least `words_min_length` characters
 6304                    let query_chars = query.iter().flat_map(|q| q.chars());
 6305                    query_chars.take(words_min_length).count() == words_min_length
 6306                })
 6307        };
 6308
 6309        let mut words = if load_word_completions {
 6310            cx.background_spawn({
 6311                let buffer_snapshot = buffer_snapshot.clone();
 6312                async move {
 6313                    buffer_snapshot.words_in_range(WordsQuery {
 6314                        fuzzy_contents: None,
 6315                        range: word_search_range,
 6316                        skip_digits,
 6317                    })
 6318                }
 6319            })
 6320        } else {
 6321            Task::ready(BTreeMap::default())
 6322        };
 6323
 6324        let snippets = if let Some(provider) = &provider
 6325            && provider.show_snippets()
 6326            && let Some(project) = self.project()
 6327        {
 6328            let char_classifier = buffer_snapshot
 6329                .char_classifier_at(buffer_position)
 6330                .scope_context(Some(CharScopeContext::Completion));
 6331            project.update(cx, |project, cx| {
 6332                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6333            })
 6334        } else {
 6335            Task::ready(Ok(CompletionResponse {
 6336                completions: Vec::new(),
 6337                display_options: Default::default(),
 6338                is_incomplete: false,
 6339            }))
 6340        };
 6341
 6342        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6343
 6344        let id = post_inc(&mut self.next_completion_id);
 6345        let task = cx.spawn_in(window, async move |editor, cx| {
 6346            let Ok(()) = editor.update(cx, |this, _| {
 6347                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6348            }) else {
 6349                return;
 6350            };
 6351
 6352            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6353            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6354            let mut completions = Vec::new();
 6355            let mut is_incomplete = false;
 6356            let mut display_options: Option<CompletionDisplayOptions> = None;
 6357            if let Some(provider_responses) = provider_responses.await.log_err()
 6358                && !provider_responses.is_empty()
 6359            {
 6360                for response in provider_responses {
 6361                    completions.extend(response.completions);
 6362                    is_incomplete = is_incomplete || response.is_incomplete;
 6363                    match display_options.as_mut() {
 6364                        None => {
 6365                            display_options = Some(response.display_options);
 6366                        }
 6367                        Some(options) => options.merge(&response.display_options),
 6368                    }
 6369                }
 6370                if completion_settings.words == WordsCompletionMode::Fallback {
 6371                    words = Task::ready(BTreeMap::default());
 6372                }
 6373            }
 6374            let display_options = display_options.unwrap_or_default();
 6375
 6376            let mut words = words.await;
 6377            if let Some(word_to_exclude) = &word_to_exclude {
 6378                words.remove(word_to_exclude);
 6379            }
 6380            for lsp_completion in &completions {
 6381                words.remove(&lsp_completion.new_text);
 6382            }
 6383            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6384                replace_range: word_replace_range.clone(),
 6385                new_text: word.clone(),
 6386                label: CodeLabel::plain(word, None),
 6387                match_start: None,
 6388                snippet_deduplication_key: None,
 6389                icon_path: None,
 6390                documentation: None,
 6391                source: CompletionSource::BufferWord {
 6392                    word_range,
 6393                    resolved: false,
 6394                },
 6395                insert_text_mode: Some(InsertTextMode::AS_IS),
 6396                confirm: None,
 6397            }));
 6398
 6399            completions.extend(
 6400                snippets
 6401                    .await
 6402                    .into_iter()
 6403                    .flat_map(|response| response.completions),
 6404            );
 6405
 6406            let menu = if completions.is_empty() {
 6407                None
 6408            } else {
 6409                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6410                    let languages = editor
 6411                        .workspace
 6412                        .as_ref()
 6413                        .and_then(|(workspace, _)| workspace.upgrade())
 6414                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6415                    let menu = CompletionsMenu::new(
 6416                        id,
 6417                        requested_source.unwrap_or(if load_provider_completions {
 6418                            CompletionsMenuSource::Normal
 6419                        } else {
 6420                            CompletionsMenuSource::SnippetsOnly
 6421                        }),
 6422                        sort_completions,
 6423                        show_completion_documentation,
 6424                        position,
 6425                        query.clone(),
 6426                        is_incomplete,
 6427                        buffer.clone(),
 6428                        completions.into(),
 6429                        editor
 6430                            .context_menu()
 6431                            .borrow_mut()
 6432                            .as_ref()
 6433                            .map(|menu| menu.primary_scroll_handle()),
 6434                        display_options,
 6435                        snippet_sort_order,
 6436                        languages,
 6437                        language,
 6438                        cx,
 6439                    );
 6440
 6441                    let query = if filter_completions { query } else { None };
 6442                    let matches_task = menu.do_async_filtering(
 6443                        query.unwrap_or_default(),
 6444                        buffer_position,
 6445                        &buffer,
 6446                        cx,
 6447                    );
 6448                    (menu, matches_task)
 6449                }) else {
 6450                    return;
 6451                };
 6452
 6453                let matches = matches_task.await;
 6454
 6455                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6456                    // Newer menu already set, so exit.
 6457                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6458                        editor.context_menu.borrow().as_ref()
 6459                        && prev_menu.id > id
 6460                    {
 6461                        return;
 6462                    };
 6463
 6464                    // Only valid to take prev_menu because either the new menu is immediately set
 6465                    // below, or the menu is hidden.
 6466                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6467                        editor.context_menu.borrow_mut().take()
 6468                    {
 6469                        let position_matches =
 6470                            if prev_menu.initial_position == menu.initial_position {
 6471                                true
 6472                            } else {
 6473                                let snapshot = editor.buffer.read(cx).read(cx);
 6474                                prev_menu.initial_position.to_offset(&snapshot)
 6475                                    == menu.initial_position.to_offset(&snapshot)
 6476                            };
 6477                        if position_matches {
 6478                            // Preserve markdown cache before `set_filter_results` because it will
 6479                            // try to populate the documentation cache.
 6480                            menu.preserve_markdown_cache(prev_menu);
 6481                        }
 6482                    };
 6483
 6484                    menu.set_filter_results(matches, provider, window, cx);
 6485                }) else {
 6486                    return;
 6487                };
 6488
 6489                menu.visible().then_some(menu)
 6490            };
 6491
 6492            editor
 6493                .update_in(cx, |editor, window, cx| {
 6494                    if editor.focus_handle.is_focused(window)
 6495                        && let Some(menu) = menu
 6496                    {
 6497                        *editor.context_menu.borrow_mut() =
 6498                            Some(CodeContextMenu::Completions(menu));
 6499
 6500                        crate::hover_popover::hide_hover(editor, cx);
 6501                        if editor.show_edit_predictions_in_menu() {
 6502                            editor.update_visible_edit_prediction(window, cx);
 6503                        } else {
 6504                            editor
 6505                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6506                        }
 6507
 6508                        cx.notify();
 6509                        return;
 6510                    }
 6511
 6512                    if editor.completion_tasks.len() <= 1 {
 6513                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6514                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6515                        // If it was already hidden and we don't show edit predictions in the menu,
 6516                        // we should also show the edit prediction when available.
 6517                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6518                            editor.update_visible_edit_prediction(window, cx);
 6519                        }
 6520                    }
 6521                })
 6522                .ok();
 6523        });
 6524
 6525        self.completion_tasks.push((id, task));
 6526    }
 6527
 6528    #[cfg(any(test, feature = "test-support"))]
 6529    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6530        let menu = self.context_menu.borrow();
 6531        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6532            let completions = menu.completions.borrow();
 6533            Some(completions.to_vec())
 6534        } else {
 6535            None
 6536        }
 6537    }
 6538
 6539    pub fn with_completions_menu_matching_id<R>(
 6540        &self,
 6541        id: CompletionId,
 6542        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6543    ) -> R {
 6544        let mut context_menu = self.context_menu.borrow_mut();
 6545        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6546            return f(None);
 6547        };
 6548        if completions_menu.id != id {
 6549            return f(None);
 6550        }
 6551        f(Some(completions_menu))
 6552    }
 6553
 6554    pub fn confirm_completion(
 6555        &mut self,
 6556        action: &ConfirmCompletion,
 6557        window: &mut Window,
 6558        cx: &mut Context<Self>,
 6559    ) -> Option<Task<Result<()>>> {
 6560        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6561        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6562    }
 6563
 6564    pub fn confirm_completion_insert(
 6565        &mut self,
 6566        _: &ConfirmCompletionInsert,
 6567        window: &mut Window,
 6568        cx: &mut Context<Self>,
 6569    ) -> Option<Task<Result<()>>> {
 6570        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6571        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6572    }
 6573
 6574    pub fn confirm_completion_replace(
 6575        &mut self,
 6576        _: &ConfirmCompletionReplace,
 6577        window: &mut Window,
 6578        cx: &mut Context<Self>,
 6579    ) -> Option<Task<Result<()>>> {
 6580        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6581        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6582    }
 6583
 6584    pub fn compose_completion(
 6585        &mut self,
 6586        action: &ComposeCompletion,
 6587        window: &mut Window,
 6588        cx: &mut Context<Self>,
 6589    ) -> Option<Task<Result<()>>> {
 6590        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6591        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6592    }
 6593
 6594    fn do_completion(
 6595        &mut self,
 6596        item_ix: Option<usize>,
 6597        intent: CompletionIntent,
 6598        window: &mut Window,
 6599        cx: &mut Context<Editor>,
 6600    ) -> Option<Task<Result<()>>> {
 6601        use language::ToOffset as _;
 6602
 6603        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6604        else {
 6605            return None;
 6606        };
 6607
 6608        let candidate_id = {
 6609            let entries = completions_menu.entries.borrow();
 6610            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6611            if self.show_edit_predictions_in_menu() {
 6612                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6613            }
 6614            mat.candidate_id
 6615        };
 6616
 6617        let completion = completions_menu
 6618            .completions
 6619            .borrow()
 6620            .get(candidate_id)?
 6621            .clone();
 6622        cx.stop_propagation();
 6623
 6624        let buffer_handle = completions_menu.buffer.clone();
 6625        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6626        let (initial_position, _) =
 6627            multibuffer_snapshot.anchor_to_buffer_anchor(completions_menu.initial_position)?;
 6628
 6629        let CompletionEdit {
 6630            new_text,
 6631            snippet,
 6632            replace_range,
 6633        } = process_completion_for_edit(&completion, intent, &buffer_handle, &initial_position, cx);
 6634
 6635        let buffer = buffer_handle.read(cx).snapshot();
 6636        let newest_selection = self.selections.newest_anchor();
 6637
 6638        let Some(replace_range_multibuffer) =
 6639            multibuffer_snapshot.buffer_anchor_range_to_anchor_range(replace_range.clone())
 6640        else {
 6641            return None;
 6642        };
 6643
 6644        let Some((buffer_snapshot, newest_range_buffer)) =
 6645            multibuffer_snapshot.anchor_range_to_buffer_anchor_range(newest_selection.range())
 6646        else {
 6647            return None;
 6648        };
 6649
 6650        let old_text = buffer
 6651            .text_for_range(replace_range.clone())
 6652            .collect::<String>();
 6653        let lookbehind = newest_range_buffer
 6654            .start
 6655            .to_offset(buffer_snapshot)
 6656            .saturating_sub(replace_range.start.to_offset(&buffer_snapshot));
 6657        let lookahead = replace_range
 6658            .end
 6659            .to_offset(&buffer_snapshot)
 6660            .saturating_sub(newest_range_buffer.end.to_offset(&buffer));
 6661        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6662        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6663
 6664        let selections = self
 6665            .selections
 6666            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6667        let mut ranges = Vec::new();
 6668        let mut all_commit_ranges = Vec::new();
 6669        let mut linked_edits = LinkedEdits::new();
 6670
 6671        let text: Arc<str> = new_text.clone().into();
 6672        for selection in &selections {
 6673            let range = if selection.id == newest_selection.id {
 6674                replace_range_multibuffer.clone()
 6675            } else {
 6676                let mut range = selection.range();
 6677
 6678                // if prefix is present, don't duplicate it
 6679                if multibuffer_snapshot
 6680                    .contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix)
 6681                {
 6682                    range.start = range.start.saturating_sub_usize(lookbehind);
 6683
 6684                    // if suffix is also present, mimic the newest cursor and replace it
 6685                    if selection.id != newest_selection.id
 6686                        && multibuffer_snapshot.contains_str_at(range.end, suffix)
 6687                    {
 6688                        range.end += lookahead;
 6689                    }
 6690                }
 6691                range.to_anchors(&multibuffer_snapshot)
 6692            };
 6693
 6694            ranges.push(range.clone());
 6695
 6696            let start_anchor = multibuffer_snapshot.anchor_before(range.start);
 6697            let end_anchor = multibuffer_snapshot.anchor_after(range.end);
 6698
 6699            if let Some((buffer_snapshot_2, anchor_range)) =
 6700                multibuffer_snapshot.anchor_range_to_buffer_anchor_range(start_anchor..end_anchor)
 6701                && buffer_snapshot_2.remote_id() == buffer_snapshot.remote_id()
 6702            {
 6703                all_commit_ranges.push(anchor_range.clone());
 6704                if !self.linked_edit_ranges.is_empty() {
 6705                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 6706                }
 6707            }
 6708        }
 6709
 6710        let common_prefix_len = old_text
 6711            .chars()
 6712            .zip(new_text.chars())
 6713            .take_while(|(a, b)| a == b)
 6714            .map(|(a, _)| a.len_utf8())
 6715            .sum::<usize>();
 6716
 6717        cx.emit(EditorEvent::InputHandled {
 6718            utf16_range_to_replace: None,
 6719            text: new_text[common_prefix_len..].into(),
 6720        });
 6721
 6722        let tx_id = self.transact(window, cx, |editor, window, cx| {
 6723            if let Some(mut snippet) = snippet {
 6724                snippet.text = new_text.to_string();
 6725                let offset_ranges = ranges
 6726                    .iter()
 6727                    .map(|range| range.to_offset(&multibuffer_snapshot))
 6728                    .collect::<Vec<_>>();
 6729                editor
 6730                    .insert_snippet(&offset_ranges, snippet, window, cx)
 6731                    .log_err();
 6732            } else {
 6733                editor.buffer.update(cx, |multi_buffer, cx| {
 6734                    let auto_indent = match completion.insert_text_mode {
 6735                        Some(InsertTextMode::AS_IS) => None,
 6736                        _ => editor.autoindent_mode.clone(),
 6737                    };
 6738                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6739                    multi_buffer.edit(edits, auto_indent, cx);
 6740                });
 6741            }
 6742            linked_edits.apply(cx);
 6743            editor.refresh_edit_prediction(true, false, window, cx);
 6744        });
 6745        self.invalidate_autoclose_regions(
 6746            &self.selections.disjoint_anchors_arc(),
 6747            &multibuffer_snapshot,
 6748        );
 6749
 6750        let show_new_completions_on_confirm = completion
 6751            .confirm
 6752            .as_ref()
 6753            .is_some_and(|confirm| confirm(intent, window, cx));
 6754        if show_new_completions_on_confirm {
 6755            self.open_or_update_completions_menu(None, None, false, window, cx);
 6756        }
 6757
 6758        let provider = self.completion_provider.as_ref()?;
 6759
 6760        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6761        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6762            let CompletionSource::Lsp {
 6763                lsp_completion,
 6764                server_id,
 6765                ..
 6766            } = &completion.source
 6767            else {
 6768                return None;
 6769            };
 6770            let lsp_command = lsp_completion.command.as_ref()?;
 6771            let available_commands = lsp_store
 6772                .read(cx)
 6773                .lsp_server_capabilities
 6774                .get(server_id)
 6775                .and_then(|server_capabilities| {
 6776                    server_capabilities
 6777                        .execute_command_provider
 6778                        .as_ref()
 6779                        .map(|options| options.commands.as_slice())
 6780                })?;
 6781            if available_commands.contains(&lsp_command.command) {
 6782                Some(CodeAction {
 6783                    server_id: *server_id,
 6784                    range: language::Anchor::min_min_range_for_buffer(buffer.remote_id()),
 6785                    lsp_action: LspAction::Command(lsp_command.clone()),
 6786                    resolved: false,
 6787                })
 6788            } else {
 6789                None
 6790            }
 6791        });
 6792
 6793        drop(completion);
 6794        let apply_edits = provider.apply_additional_edits_for_completion(
 6795            buffer_handle.clone(),
 6796            completions_menu.completions.clone(),
 6797            candidate_id,
 6798            true,
 6799            all_commit_ranges,
 6800            cx,
 6801        );
 6802
 6803        let editor_settings = EditorSettings::get_global(cx);
 6804        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6805            // After the code completion is finished, users often want to know what signatures are needed.
 6806            // so we should automatically call signature_help
 6807            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6808        }
 6809
 6810        Some(cx.spawn_in(window, async move |editor, cx| {
 6811            let additional_edits_tx = apply_edits.await?;
 6812
 6813            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6814                let title = command.lsp_action.title().to_owned();
 6815                let project_transaction = lsp_store
 6816                    .update(cx, |lsp_store, cx| {
 6817                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6818                    })
 6819                    .await
 6820                    .context("applying post-completion command")?;
 6821                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6822                    Self::open_project_transaction(
 6823                        &editor,
 6824                        workspace.downgrade(),
 6825                        project_transaction,
 6826                        title,
 6827                        cx,
 6828                    )
 6829                    .await?;
 6830                }
 6831            }
 6832
 6833            if let Some(tx_id) = tx_id
 6834                && let Some(additional_edits_tx) = additional_edits_tx
 6835            {
 6836                editor
 6837                    .update(cx, |editor, cx| {
 6838                        editor.buffer.update(cx, |buffer, cx| {
 6839                            buffer.merge_transactions(additional_edits_tx.id, tx_id, cx)
 6840                        });
 6841                    })
 6842                    .context("merge transactions")?;
 6843            }
 6844
 6845            Ok(())
 6846        }))
 6847    }
 6848
 6849    pub fn toggle_code_actions(
 6850        &mut self,
 6851        action: &ToggleCodeActions,
 6852        window: &mut Window,
 6853        cx: &mut Context<Self>,
 6854    ) {
 6855        let quick_launch = action.quick_launch;
 6856        let mut context_menu = self.context_menu.borrow_mut();
 6857        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6858            if code_actions.deployed_from == action.deployed_from {
 6859                // Toggle if we're selecting the same one
 6860                *context_menu = None;
 6861                cx.notify();
 6862                return;
 6863            } else {
 6864                // Otherwise, clear it and start a new one
 6865                *context_menu = None;
 6866                cx.notify();
 6867            }
 6868        }
 6869        drop(context_menu);
 6870        let snapshot = self.snapshot(window, cx);
 6871        let deployed_from = action.deployed_from.clone();
 6872        let action = action.clone();
 6873        self.completion_tasks.clear();
 6874        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6875
 6876        let multibuffer_point = match &action.deployed_from {
 6877            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6878                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6879            }
 6880            _ => self
 6881                .selections
 6882                .newest::<Point>(&snapshot.display_snapshot)
 6883                .head(),
 6884        };
 6885        let Some((buffer, buffer_row)) = snapshot
 6886            .buffer_snapshot()
 6887            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6888            .and_then(|(buffer_snapshot, range)| {
 6889                self.buffer()
 6890                    .read(cx)
 6891                    .buffer(buffer_snapshot.remote_id())
 6892                    .map(|buffer| (buffer, range.start.row))
 6893            })
 6894        else {
 6895            return;
 6896        };
 6897        let buffer_id = buffer.read(cx).remote_id();
 6898        let tasks = self
 6899            .runnables
 6900            .runnables((buffer_id, buffer_row))
 6901            .map(|t| Arc::new(t.to_owned()));
 6902
 6903        if !self.focus_handle.is_focused(window) {
 6904            return;
 6905        }
 6906        let project = self.project.clone();
 6907
 6908        let code_actions_task = match deployed_from {
 6909            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6910            _ => self.code_actions(buffer_row, window, cx),
 6911        };
 6912
 6913        let runnable_task = match deployed_from {
 6914            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6915            _ => {
 6916                let mut task_context_task = Task::ready(None);
 6917                if let Some(tasks) = &tasks
 6918                    && let Some(project) = project
 6919                {
 6920                    task_context_task =
 6921                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6922                }
 6923
 6924                cx.spawn_in(window, {
 6925                    let buffer = buffer.clone();
 6926                    async move |editor, cx| {
 6927                        let task_context = task_context_task.await;
 6928
 6929                        let resolved_tasks =
 6930                            tasks
 6931                                .zip(task_context.clone())
 6932                                .map(|(tasks, task_context)| ResolvedTasks {
 6933                                    templates: tasks.resolve(&task_context).collect(),
 6934                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6935                                        multibuffer_point.row,
 6936                                        tasks.column,
 6937                                    )),
 6938                                });
 6939                        let debug_scenarios = editor
 6940                            .update(cx, |editor, cx| {
 6941                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6942                            })?
 6943                            .await;
 6944                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6945                    }
 6946                })
 6947            }
 6948        };
 6949
 6950        cx.spawn_in(window, async move |editor, cx| {
 6951            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6952            let code_actions = code_actions_task.await;
 6953            let spawn_straight_away = quick_launch
 6954                && resolved_tasks
 6955                    .as_ref()
 6956                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6957                && code_actions
 6958                    .as_ref()
 6959                    .is_none_or(|actions| actions.is_empty())
 6960                && debug_scenarios.is_empty();
 6961
 6962            editor.update_in(cx, |editor, window, cx| {
 6963                crate::hover_popover::hide_hover(editor, cx);
 6964                let actions = CodeActionContents::new(
 6965                    resolved_tasks,
 6966                    code_actions,
 6967                    debug_scenarios,
 6968                    task_context.unwrap_or_default(),
 6969                );
 6970
 6971                // Don't show the menu if there are no actions available
 6972                if actions.is_empty() {
 6973                    cx.notify();
 6974                    return Task::ready(Ok(()));
 6975                }
 6976
 6977                *editor.context_menu.borrow_mut() =
 6978                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6979                        buffer,
 6980                        actions,
 6981                        selected_item: Default::default(),
 6982                        scroll_handle: UniformListScrollHandle::default(),
 6983                        deployed_from,
 6984                    }));
 6985                cx.notify();
 6986                if spawn_straight_away
 6987                    && let Some(task) = editor.confirm_code_action(
 6988                        &ConfirmCodeAction { item_ix: Some(0) },
 6989                        window,
 6990                        cx,
 6991                    )
 6992                {
 6993                    return task;
 6994                }
 6995
 6996                Task::ready(Ok(()))
 6997            })
 6998        })
 6999        .detach_and_log_err(cx);
 7000    }
 7001
 7002    fn debug_scenarios(
 7003        &mut self,
 7004        resolved_tasks: &Option<ResolvedTasks>,
 7005        buffer: &Entity<Buffer>,
 7006        cx: &mut App,
 7007    ) -> Task<Vec<task::DebugScenario>> {
 7008        maybe!({
 7009            let project = self.project()?;
 7010            let dap_store = project.read(cx).dap_store();
 7011            let mut scenarios = vec![];
 7012            let resolved_tasks = resolved_tasks.as_ref()?;
 7013            let buffer = buffer.read(cx);
 7014            let language = buffer.language()?;
 7015            let debug_adapter = LanguageSettings::for_buffer(&buffer, cx)
 7016                .debuggers
 7017                .first()
 7018                .map(SharedString::from)
 7019                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 7020
 7021            dap_store.update(cx, |dap_store, cx| {
 7022                for (_, task) in &resolved_tasks.templates {
 7023                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 7024                        task.original_task().clone(),
 7025                        debug_adapter.clone().into(),
 7026                        task.display_label().to_owned().into(),
 7027                        cx,
 7028                    );
 7029                    scenarios.push(maybe_scenario);
 7030                }
 7031            });
 7032            Some(cx.background_spawn(async move {
 7033                futures::future::join_all(scenarios)
 7034                    .await
 7035                    .into_iter()
 7036                    .flatten()
 7037                    .collect::<Vec<_>>()
 7038            }))
 7039        })
 7040        .unwrap_or_else(|| Task::ready(vec![]))
 7041    }
 7042
 7043    fn code_actions(
 7044        &mut self,
 7045        buffer_row: u32,
 7046        window: &mut Window,
 7047        cx: &mut Context<Self>,
 7048    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 7049        let mut task = self.code_actions_task.take();
 7050        cx.spawn_in(window, async move |editor, cx| {
 7051            while let Some(prev_task) = task {
 7052                prev_task.await.log_err();
 7053                task = editor
 7054                    .update(cx, |this, _| this.code_actions_task.take())
 7055                    .ok()?;
 7056            }
 7057
 7058            editor
 7059                .update(cx, |editor, cx| {
 7060                    editor
 7061                        .available_code_actions
 7062                        .clone()
 7063                        .and_then(|(location, code_actions)| {
 7064                            let snapshot = location.buffer.read(cx).snapshot();
 7065                            let point_range = location.range.to_point(&snapshot);
 7066                            let point_range = point_range.start.row..=point_range.end.row;
 7067                            if point_range.contains(&buffer_row) {
 7068                                Some(code_actions)
 7069                            } else {
 7070                                None
 7071                            }
 7072                        })
 7073                })
 7074                .ok()
 7075                .flatten()
 7076        })
 7077    }
 7078
 7079    pub fn confirm_code_action(
 7080        &mut self,
 7081        action: &ConfirmCodeAction,
 7082        window: &mut Window,
 7083        cx: &mut Context<Self>,
 7084    ) -> Option<Task<Result<()>>> {
 7085        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7086
 7087        let actions_menu =
 7088            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7089                menu
 7090            } else {
 7091                return None;
 7092            };
 7093
 7094        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7095        let action = actions_menu.actions.get(action_ix)?;
 7096        let title = action.label();
 7097        let buffer = actions_menu.buffer;
 7098        let workspace = self.workspace()?;
 7099
 7100        match action {
 7101            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7102                workspace.update(cx, |workspace, cx| {
 7103                    workspace.schedule_resolved_task(
 7104                        task_source_kind,
 7105                        resolved_task,
 7106                        false,
 7107                        window,
 7108                        cx,
 7109                    );
 7110
 7111                    Some(Task::ready(Ok(())))
 7112                })
 7113            }
 7114            CodeActionsItem::CodeAction { action, provider } => {
 7115                let apply_code_action =
 7116                    provider.apply_code_action(buffer, action, true, window, cx);
 7117                let workspace = workspace.downgrade();
 7118                Some(cx.spawn_in(window, async move |editor, cx| {
 7119                    let project_transaction = apply_code_action.await?;
 7120                    Self::open_project_transaction(
 7121                        &editor,
 7122                        workspace,
 7123                        project_transaction,
 7124                        title,
 7125                        cx,
 7126                    )
 7127                    .await
 7128                }))
 7129            }
 7130            CodeActionsItem::DebugScenario(scenario) => {
 7131                let context = actions_menu.actions.context.into();
 7132
 7133                workspace.update(cx, |workspace, cx| {
 7134                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7135                    workspace.start_debug_session(
 7136                        scenario,
 7137                        context,
 7138                        Some(buffer),
 7139                        None,
 7140                        window,
 7141                        cx,
 7142                    );
 7143                });
 7144                Some(Task::ready(Ok(())))
 7145            }
 7146        }
 7147    }
 7148
 7149    fn open_transaction_for_hidden_buffers(
 7150        workspace: Entity<Workspace>,
 7151        transaction: ProjectTransaction,
 7152        title: String,
 7153        window: &mut Window,
 7154        cx: &mut Context<Self>,
 7155    ) {
 7156        if transaction.0.is_empty() {
 7157            return;
 7158        }
 7159
 7160        let edited_buffers_already_open = {
 7161            let other_editors: Vec<Entity<Editor>> = workspace
 7162                .read(cx)
 7163                .panes()
 7164                .iter()
 7165                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7166                .filter(|editor| editor.entity_id() != cx.entity_id())
 7167                .collect();
 7168
 7169            transaction.0.keys().all(|buffer| {
 7170                other_editors.iter().any(|editor| {
 7171                    let multi_buffer = editor.read(cx).buffer();
 7172                    multi_buffer.read(cx).is_singleton()
 7173                        && multi_buffer
 7174                            .read(cx)
 7175                            .as_singleton()
 7176                            .map_or(false, |singleton| {
 7177                                singleton.entity_id() == buffer.entity_id()
 7178                            })
 7179                })
 7180            })
 7181        };
 7182        if !edited_buffers_already_open {
 7183            let workspace = workspace.downgrade();
 7184            cx.defer_in(window, move |_, window, cx| {
 7185                cx.spawn_in(window, async move |editor, cx| {
 7186                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7187                        .await
 7188                        .ok()
 7189                })
 7190                .detach();
 7191            });
 7192        }
 7193    }
 7194
 7195    pub async fn open_project_transaction(
 7196        editor: &WeakEntity<Editor>,
 7197        workspace: WeakEntity<Workspace>,
 7198        transaction: ProjectTransaction,
 7199        title: String,
 7200        cx: &mut AsyncWindowContext,
 7201    ) -> Result<()> {
 7202        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7203        cx.update(|_, cx| {
 7204            entries.sort_unstable_by_key(|(buffer, _)| {
 7205                buffer.read(cx).file().map(|f| f.path().clone())
 7206            });
 7207        })?;
 7208        if entries.is_empty() {
 7209            return Ok(());
 7210        }
 7211
 7212        // If the project transaction's edits are all contained within this editor, then
 7213        // avoid opening a new editor to display them.
 7214
 7215        if let [(buffer, transaction)] = &*entries {
 7216            let cursor_excerpt = editor.update(cx, |editor, cx| {
 7217                let snapshot = editor.buffer().read(cx).snapshot(cx);
 7218                let head = editor.selections.newest_anchor().head();
 7219                let (buffer_snapshot, excerpt_range) = snapshot.excerpt_containing(head..head)?;
 7220                if buffer_snapshot.remote_id() != buffer.read(cx).remote_id() {
 7221                    return None;
 7222                }
 7223                Some(excerpt_range)
 7224            })?;
 7225
 7226            if let Some(excerpt_range) = cursor_excerpt {
 7227                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7228                    let excerpt_range = excerpt_range.context.to_offset(buffer);
 7229                    buffer
 7230                        .edited_ranges_for_transaction::<usize>(transaction)
 7231                        .all(|range| {
 7232                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7233                        })
 7234                });
 7235
 7236                if all_edits_within_excerpt {
 7237                    return Ok(());
 7238                }
 7239            }
 7240        }
 7241
 7242        let mut ranges_to_highlight = Vec::new();
 7243        let excerpt_buffer = cx.new(|cx| {
 7244            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7245            for (buffer_handle, transaction) in &entries {
 7246                let edited_ranges = buffer_handle
 7247                    .read(cx)
 7248                    .edited_ranges_for_transaction::<Point>(transaction)
 7249                    .collect::<Vec<_>>();
 7250                multibuffer.set_excerpts_for_path(
 7251                    PathKey::for_buffer(buffer_handle, cx),
 7252                    buffer_handle.clone(),
 7253                    edited_ranges.clone(),
 7254                    multibuffer_context_lines(cx),
 7255                    cx,
 7256                );
 7257                let snapshot = multibuffer.snapshot(cx);
 7258                let buffer_snapshot = buffer_handle.read(cx).snapshot();
 7259                ranges_to_highlight.extend(edited_ranges.into_iter().filter_map(|range| {
 7260                    let text_range = buffer_snapshot.anchor_range_inside(range);
 7261                    let start = snapshot.anchor_in_buffer(text_range.start)?;
 7262                    let end = snapshot.anchor_in_buffer(text_range.end)?;
 7263                    Some(start..end)
 7264                }));
 7265            }
 7266            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7267            multibuffer
 7268        });
 7269
 7270        workspace.update_in(cx, |workspace, window, cx| {
 7271            let project = workspace.project().clone();
 7272            let editor =
 7273                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7274            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7275            editor.update(cx, |editor, cx| {
 7276                editor.highlight_background(
 7277                    HighlightKey::Editor,
 7278                    &ranges_to_highlight,
 7279                    |_, theme| theme.colors().editor_highlighted_line_background,
 7280                    cx,
 7281                );
 7282            });
 7283        })?;
 7284
 7285        Ok(())
 7286    }
 7287
 7288    pub fn clear_code_action_providers(&mut self) {
 7289        self.code_action_providers.clear();
 7290        self.available_code_actions.take();
 7291    }
 7292
 7293    pub fn add_code_action_provider(
 7294        &mut self,
 7295        provider: Rc<dyn CodeActionProvider>,
 7296        window: &mut Window,
 7297        cx: &mut Context<Self>,
 7298    ) {
 7299        if self
 7300            .code_action_providers
 7301            .iter()
 7302            .any(|existing_provider| existing_provider.id() == provider.id())
 7303        {
 7304            return;
 7305        }
 7306
 7307        self.code_action_providers.push(provider);
 7308        self.refresh_code_actions(window, cx);
 7309    }
 7310
 7311    pub fn remove_code_action_provider(
 7312        &mut self,
 7313        id: Arc<str>,
 7314        window: &mut Window,
 7315        cx: &mut Context<Self>,
 7316    ) {
 7317        self.code_action_providers
 7318            .retain(|provider| provider.id() != id);
 7319        self.refresh_code_actions(window, cx);
 7320    }
 7321
 7322    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7323        !self.code_action_providers.is_empty()
 7324            && EditorSettings::get_global(cx).toolbar.code_actions
 7325    }
 7326
 7327    pub fn has_available_code_actions(&self) -> bool {
 7328        self.available_code_actions
 7329            .as_ref()
 7330            .is_some_and(|(_, actions)| !actions.is_empty())
 7331    }
 7332
 7333    fn render_inline_code_actions(
 7334        &self,
 7335        icon_size: ui::IconSize,
 7336        display_row: DisplayRow,
 7337        is_active: bool,
 7338        cx: &mut Context<Self>,
 7339    ) -> AnyElement {
 7340        let show_tooltip = !self.context_menu_visible();
 7341        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7342            .icon_size(icon_size)
 7343            .shape(ui::IconButtonShape::Square)
 7344            .icon_color(ui::Color::Hidden)
 7345            .toggle_state(is_active)
 7346            .when(show_tooltip, |this| {
 7347                this.tooltip({
 7348                    let focus_handle = self.focus_handle.clone();
 7349                    move |_window, cx| {
 7350                        Tooltip::for_action_in(
 7351                            "Toggle Code Actions",
 7352                            &ToggleCodeActions {
 7353                                deployed_from: None,
 7354                                quick_launch: false,
 7355                            },
 7356                            &focus_handle,
 7357                            cx,
 7358                        )
 7359                    }
 7360                })
 7361            })
 7362            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7363                window.focus(&editor.focus_handle(cx), cx);
 7364                editor.toggle_code_actions(
 7365                    &crate::actions::ToggleCodeActions {
 7366                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7367                            display_row,
 7368                        )),
 7369                        quick_launch: false,
 7370                    },
 7371                    window,
 7372                    cx,
 7373                );
 7374            }))
 7375            .into_any_element()
 7376    }
 7377
 7378    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7379        &self.context_menu
 7380    }
 7381
 7382    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7383        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7384            cx.background_executor()
 7385                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7386                .await;
 7387
 7388            let (start_buffer, start, _, end, _newest_selection) = this
 7389                .update(cx, |this, cx| {
 7390                    let newest_selection = this.selections.newest_anchor().clone();
 7391                    if newest_selection.head().diff_base_anchor().is_some() {
 7392                        return None;
 7393                    }
 7394                    let display_snapshot = this.display_snapshot(cx);
 7395                    let newest_selection_adjusted =
 7396                        this.selections.newest_adjusted(&display_snapshot);
 7397                    let buffer = this.buffer.read(cx);
 7398
 7399                    let (start_buffer, start) =
 7400                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7401                    let (end_buffer, end) =
 7402                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7403
 7404                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7405                })?
 7406                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7407                .context(
 7408                    "Expected selection to lie in a single buffer when refreshing code actions",
 7409                )?;
 7410            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7411                let providers = this.code_action_providers.clone();
 7412                let tasks = this
 7413                    .code_action_providers
 7414                    .iter()
 7415                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7416                    .collect::<Vec<_>>();
 7417                (providers, tasks)
 7418            })?;
 7419
 7420            let mut actions = Vec::new();
 7421            for (provider, provider_actions) in
 7422                providers.into_iter().zip(future::join_all(tasks).await)
 7423            {
 7424                if let Some(provider_actions) = provider_actions.log_err() {
 7425                    actions.extend(provider_actions.into_iter().map(|action| {
 7426                        AvailableCodeAction {
 7427                            action,
 7428                            provider: provider.clone(),
 7429                        }
 7430                    }));
 7431                }
 7432            }
 7433
 7434            this.update(cx, |this, cx| {
 7435                this.available_code_actions = if actions.is_empty() {
 7436                    None
 7437                } else {
 7438                    Some((
 7439                        Location {
 7440                            buffer: start_buffer,
 7441                            range: start..end,
 7442                        },
 7443                        actions.into(),
 7444                    ))
 7445                };
 7446                cx.notify();
 7447            })
 7448        }));
 7449    }
 7450
 7451    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7452        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7453            self.show_git_blame_inline = false;
 7454
 7455            self.show_git_blame_inline_delay_task =
 7456                Some(cx.spawn_in(window, async move |this, cx| {
 7457                    cx.background_executor().timer(delay).await;
 7458
 7459                    this.update(cx, |this, cx| {
 7460                        this.show_git_blame_inline = true;
 7461                        cx.notify();
 7462                    })
 7463                    .log_err();
 7464                }));
 7465        }
 7466    }
 7467
 7468    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7469        let snapshot = self.snapshot(window, cx);
 7470        let cursor = self
 7471            .selections
 7472            .newest::<Point>(&snapshot.display_snapshot)
 7473            .head();
 7474        let Some((buffer, point)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor) else {
 7475            return;
 7476        };
 7477
 7478        if self.blame.is_none() {
 7479            self.start_git_blame(true, window, cx);
 7480        }
 7481        let Some(blame) = self.blame.as_ref() else {
 7482            return;
 7483        };
 7484
 7485        let row_info = RowInfo {
 7486            buffer_id: Some(buffer.remote_id()),
 7487            buffer_row: Some(point.row),
 7488            ..Default::default()
 7489        };
 7490        let Some((buffer, blame_entry)) = blame
 7491            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7492            .flatten()
 7493        else {
 7494            return;
 7495        };
 7496
 7497        let anchor = self.selections.newest_anchor().head();
 7498        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7499        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7500            self.show_blame_popover(
 7501                buffer,
 7502                &blame_entry,
 7503                position + last_bounds.origin,
 7504                true,
 7505                cx,
 7506            );
 7507        };
 7508    }
 7509
 7510    fn show_blame_popover(
 7511        &mut self,
 7512        buffer: BufferId,
 7513        blame_entry: &BlameEntry,
 7514        position: gpui::Point<Pixels>,
 7515        ignore_timeout: bool,
 7516        cx: &mut Context<Self>,
 7517    ) {
 7518        if let Some(state) = &mut self.inline_blame_popover {
 7519            state.hide_task.take();
 7520        } else {
 7521            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7522            let blame_entry = blame_entry.clone();
 7523            let show_task = cx.spawn(async move |editor, cx| {
 7524                if !ignore_timeout {
 7525                    cx.background_executor()
 7526                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7527                        .await;
 7528                }
 7529                editor
 7530                    .update(cx, |editor, cx| {
 7531                        editor.inline_blame_popover_show_task.take();
 7532                        let Some(blame) = editor.blame.as_ref() else {
 7533                            return;
 7534                        };
 7535                        let blame = blame.read(cx);
 7536                        let details = blame.details_for_entry(buffer, &blame_entry);
 7537                        let markdown = cx.new(|cx| {
 7538                            Markdown::new(
 7539                                details
 7540                                    .as_ref()
 7541                                    .map(|message| message.message.clone())
 7542                                    .unwrap_or_default(),
 7543                                None,
 7544                                None,
 7545                                cx,
 7546                            )
 7547                        });
 7548                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7549                            position,
 7550                            hide_task: None,
 7551                            popover_bounds: None,
 7552                            popover_state: InlineBlamePopoverState {
 7553                                scroll_handle: ScrollHandle::new(),
 7554                                commit_message: details,
 7555                                markdown,
 7556                            },
 7557                            keyboard_grace: ignore_timeout,
 7558                        });
 7559                        cx.notify();
 7560                    })
 7561                    .ok();
 7562            });
 7563            self.inline_blame_popover_show_task = Some(show_task);
 7564        }
 7565    }
 7566
 7567    pub fn has_mouse_context_menu(&self) -> bool {
 7568        self.mouse_context_menu.is_some()
 7569    }
 7570
 7571    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7572        self.inline_blame_popover_show_task.take();
 7573        if let Some(state) = &mut self.inline_blame_popover {
 7574            let hide_task = cx.spawn(async move |editor, cx| {
 7575                if !ignore_timeout {
 7576                    cx.background_executor()
 7577                        .timer(std::time::Duration::from_millis(100))
 7578                        .await;
 7579                }
 7580                editor
 7581                    .update(cx, |editor, cx| {
 7582                        editor.inline_blame_popover.take();
 7583                        cx.notify();
 7584                    })
 7585                    .ok();
 7586            });
 7587            state.hide_task = Some(hide_task);
 7588            true
 7589        } else {
 7590            false
 7591        }
 7592    }
 7593
 7594    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7595        if self.pending_rename.is_some() {
 7596            return None;
 7597        }
 7598
 7599        let provider = self.semantics_provider.clone()?;
 7600        let buffer = self.buffer.read(cx);
 7601        let newest_selection = self.selections.newest_anchor().clone();
 7602        let cursor_position = newest_selection.head();
 7603        let (cursor_buffer, cursor_buffer_position) =
 7604            buffer.text_anchor_for_position(cursor_position, cx)?;
 7605        let (tail_buffer, tail_buffer_position) =
 7606            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7607        if cursor_buffer != tail_buffer {
 7608            return None;
 7609        }
 7610
 7611        let snapshot = cursor_buffer.read(cx).snapshot();
 7612        let word_ranges = cx.background_spawn(async move {
 7613            // this might look odd to put on the background thread, but
 7614            // `surrounding_word` can be quite expensive as it calls into
 7615            // tree-sitter language scopes
 7616            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7617            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7618            (start_word_range, end_word_range)
 7619        });
 7620
 7621        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7622        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7623            let (start_word_range, end_word_range) = word_ranges.await;
 7624            if start_word_range != end_word_range {
 7625                this.update(cx, |this, cx| {
 7626                    this.document_highlights_task.take();
 7627                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7628                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7629                })
 7630                .ok();
 7631                return;
 7632            }
 7633            cx.background_executor()
 7634                .timer(Duration::from_millis(debounce))
 7635                .await;
 7636
 7637            let highlights = if let Some(highlights) = cx.update(|cx| {
 7638                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7639            }) {
 7640                highlights.await.log_err()
 7641            } else {
 7642                None
 7643            };
 7644
 7645            if let Some(highlights) = highlights {
 7646                this.update(cx, |this, cx| {
 7647                    if this.pending_rename.is_some() {
 7648                        return;
 7649                    }
 7650
 7651                    let buffer = this.buffer.read(cx);
 7652                    if buffer
 7653                        .text_anchor_for_position(cursor_position, cx)
 7654                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7655                    {
 7656                        return;
 7657                    }
 7658
 7659                    let mut write_ranges = Vec::new();
 7660                    let mut read_ranges = Vec::new();
 7661                    let multibuffer_snapshot = buffer.snapshot(cx);
 7662                    for highlight in highlights {
 7663                        for range in
 7664                            multibuffer_snapshot.buffer_range_to_excerpt_ranges(highlight.range)
 7665                        {
 7666                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7667                                write_ranges.push(range);
 7668                            } else {
 7669                                read_ranges.push(range);
 7670                            }
 7671                        }
 7672                    }
 7673
 7674                    this.highlight_background(
 7675                        HighlightKey::DocumentHighlightRead,
 7676                        &read_ranges,
 7677                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7678                        cx,
 7679                    );
 7680                    this.highlight_background(
 7681                        HighlightKey::DocumentHighlightWrite,
 7682                        &write_ranges,
 7683                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7684                        cx,
 7685                    );
 7686                    cx.notify();
 7687                })
 7688                .log_err();
 7689            }
 7690        }));
 7691        None
 7692    }
 7693
 7694    fn prepare_highlight_query_from_selection(
 7695        &mut self,
 7696        snapshot: &DisplaySnapshot,
 7697        cx: &mut Context<Editor>,
 7698    ) -> Option<(String, Range<Anchor>)> {
 7699        if matches!(self.mode, EditorMode::SingleLine) {
 7700            return None;
 7701        }
 7702        if !EditorSettings::get_global(cx).selection_highlight {
 7703            return None;
 7704        }
 7705        if self.selections.count() != 1 || self.selections.line_mode() {
 7706            return None;
 7707        }
 7708        let selection = self.selections.newest::<Point>(&snapshot);
 7709        // If the selection spans multiple rows OR it is empty
 7710        if selection.start.row != selection.end.row
 7711            || selection.start.column == selection.end.column
 7712        {
 7713            return None;
 7714        }
 7715        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7716        let query = snapshot
 7717            .buffer_snapshot()
 7718            .text_for_range(selection_anchor_range.clone())
 7719            .collect::<String>();
 7720        if query.trim().is_empty() {
 7721            return None;
 7722        }
 7723        Some((query, selection_anchor_range))
 7724    }
 7725
 7726    #[ztracing::instrument(skip_all)]
 7727    fn update_selection_occurrence_highlights(
 7728        &mut self,
 7729        multi_buffer_snapshot: MultiBufferSnapshot,
 7730        query_text: String,
 7731        query_range: Range<Anchor>,
 7732        multi_buffer_range_to_query: Range<Point>,
 7733        use_debounce: bool,
 7734        window: &mut Window,
 7735        cx: &mut Context<Editor>,
 7736    ) -> Task<()> {
 7737        cx.spawn_in(window, async move |editor, cx| {
 7738            if use_debounce {
 7739                cx.background_executor()
 7740                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7741                    .await;
 7742            }
 7743            let match_task = cx.background_spawn(async move {
 7744                let buffer_ranges = multi_buffer_snapshot
 7745                    .range_to_buffer_ranges(
 7746                        multi_buffer_range_to_query.start..multi_buffer_range_to_query.end,
 7747                    )
 7748                    .into_iter()
 7749                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7750                let mut match_ranges = Vec::new();
 7751                let Ok(regex) = project::search::SearchQuery::text(
 7752                    query_text,
 7753                    false,
 7754                    false,
 7755                    false,
 7756                    Default::default(),
 7757                    Default::default(),
 7758                    false,
 7759                    None,
 7760                ) else {
 7761                    return Vec::default();
 7762                };
 7763                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7764                for (buffer_snapshot, search_range, _) in buffer_ranges {
 7765                    match_ranges.extend(
 7766                        regex
 7767                            .search(
 7768                                &buffer_snapshot,
 7769                                Some(search_range.start.0..search_range.end.0),
 7770                            )
 7771                            .await
 7772                            .into_iter()
 7773                            .filter_map(|match_range| {
 7774                                let match_start = buffer_snapshot
 7775                                    .anchor_after(search_range.start + match_range.start);
 7776                                let match_end = buffer_snapshot
 7777                                    .anchor_before(search_range.start + match_range.end);
 7778                                {
 7779                                    let range = multi_buffer_snapshot
 7780                                        .anchor_in_buffer(match_start)?
 7781                                        ..multi_buffer_snapshot.anchor_in_buffer(match_end)?;
 7782                                    Some(range).filter(|match_anchor_range| {
 7783                                        match_anchor_range != &query_range
 7784                                    })
 7785                                }
 7786                            }),
 7787                    );
 7788                }
 7789                match_ranges
 7790            });
 7791            let match_ranges = match_task.await;
 7792            editor
 7793                .update_in(cx, |editor, _, cx| {
 7794                    if use_debounce {
 7795                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7796                        editor.debounced_selection_highlight_complete = true;
 7797                    } else if editor.debounced_selection_highlight_complete {
 7798                        return;
 7799                    }
 7800                    if !match_ranges.is_empty() {
 7801                        editor.highlight_background(
 7802                            HighlightKey::SelectedTextHighlight,
 7803                            &match_ranges,
 7804                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7805                            cx,
 7806                        )
 7807                    }
 7808                })
 7809                .log_err();
 7810        })
 7811    }
 7812
 7813    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7814        struct NewlineFold;
 7815        let type_id = std::any::TypeId::of::<NewlineFold>();
 7816        if !self.mode.is_single_line() {
 7817            return;
 7818        }
 7819        let snapshot = self.snapshot(window, cx);
 7820        if snapshot.buffer_snapshot().max_point().row == 0 {
 7821            return;
 7822        }
 7823        let task = cx.background_spawn(async move {
 7824            let new_newlines = snapshot
 7825                .buffer_chars_at(MultiBufferOffset(0))
 7826                .filter_map(|(c, i)| {
 7827                    if c == '\n' {
 7828                        Some(
 7829                            snapshot.buffer_snapshot().anchor_after(i)
 7830                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7831                        )
 7832                    } else {
 7833                        None
 7834                    }
 7835                })
 7836                .collect::<Vec<_>>();
 7837            let existing_newlines = snapshot
 7838                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7839                .filter_map(|fold| {
 7840                    if fold.placeholder.type_tag == Some(type_id) {
 7841                        Some(fold.range.start..fold.range.end)
 7842                    } else {
 7843                        None
 7844                    }
 7845                })
 7846                .collect::<Vec<_>>();
 7847
 7848            (new_newlines, existing_newlines)
 7849        });
 7850        self.folding_newlines = cx.spawn(async move |this, cx| {
 7851            let (new_newlines, existing_newlines) = task.await;
 7852            if new_newlines == existing_newlines {
 7853                return;
 7854            }
 7855            let placeholder = FoldPlaceholder {
 7856                render: Arc::new(move |_, _, cx| {
 7857                    div()
 7858                        .bg(cx.theme().status().hint_background)
 7859                        .border_b_1()
 7860                        .size_full()
 7861                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7862                        .border_color(cx.theme().status().hint)
 7863                        .child("\\n")
 7864                        .into_any()
 7865                }),
 7866                constrain_width: false,
 7867                merge_adjacent: false,
 7868                type_tag: Some(type_id),
 7869                collapsed_text: None,
 7870            };
 7871            let creases = new_newlines
 7872                .into_iter()
 7873                .map(|range| Crease::simple(range, placeholder.clone()))
 7874                .collect();
 7875            this.update(cx, |this, cx| {
 7876                this.display_map.update(cx, |display_map, cx| {
 7877                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7878                    display_map.fold(creases, cx);
 7879                });
 7880            })
 7881            .ok();
 7882        });
 7883    }
 7884
 7885    #[ztracing::instrument(skip_all)]
 7886    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7887        if !self.lsp_data_enabled() {
 7888            return;
 7889        }
 7890        let cursor = self.selections.newest_anchor().head();
 7891        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7892
 7893        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7894            self.outline_symbols_at_cursor =
 7895                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7896            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7897            cx.notify();
 7898        } else {
 7899            let syntax = cx.theme().syntax().clone();
 7900            let background_task = cx.background_spawn(async move {
 7901                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7902            });
 7903            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7904                cx.spawn(async move |this, cx| {
 7905                    let symbols = background_task.await;
 7906                    this.update(cx, |this, cx| {
 7907                        this.outline_symbols_at_cursor = symbols;
 7908                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7909                        cx.notify();
 7910                    })
 7911                    .ok();
 7912                });
 7913        }
 7914    }
 7915
 7916    #[ztracing::instrument(skip_all)]
 7917    fn refresh_selected_text_highlights(
 7918        &mut self,
 7919        snapshot: &DisplaySnapshot,
 7920        on_buffer_edit: bool,
 7921        window: &mut Window,
 7922        cx: &mut Context<Editor>,
 7923    ) {
 7924        let Some((query_text, query_range)) =
 7925            self.prepare_highlight_query_from_selection(snapshot, cx)
 7926        else {
 7927            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7928            self.quick_selection_highlight_task.take();
 7929            self.debounced_selection_highlight_task.take();
 7930            self.debounced_selection_highlight_complete = false;
 7931            return;
 7932        };
 7933        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7934        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7935        let query_changed = self
 7936            .quick_selection_highlight_task
 7937            .as_ref()
 7938            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7939        if query_changed {
 7940            self.debounced_selection_highlight_complete = false;
 7941        }
 7942        if on_buffer_edit || query_changed {
 7943            self.quick_selection_highlight_task = Some((
 7944                query_range.clone(),
 7945                self.update_selection_occurrence_highlights(
 7946                    snapshot.buffer.clone(),
 7947                    query_text.clone(),
 7948                    query_range.clone(),
 7949                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7950                    false,
 7951                    window,
 7952                    cx,
 7953                ),
 7954            ));
 7955        }
 7956        if on_buffer_edit
 7957            || self
 7958                .debounced_selection_highlight_task
 7959                .as_ref()
 7960                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7961        {
 7962            let multi_buffer_start = multi_buffer_snapshot
 7963                .anchor_before(MultiBufferOffset(0))
 7964                .to_point(&multi_buffer_snapshot);
 7965            let multi_buffer_end = multi_buffer_snapshot
 7966                .anchor_after(multi_buffer_snapshot.len())
 7967                .to_point(&multi_buffer_snapshot);
 7968            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7969            self.debounced_selection_highlight_task = Some((
 7970                query_range.clone(),
 7971                self.update_selection_occurrence_highlights(
 7972                    snapshot.buffer.clone(),
 7973                    query_text,
 7974                    query_range,
 7975                    multi_buffer_full_range,
 7976                    true,
 7977                    window,
 7978                    cx,
 7979                ),
 7980            ));
 7981        }
 7982    }
 7983
 7984    pub fn multi_buffer_visible_range(
 7985        &self,
 7986        display_snapshot: &DisplaySnapshot,
 7987        cx: &App,
 7988    ) -> Range<Point> {
 7989        let visible_start = self
 7990            .scroll_manager
 7991            .native_anchor(display_snapshot, cx)
 7992            .anchor
 7993            .to_point(display_snapshot.buffer_snapshot())
 7994            .to_display_point(display_snapshot);
 7995
 7996        let mut target_end = visible_start;
 7997        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 7998
 7999        visible_start.to_point(display_snapshot)
 8000            ..display_snapshot
 8001                .clip_point(target_end, Bias::Right)
 8002                .to_point(display_snapshot)
 8003    }
 8004
 8005    pub fn refresh_edit_prediction(
 8006        &mut self,
 8007        debounce: bool,
 8008        user_requested: bool,
 8009        window: &mut Window,
 8010        cx: &mut Context<Self>,
 8011    ) -> Option<()> {
 8012        if self.leader_id.is_some() {
 8013            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8014            return None;
 8015        }
 8016
 8017        let cursor = self.selections.newest_anchor().head();
 8018        let (buffer, cursor_buffer_position) =
 8019            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8020
 8021        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8022            return None;
 8023        }
 8024
 8025        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 8026            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8027            return None;
 8028        }
 8029
 8030        self.update_visible_edit_prediction(window, cx);
 8031
 8032        if !user_requested
 8033            && (!self.should_show_edit_predictions()
 8034                || !self.is_focused(window)
 8035                || buffer.read(cx).is_empty())
 8036        {
 8037            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8038            return None;
 8039        }
 8040
 8041        self.edit_prediction_provider()?
 8042            .refresh(buffer, cursor_buffer_position, debounce, cx);
 8043        Some(())
 8044    }
 8045
 8046    fn show_edit_predictions_in_menu(&self) -> bool {
 8047        match self.edit_prediction_settings {
 8048            EditPredictionSettings::Disabled => false,
 8049            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8050        }
 8051    }
 8052
 8053    pub fn edit_predictions_enabled(&self) -> bool {
 8054        match self.edit_prediction_settings {
 8055            EditPredictionSettings::Disabled => false,
 8056            EditPredictionSettings::Enabled { .. } => true,
 8057        }
 8058    }
 8059
 8060    fn edit_prediction_requires_modifier(&self) -> bool {
 8061        match self.edit_prediction_settings {
 8062            EditPredictionSettings::Disabled => false,
 8063            EditPredictionSettings::Enabled {
 8064                preview_requires_modifier,
 8065                ..
 8066            } => preview_requires_modifier,
 8067        }
 8068    }
 8069
 8070    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8071        if self.edit_prediction_provider.is_none() {
 8072            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8073            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8074            return;
 8075        }
 8076
 8077        let selection = self.selections.newest_anchor();
 8078        let cursor = selection.head();
 8079
 8080        if let Some((buffer, cursor_buffer_position)) =
 8081            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8082        {
 8083            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8084                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8085                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8086                return;
 8087            }
 8088            self.edit_prediction_settings =
 8089                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8090        }
 8091    }
 8092
 8093    fn edit_prediction_settings_at_position(
 8094        &self,
 8095        buffer: &Entity<Buffer>,
 8096        buffer_position: language::Anchor,
 8097        cx: &App,
 8098    ) -> EditPredictionSettings {
 8099        if !self.mode.is_full()
 8100            || !self.show_edit_predictions_override.unwrap_or(true)
 8101            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8102        {
 8103            return EditPredictionSettings::Disabled;
 8104        }
 8105
 8106        if !LanguageSettings::for_buffer(&buffer.read(cx), cx).show_edit_predictions {
 8107            return EditPredictionSettings::Disabled;
 8108        };
 8109
 8110        let by_provider = matches!(
 8111            self.menu_edit_predictions_policy,
 8112            MenuEditPredictionsPolicy::ByProvider
 8113        );
 8114
 8115        let show_in_menu = by_provider
 8116            && self
 8117                .edit_prediction_provider
 8118                .as_ref()
 8119                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8120
 8121        let file = buffer.read(cx).file();
 8122        let preview_requires_modifier =
 8123            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8124
 8125        EditPredictionSettings::Enabled {
 8126            show_in_menu,
 8127            preview_requires_modifier,
 8128        }
 8129    }
 8130
 8131    fn should_show_edit_predictions(&self) -> bool {
 8132        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8133    }
 8134
 8135    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8136        matches!(
 8137            self.edit_prediction_preview,
 8138            EditPredictionPreview::Active { .. }
 8139        )
 8140    }
 8141
 8142    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8143        let cursor = self.selections.newest_anchor().head();
 8144        if let Some((buffer, cursor_position)) =
 8145            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8146        {
 8147            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8148        } else {
 8149            false
 8150        }
 8151    }
 8152
 8153    pub fn supports_minimap(&self, cx: &App) -> bool {
 8154        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8155    }
 8156
 8157    fn edit_predictions_enabled_in_buffer(
 8158        &self,
 8159        buffer: &Entity<Buffer>,
 8160        buffer_position: language::Anchor,
 8161        cx: &App,
 8162    ) -> bool {
 8163        maybe!({
 8164            if self.read_only(cx) || self.leader_id.is_some() {
 8165                return Some(false);
 8166            }
 8167            let provider = self.edit_prediction_provider()?;
 8168            if !provider.is_enabled(buffer, buffer_position, cx) {
 8169                return Some(false);
 8170            }
 8171            let buffer = buffer.read(cx);
 8172            let Some(file) = buffer.file() else {
 8173                return Some(true);
 8174            };
 8175            let settings = all_language_settings(Some(file), cx);
 8176            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8177        })
 8178        .unwrap_or(false)
 8179    }
 8180
 8181    pub fn show_edit_prediction(
 8182        &mut self,
 8183        _: &ShowEditPrediction,
 8184        window: &mut Window,
 8185        cx: &mut Context<Self>,
 8186    ) {
 8187        if !self.has_active_edit_prediction() {
 8188            self.refresh_edit_prediction(false, true, window, cx);
 8189            return;
 8190        }
 8191
 8192        self.update_visible_edit_prediction(window, cx);
 8193    }
 8194
 8195    pub fn display_cursor_names(
 8196        &mut self,
 8197        _: &DisplayCursorNames,
 8198        window: &mut Window,
 8199        cx: &mut Context<Self>,
 8200    ) {
 8201        self.show_cursor_names(window, cx);
 8202    }
 8203
 8204    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8205        self.show_cursor_names = true;
 8206        cx.notify();
 8207        cx.spawn_in(window, async move |this, cx| {
 8208            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8209            this.update(cx, |this, cx| {
 8210                this.show_cursor_names = false;
 8211                cx.notify()
 8212            })
 8213            .ok()
 8214        })
 8215        .detach();
 8216    }
 8217
 8218    pub fn accept_partial_edit_prediction(
 8219        &mut self,
 8220        granularity: EditPredictionGranularity,
 8221        window: &mut Window,
 8222        cx: &mut Context<Self>,
 8223    ) {
 8224        if self.show_edit_predictions_in_menu() {
 8225            self.hide_context_menu(window, cx);
 8226        }
 8227
 8228        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8229            return;
 8230        };
 8231
 8232        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8233            return;
 8234        }
 8235
 8236        match &active_edit_prediction.completion {
 8237            EditPrediction::MoveWithin { target, .. } => {
 8238                let target = *target;
 8239
 8240                if matches!(granularity, EditPredictionGranularity::Full) {
 8241                    if let Some(position_map) = &self.last_position_map {
 8242                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8243                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8244
 8245                        if is_visible || !self.edit_prediction_requires_modifier() {
 8246                            self.unfold_ranges(&[target..target], true, false, cx);
 8247                            self.change_selections(
 8248                                SelectionEffects::scroll(Autoscroll::newest()),
 8249                                window,
 8250                                cx,
 8251                                |selections| {
 8252                                    selections.select_anchor_ranges([target..target]);
 8253                                },
 8254                            );
 8255                            self.clear_row_highlights::<EditPredictionPreview>();
 8256                            self.edit_prediction_preview
 8257                                .set_previous_scroll_position(None);
 8258                        } else {
 8259                            // Highlight and request scroll
 8260                            self.edit_prediction_preview
 8261                                .set_previous_scroll_position(Some(
 8262                                    position_map.snapshot.scroll_anchor,
 8263                                ));
 8264                            self.highlight_rows::<EditPredictionPreview>(
 8265                                target..target,
 8266                                cx.theme().colors().editor_highlighted_line_background,
 8267                                RowHighlightOptions {
 8268                                    autoscroll: true,
 8269                                    ..Default::default()
 8270                                },
 8271                                cx,
 8272                            );
 8273                            self.request_autoscroll(Autoscroll::fit(), cx);
 8274                        }
 8275                    }
 8276                } else {
 8277                    self.change_selections(
 8278                        SelectionEffects::scroll(Autoscroll::newest()),
 8279                        window,
 8280                        cx,
 8281                        |selections| {
 8282                            selections.select_anchor_ranges([target..target]);
 8283                        },
 8284                    );
 8285                }
 8286            }
 8287            EditPrediction::MoveOutside { snapshot, target } => {
 8288                if let Some(workspace) = self.workspace() {
 8289                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8290                        .detach_and_log_err(cx);
 8291                }
 8292            }
 8293            EditPrediction::Edit {
 8294                edits,
 8295                cursor_position,
 8296                ..
 8297            } => {
 8298                self.report_edit_prediction_event(
 8299                    active_edit_prediction.completion_id.clone(),
 8300                    true,
 8301                    cx,
 8302                );
 8303
 8304                match granularity {
 8305                    EditPredictionGranularity::Full => {
 8306                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8307
 8308                        // Compute fallback cursor position BEFORE applying the edit,
 8309                        // so the anchor tracks through the edit correctly
 8310                        let fallback_cursor_target = {
 8311                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8312                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8313                        };
 8314
 8315                        self.buffer.update(cx, |buffer, cx| {
 8316                            buffer.edit(edits.iter().cloned(), None, cx)
 8317                        });
 8318
 8319                        if let Some(provider) = self.edit_prediction_provider() {
 8320                            provider.accept(cx);
 8321                        }
 8322
 8323                        // Resolve cursor position after the edit is applied
 8324                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8325                            // The anchor tracks through the edit, then we add the offset
 8326                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8327                            let base_offset = anchor.to_offset(&snapshot).0;
 8328                            let target_offset =
 8329                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8330                            snapshot.anchor_after(target_offset)
 8331                        } else {
 8332                            fallback_cursor_target
 8333                        };
 8334
 8335                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8336                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8337                        });
 8338
 8339                        let selections = self.selections.disjoint_anchors_arc();
 8340                        if let Some(transaction_id_now) =
 8341                            self.buffer.read(cx).last_transaction_id(cx)
 8342                        {
 8343                            if transaction_id_prev != Some(transaction_id_now) {
 8344                                self.selection_history
 8345                                    .insert_transaction(transaction_id_now, selections);
 8346                            }
 8347                        }
 8348
 8349                        self.update_visible_edit_prediction(window, cx);
 8350                        if self.active_edit_prediction.is_none() {
 8351                            self.refresh_edit_prediction(true, true, window, cx);
 8352                        }
 8353                        cx.notify();
 8354                    }
 8355                    _ => {
 8356                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8357                        let cursor_offset = self
 8358                            .selections
 8359                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8360                            .head();
 8361
 8362                        let insertion = edits.iter().find_map(|(range, text)| {
 8363                            let range = range.to_offset(&snapshot);
 8364                            if range.is_empty() && range.start == cursor_offset {
 8365                                Some(text)
 8366                            } else {
 8367                                None
 8368                            }
 8369                        });
 8370
 8371                        if let Some(text) = insertion {
 8372                            let text_to_insert = match granularity {
 8373                                EditPredictionGranularity::Word => {
 8374                                    let mut partial = text
 8375                                        .chars()
 8376                                        .by_ref()
 8377                                        .take_while(|c| c.is_alphabetic())
 8378                                        .collect::<String>();
 8379                                    if partial.is_empty() {
 8380                                        partial = text
 8381                                            .chars()
 8382                                            .by_ref()
 8383                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8384                                            .collect::<String>();
 8385                                    }
 8386                                    partial
 8387                                }
 8388                                EditPredictionGranularity::Line => {
 8389                                    if let Some(line) = text.split_inclusive('\n').next() {
 8390                                        line.to_string()
 8391                                    } else {
 8392                                        text.to_string()
 8393                                    }
 8394                                }
 8395                                EditPredictionGranularity::Full => unreachable!(),
 8396                            };
 8397
 8398                            cx.emit(EditorEvent::InputHandled {
 8399                                utf16_range_to_replace: None,
 8400                                text: text_to_insert.clone().into(),
 8401                            });
 8402
 8403                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8404                            self.refresh_edit_prediction(true, true, window, cx);
 8405                            cx.notify();
 8406                        } else {
 8407                            self.accept_partial_edit_prediction(
 8408                                EditPredictionGranularity::Full,
 8409                                window,
 8410                                cx,
 8411                            );
 8412                        }
 8413                    }
 8414                }
 8415            }
 8416        }
 8417    }
 8418
 8419    pub fn accept_next_word_edit_prediction(
 8420        &mut self,
 8421        _: &AcceptNextWordEditPrediction,
 8422        window: &mut Window,
 8423        cx: &mut Context<Self>,
 8424    ) {
 8425        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8426    }
 8427
 8428    pub fn accept_next_line_edit_prediction(
 8429        &mut self,
 8430        _: &AcceptNextLineEditPrediction,
 8431        window: &mut Window,
 8432        cx: &mut Context<Self>,
 8433    ) {
 8434        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8435    }
 8436
 8437    pub fn accept_edit_prediction(
 8438        &mut self,
 8439        _: &AcceptEditPrediction,
 8440        window: &mut Window,
 8441        cx: &mut Context<Self>,
 8442    ) {
 8443        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8444    }
 8445
 8446    fn discard_edit_prediction(
 8447        &mut self,
 8448        reason: EditPredictionDiscardReason,
 8449        cx: &mut Context<Self>,
 8450    ) -> bool {
 8451        if reason == EditPredictionDiscardReason::Rejected {
 8452            let completion_id = self
 8453                .active_edit_prediction
 8454                .as_ref()
 8455                .and_then(|active_completion| active_completion.completion_id.clone());
 8456
 8457            self.report_edit_prediction_event(completion_id, false, cx);
 8458        }
 8459
 8460        if let Some(provider) = self.edit_prediction_provider() {
 8461            provider.discard(reason, cx);
 8462        }
 8463
 8464        self.take_active_edit_prediction(reason == EditPredictionDiscardReason::Ignored, cx)
 8465    }
 8466
 8467    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8468        let Some(provider) = self.edit_prediction_provider() else {
 8469            return;
 8470        };
 8471
 8472        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 8473        let Some((position, _)) =
 8474            buffer_snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())
 8475        else {
 8476            return;
 8477        };
 8478        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
 8479            return;
 8480        };
 8481
 8482        let extension = buffer
 8483            .read(cx)
 8484            .file()
 8485            .and_then(|file| Some(file.path().extension()?.to_string()));
 8486
 8487        let event_type = match accepted {
 8488            true => "Edit Prediction Accepted",
 8489            false => "Edit Prediction Discarded",
 8490        };
 8491        telemetry::event!(
 8492            event_type,
 8493            provider = provider.name(),
 8494            prediction_id = id,
 8495            suggestion_accepted = accepted,
 8496            file_extension = extension,
 8497        );
 8498    }
 8499
 8500    fn open_editor_at_anchor(
 8501        snapshot: &language::BufferSnapshot,
 8502        target: language::Anchor,
 8503        workspace: &Entity<Workspace>,
 8504        window: &mut Window,
 8505        cx: &mut App,
 8506    ) -> Task<Result<()>> {
 8507        workspace.update(cx, |workspace, cx| {
 8508            let path = snapshot.file().map(|file| file.full_path(cx));
 8509            let Some(path) =
 8510                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8511            else {
 8512                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8513            };
 8514            let target = text::ToPoint::to_point(&target, snapshot);
 8515            let item = workspace.open_path(path, None, true, window, cx);
 8516            window.spawn(cx, async move |cx| {
 8517                let Some(editor) = item.await?.downcast::<Editor>() else {
 8518                    return Ok(());
 8519                };
 8520                editor
 8521                    .update_in(cx, |editor, window, cx| {
 8522                        editor.go_to_singleton_buffer_point(target, window, cx);
 8523                    })
 8524                    .ok();
 8525                anyhow::Ok(())
 8526            })
 8527        })
 8528    }
 8529
 8530    pub fn has_active_edit_prediction(&self) -> bool {
 8531        self.active_edit_prediction.is_some()
 8532    }
 8533
 8534    fn take_active_edit_prediction(
 8535        &mut self,
 8536        preserve_stale_in_menu: bool,
 8537        cx: &mut Context<Self>,
 8538    ) -> bool {
 8539        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8540            if !preserve_stale_in_menu {
 8541                self.stale_edit_prediction_in_menu = None;
 8542            }
 8543            return false;
 8544        };
 8545
 8546        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8547        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8548        self.stale_edit_prediction_in_menu =
 8549            preserve_stale_in_menu.then_some(active_edit_prediction);
 8550        true
 8551    }
 8552
 8553    /// Returns true when we're displaying the edit prediction popover below the cursor
 8554    /// like we are not previewing and the LSP autocomplete menu is visible
 8555    /// or we are in `when_holding_modifier` mode.
 8556    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8557        if self.edit_prediction_preview_is_active()
 8558            || !self.show_edit_predictions_in_menu()
 8559            || !self.edit_predictions_enabled()
 8560        {
 8561            return false;
 8562        }
 8563
 8564        if self.has_visible_completions_menu() {
 8565            return true;
 8566        }
 8567
 8568        has_completion && self.edit_prediction_requires_modifier()
 8569    }
 8570
 8571    fn handle_modifiers_changed(
 8572        &mut self,
 8573        modifiers: Modifiers,
 8574        position_map: &PositionMap,
 8575        window: &mut Window,
 8576        cx: &mut Context<Self>,
 8577    ) {
 8578        self.update_edit_prediction_settings(cx);
 8579
 8580        // Ensure that the edit prediction preview is updated, even when not
 8581        // enabled, if there's an active edit prediction preview.
 8582        if self.show_edit_predictions_in_menu()
 8583            || self.edit_prediction_requires_modifier()
 8584            || matches!(
 8585                self.edit_prediction_preview,
 8586                EditPredictionPreview::Active { .. }
 8587            )
 8588        {
 8589            self.update_edit_prediction_preview(&modifiers, window, cx);
 8590        }
 8591
 8592        self.update_selection_mode(&modifiers, position_map, window, cx);
 8593
 8594        let mouse_position = window.mouse_position();
 8595        if !position_map.text_hitbox.is_hovered(window) {
 8596            return;
 8597        }
 8598
 8599        self.update_hovered_link(
 8600            position_map.point_for_position(mouse_position),
 8601            Some(mouse_position),
 8602            &position_map.snapshot,
 8603            modifiers,
 8604            window,
 8605            cx,
 8606        )
 8607    }
 8608
 8609    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8610        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8611            MultiCursorModifier::Alt => modifiers.secondary(),
 8612            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8613        }
 8614    }
 8615
 8616    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8617        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8618            MultiCursorModifier::Alt => modifiers.alt,
 8619            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8620        }
 8621    }
 8622
 8623    fn columnar_selection_mode(
 8624        modifiers: &Modifiers,
 8625        cx: &mut Context<Self>,
 8626    ) -> Option<ColumnarMode> {
 8627        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8628            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8629                Some(ColumnarMode::FromMouse)
 8630            } else if Self::is_alt_pressed(modifiers, cx) {
 8631                Some(ColumnarMode::FromSelection)
 8632            } else {
 8633                None
 8634            }
 8635        } else {
 8636            None
 8637        }
 8638    }
 8639
 8640    fn update_selection_mode(
 8641        &mut self,
 8642        modifiers: &Modifiers,
 8643        position_map: &PositionMap,
 8644        window: &mut Window,
 8645        cx: &mut Context<Self>,
 8646    ) {
 8647        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8648            return;
 8649        };
 8650        if self.selections.pending_anchor().is_none() {
 8651            return;
 8652        }
 8653
 8654        let mouse_position = window.mouse_position();
 8655        let point_for_position = position_map.point_for_position(mouse_position);
 8656        let position = point_for_position.previous_valid;
 8657
 8658        self.select(
 8659            SelectPhase::BeginColumnar {
 8660                position,
 8661                reset: false,
 8662                mode,
 8663                goal_column: point_for_position.exact_unclipped.column(),
 8664            },
 8665            window,
 8666            cx,
 8667        );
 8668    }
 8669
 8670    fn update_edit_prediction_preview(
 8671        &mut self,
 8672        modifiers: &Modifiers,
 8673        window: &mut Window,
 8674        cx: &mut Context<Self>,
 8675    ) {
 8676        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8677
 8678        if modifiers_held {
 8679            if matches!(
 8680                self.edit_prediction_preview,
 8681                EditPredictionPreview::Inactive { .. }
 8682            ) {
 8683                self.edit_prediction_preview = EditPredictionPreview::Active {
 8684                    previous_scroll_position: None,
 8685                    since: Instant::now(),
 8686                };
 8687
 8688                self.update_visible_edit_prediction(window, cx);
 8689                cx.notify();
 8690            }
 8691        } else if let EditPredictionPreview::Active {
 8692            previous_scroll_position,
 8693            since,
 8694        } = self.edit_prediction_preview
 8695        {
 8696            if let (Some(previous_scroll_position), Some(position_map)) =
 8697                (previous_scroll_position, self.last_position_map.as_ref())
 8698            {
 8699                self.set_scroll_position(
 8700                    previous_scroll_position
 8701                        .scroll_position(&position_map.snapshot.display_snapshot),
 8702                    window,
 8703                    cx,
 8704                );
 8705            }
 8706
 8707            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8708                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8709            };
 8710            self.clear_row_highlights::<EditPredictionPreview>();
 8711            self.update_visible_edit_prediction(window, cx);
 8712            cx.notify();
 8713        }
 8714    }
 8715
 8716    fn update_visible_edit_prediction(
 8717        &mut self,
 8718        _window: &mut Window,
 8719        cx: &mut Context<Self>,
 8720    ) -> Option<()> {
 8721        if self.ime_transaction.is_some() {
 8722            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8723            return None;
 8724        }
 8725
 8726        let selection = self.selections.newest_anchor();
 8727        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8728        let cursor = selection.head();
 8729        let (cursor_text_anchor, _) = multibuffer.anchor_to_buffer_anchor(cursor)?;
 8730        let buffer = self.buffer.read(cx).buffer(cursor_text_anchor.buffer_id)?;
 8731
 8732        // Check project-level disable_ai setting for the current buffer
 8733        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8734            return None;
 8735        }
 8736        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8737
 8738        let show_in_menu = self.show_edit_predictions_in_menu();
 8739        let completions_menu_has_precedence = !show_in_menu
 8740            && (self.context_menu.borrow().is_some()
 8741                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8742
 8743        if completions_menu_has_precedence
 8744            || !offset_selection.is_empty()
 8745            || self
 8746                .active_edit_prediction
 8747                .as_ref()
 8748                .is_some_and(|completion| {
 8749                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8750                        return false;
 8751                    };
 8752                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8753                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8754                    !invalidation_range.contains(&offset_selection.head())
 8755                })
 8756        {
 8757            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8758            return None;
 8759        }
 8760
 8761        self.take_active_edit_prediction(true, cx);
 8762        let Some(provider) = self.edit_prediction_provider() else {
 8763            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8764            return None;
 8765        };
 8766
 8767        self.edit_prediction_settings =
 8768            self.edit_prediction_settings_at_position(&buffer, cursor_text_anchor, cx);
 8769
 8770        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8771
 8772        if self.in_leading_whitespace {
 8773            let cursor_point = cursor.to_point(&multibuffer);
 8774            let mut suggested_indent = None;
 8775            multibuffer.suggested_indents_callback(
 8776                cursor_point.row..cursor_point.row + 1,
 8777                &mut |_, indent| {
 8778                    suggested_indent = Some(indent);
 8779                    ControlFlow::Break(())
 8780                },
 8781                cx,
 8782            );
 8783
 8784            if let Some(indent) = suggested_indent
 8785                && indent.len == cursor_point.column
 8786            {
 8787                self.in_leading_whitespace = false;
 8788            }
 8789        }
 8790
 8791        let edit_prediction = provider.suggest(&buffer, cursor_text_anchor, cx)?;
 8792
 8793        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8794        {
 8795            edit_prediction_types::EditPrediction::Local {
 8796                id,
 8797                edits,
 8798                cursor_position,
 8799                edit_preview,
 8800            } => (id, edits, cursor_position, edit_preview),
 8801            edit_prediction_types::EditPrediction::Jump {
 8802                id,
 8803                snapshot,
 8804                target,
 8805            } => {
 8806                if let Some(provider) = &self.edit_prediction_provider {
 8807                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8808                }
 8809                self.stale_edit_prediction_in_menu = None;
 8810                self.active_edit_prediction = Some(EditPredictionState {
 8811                    inlay_ids: vec![],
 8812                    completion: EditPrediction::MoveOutside { snapshot, target },
 8813                    completion_id: id,
 8814                    invalidation_range: None,
 8815                });
 8816                cx.notify();
 8817                return Some(());
 8818            }
 8819        };
 8820
 8821        let edits = edits
 8822            .into_iter()
 8823            .flat_map(|(range, new_text)| {
 8824                Some((
 8825                    multibuffer.buffer_anchor_range_to_anchor_range(range)?,
 8826                    new_text,
 8827                ))
 8828            })
 8829            .collect::<Vec<_>>();
 8830        if edits.is_empty() {
 8831            return None;
 8832        }
 8833
 8834        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8835            let anchor = multibuffer.anchor_in_excerpt(predicted.anchor)?;
 8836            Some((anchor, predicted.offset))
 8837        });
 8838
 8839        let first_edit_start = edits.first().unwrap().0.start;
 8840        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8841        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8842
 8843        let last_edit_end = edits.last().unwrap().0.end;
 8844        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8845        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8846
 8847        let cursor_row = cursor.to_point(&multibuffer).row;
 8848
 8849        let snapshot = multibuffer
 8850            .buffer_for_id(cursor_text_anchor.buffer_id)
 8851            .cloned()?;
 8852
 8853        let mut inlay_ids = Vec::new();
 8854        let invalidation_row_range;
 8855        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8856            Some(cursor_row..edit_end_row)
 8857        } else if cursor_row > edit_end_row {
 8858            Some(edit_start_row..cursor_row)
 8859        } else {
 8860            None
 8861        };
 8862        let supports_jump = self
 8863            .edit_prediction_provider
 8864            .as_ref()
 8865            .map(|provider| provider.provider.supports_jump_to_edit())
 8866            .unwrap_or(true);
 8867
 8868        let is_move = supports_jump
 8869            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8870        let completion = if is_move {
 8871            if let Some(provider) = &self.edit_prediction_provider {
 8872                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8873            }
 8874            invalidation_row_range =
 8875                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8876            let target = first_edit_start;
 8877            EditPrediction::MoveWithin { target, snapshot }
 8878        } else {
 8879            let show_completions_in_menu = self.has_visible_completions_menu();
 8880            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8881                && !self.edit_predictions_hidden_for_vim_mode;
 8882
 8883            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8884                if provider.show_tab_accept_marker() {
 8885                    EditDisplayMode::TabAccept
 8886                } else {
 8887                    EditDisplayMode::Inline
 8888                }
 8889            } else {
 8890                EditDisplayMode::DiffPopover
 8891            };
 8892
 8893            let report_shown = match display_mode {
 8894                EditDisplayMode::DiffPopover | EditDisplayMode::Inline => {
 8895                    show_completions_in_buffer || show_completions_in_menu
 8896                }
 8897                EditDisplayMode::TabAccept => {
 8898                    show_completions_in_menu || self.edit_prediction_preview_is_active()
 8899                }
 8900            };
 8901
 8902            if report_shown && let Some(provider) = &self.edit_prediction_provider {
 8903                let suggestion_display_type = match display_mode {
 8904                    EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8905                    EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8906                        SuggestionDisplayType::GhostText
 8907                    }
 8908                };
 8909                provider.provider.did_show(suggestion_display_type, cx);
 8910            }
 8911
 8912            if show_completions_in_buffer {
 8913                if edits
 8914                    .iter()
 8915                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8916                {
 8917                    let mut inlays = Vec::new();
 8918                    for (range, new_text) in &edits {
 8919                        let inlay = Inlay::edit_prediction(
 8920                            post_inc(&mut self.next_inlay_id),
 8921                            range.start,
 8922                            new_text.as_ref(),
 8923                        );
 8924                        inlay_ids.push(inlay.id);
 8925                        inlays.push(inlay);
 8926                    }
 8927
 8928                    self.splice_inlays(&[], inlays, cx);
 8929                } else {
 8930                    let background_color = cx.theme().status().deleted_background;
 8931                    self.highlight_text(
 8932                        HighlightKey::EditPredictionHighlight,
 8933                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8934                        HighlightStyle {
 8935                            background_color: Some(background_color),
 8936                            ..Default::default()
 8937                        },
 8938                        cx,
 8939                    );
 8940                }
 8941            }
 8942
 8943            invalidation_row_range = edit_start_row..edit_end_row;
 8944
 8945            EditPrediction::Edit {
 8946                edits,
 8947                cursor_position,
 8948                edit_preview,
 8949                display_mode,
 8950                snapshot,
 8951            }
 8952        };
 8953
 8954        let invalidation_range = multibuffer
 8955            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8956            ..multibuffer.anchor_after(Point::new(
 8957                invalidation_row_range.end,
 8958                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8959            ));
 8960
 8961        self.stale_edit_prediction_in_menu = None;
 8962        self.active_edit_prediction = Some(EditPredictionState {
 8963            inlay_ids,
 8964            completion,
 8965            completion_id,
 8966            invalidation_range: Some(invalidation_range),
 8967        });
 8968
 8969        cx.notify();
 8970
 8971        Some(())
 8972    }
 8973
 8974    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8975        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8976    }
 8977
 8978    /// Get all display points of breakpoints that will be rendered within editor
 8979    ///
 8980    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8981    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8982    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8983    fn active_breakpoints(
 8984        &self,
 8985        range: Range<DisplayRow>,
 8986        window: &mut Window,
 8987        cx: &mut Context<Self>,
 8988    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8989        let mut breakpoint_display_points = HashMap::default();
 8990
 8991        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8992            return breakpoint_display_points;
 8993        };
 8994
 8995        let snapshot = self.snapshot(window, cx);
 8996
 8997        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8998
 8999        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 9000            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 9001
 9002        for (buffer_snapshot, range, _) in
 9003            multi_buffer_snapshot.range_to_buffer_ranges(range.start..range.end)
 9004        {
 9005            let Some(buffer) = self.buffer().read(cx).buffer(buffer_snapshot.remote_id()) else {
 9006                continue;
 9007            };
 9008            let breakpoints = breakpoint_store.read(cx).breakpoints(
 9009                &buffer,
 9010                Some(
 9011                    buffer_snapshot.anchor_before(range.start)
 9012                        ..buffer_snapshot.anchor_after(range.end),
 9013                ),
 9014                &buffer_snapshot,
 9015                cx,
 9016            );
 9017            for (breakpoint, state) in breakpoints {
 9018                let Some(multi_buffer_anchor) =
 9019                    multi_buffer_snapshot.anchor_in_excerpt(breakpoint.position)
 9020                else {
 9021                    continue;
 9022                };
 9023                let position = multi_buffer_anchor
 9024                    .to_point(&multi_buffer_snapshot)
 9025                    .to_display_point(&snapshot);
 9026
 9027                breakpoint_display_points.insert(
 9028                    position.row(),
 9029                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 9030                );
 9031            }
 9032        }
 9033
 9034        breakpoint_display_points
 9035    }
 9036
 9037    fn breakpoint_context_menu(
 9038        &self,
 9039        anchor: Anchor,
 9040        window: &mut Window,
 9041        cx: &mut Context<Self>,
 9042    ) -> Entity<ui::ContextMenu> {
 9043        let weak_editor = cx.weak_entity();
 9044        let focus_handle = self.focus_handle(cx);
 9045
 9046        let row = self
 9047            .buffer
 9048            .read(cx)
 9049            .snapshot(cx)
 9050            .summary_for_anchor::<Point>(&anchor)
 9051            .row;
 9052
 9053        let breakpoint = self
 9054            .breakpoint_at_row(row, window, cx)
 9055            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9056
 9057        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9058            "Edit Log Breakpoint"
 9059        } else {
 9060            "Set Log Breakpoint"
 9061        };
 9062
 9063        let condition_breakpoint_msg = if breakpoint
 9064            .as_ref()
 9065            .is_some_and(|bp| bp.1.condition.is_some())
 9066        {
 9067            "Edit Condition Breakpoint"
 9068        } else {
 9069            "Set Condition Breakpoint"
 9070        };
 9071
 9072        let hit_condition_breakpoint_msg = if breakpoint
 9073            .as_ref()
 9074            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9075        {
 9076            "Edit Hit Condition Breakpoint"
 9077        } else {
 9078            "Set Hit Condition Breakpoint"
 9079        };
 9080
 9081        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9082            "Unset Breakpoint"
 9083        } else {
 9084            "Set Breakpoint"
 9085        };
 9086
 9087        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9088
 9089        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9090            BreakpointState::Enabled => Some("Disable"),
 9091            BreakpointState::Disabled => Some("Enable"),
 9092        });
 9093
 9094        let (anchor, breakpoint) =
 9095            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9096
 9097        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9098            menu.on_blur_subscription(Subscription::new(|| {}))
 9099                .context(focus_handle)
 9100                .when(run_to_cursor, |this| {
 9101                    let weak_editor = weak_editor.clone();
 9102                    this.entry("Run to Cursor", None, move |window, cx| {
 9103                        weak_editor
 9104                            .update(cx, |editor, cx| {
 9105                                editor.change_selections(
 9106                                    SelectionEffects::no_scroll(),
 9107                                    window,
 9108                                    cx,
 9109                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9110                                );
 9111                            })
 9112                            .ok();
 9113
 9114                        window.dispatch_action(Box::new(RunToCursor), cx);
 9115                    })
 9116                    .separator()
 9117                })
 9118                .when_some(toggle_state_msg, |this, msg| {
 9119                    this.entry(msg, None, {
 9120                        let weak_editor = weak_editor.clone();
 9121                        let breakpoint = breakpoint.clone();
 9122                        move |_window, cx| {
 9123                            weak_editor
 9124                                .update(cx, |this, cx| {
 9125                                    this.edit_breakpoint_at_anchor(
 9126                                        anchor,
 9127                                        breakpoint.as_ref().clone(),
 9128                                        BreakpointEditAction::InvertState,
 9129                                        cx,
 9130                                    );
 9131                                })
 9132                                .log_err();
 9133                        }
 9134                    })
 9135                })
 9136                .entry(set_breakpoint_msg, None, {
 9137                    let weak_editor = weak_editor.clone();
 9138                    let breakpoint = breakpoint.clone();
 9139                    move |_window, cx| {
 9140                        weak_editor
 9141                            .update(cx, |this, cx| {
 9142                                this.edit_breakpoint_at_anchor(
 9143                                    anchor,
 9144                                    breakpoint.as_ref().clone(),
 9145                                    BreakpointEditAction::Toggle,
 9146                                    cx,
 9147                                );
 9148                            })
 9149                            .log_err();
 9150                    }
 9151                })
 9152                .entry(log_breakpoint_msg, None, {
 9153                    let breakpoint = breakpoint.clone();
 9154                    let weak_editor = weak_editor.clone();
 9155                    move |window, cx| {
 9156                        weak_editor
 9157                            .update(cx, |this, cx| {
 9158                                this.add_edit_breakpoint_block(
 9159                                    anchor,
 9160                                    breakpoint.as_ref(),
 9161                                    BreakpointPromptEditAction::Log,
 9162                                    window,
 9163                                    cx,
 9164                                );
 9165                            })
 9166                            .log_err();
 9167                    }
 9168                })
 9169                .entry(condition_breakpoint_msg, None, {
 9170                    let breakpoint = breakpoint.clone();
 9171                    let weak_editor = weak_editor.clone();
 9172                    move |window, cx| {
 9173                        weak_editor
 9174                            .update(cx, |this, cx| {
 9175                                this.add_edit_breakpoint_block(
 9176                                    anchor,
 9177                                    breakpoint.as_ref(),
 9178                                    BreakpointPromptEditAction::Condition,
 9179                                    window,
 9180                                    cx,
 9181                                );
 9182                            })
 9183                            .log_err();
 9184                    }
 9185                })
 9186                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9187                    weak_editor
 9188                        .update(cx, |this, cx| {
 9189                            this.add_edit_breakpoint_block(
 9190                                anchor,
 9191                                breakpoint.as_ref(),
 9192                                BreakpointPromptEditAction::HitCondition,
 9193                                window,
 9194                                cx,
 9195                            );
 9196                        })
 9197                        .log_err();
 9198                })
 9199        })
 9200    }
 9201
 9202    fn render_breakpoint(
 9203        &self,
 9204        position: Anchor,
 9205        row: DisplayRow,
 9206        breakpoint: &Breakpoint,
 9207        state: Option<BreakpointSessionState>,
 9208        cx: &mut Context<Self>,
 9209    ) -> IconButton {
 9210        let is_rejected = state.is_some_and(|s| !s.verified);
 9211        // Is it a breakpoint that shows up when hovering over gutter?
 9212        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9213            (false, false),
 9214            |PhantomBreakpointIndicator {
 9215                 is_active,
 9216                 display_row,
 9217                 collides_with_existing_breakpoint,
 9218             }| {
 9219                (
 9220                    is_active && display_row == row,
 9221                    collides_with_existing_breakpoint,
 9222                )
 9223            },
 9224        );
 9225
 9226        let (color, icon) = {
 9227            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9228                (false, false) => ui::IconName::DebugBreakpoint,
 9229                (true, false) => ui::IconName::DebugLogBreakpoint,
 9230                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9231                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9232            };
 9233
 9234            let theme_colors = cx.theme().colors();
 9235
 9236            let color = if is_phantom {
 9237                if collides_with_existing {
 9238                    Color::Custom(
 9239                        theme_colors
 9240                            .debugger_accent
 9241                            .blend(theme_colors.text.opacity(0.6)),
 9242                    )
 9243                } else {
 9244                    Color::Hint
 9245                }
 9246            } else if is_rejected {
 9247                Color::Disabled
 9248            } else {
 9249                Color::Debugger
 9250            };
 9251
 9252            (color, icon)
 9253        };
 9254
 9255        let breakpoint = Arc::from(breakpoint.clone());
 9256
 9257        let alt_as_text = gpui::Keystroke {
 9258            modifiers: Modifiers::secondary_key(),
 9259            ..Default::default()
 9260        };
 9261        let primary_action_text = if breakpoint.is_disabled() {
 9262            "Enable breakpoint"
 9263        } else if is_phantom && !collides_with_existing {
 9264            "Set breakpoint"
 9265        } else {
 9266            "Unset breakpoint"
 9267        };
 9268        let focus_handle = self.focus_handle.clone();
 9269
 9270        let meta = if is_rejected {
 9271            SharedString::from("No executable code is associated with this line.")
 9272        } else if collides_with_existing && !breakpoint.is_disabled() {
 9273            SharedString::from(format!(
 9274                "{alt_as_text}-click to disable,\nright-click for more options."
 9275            ))
 9276        } else {
 9277            SharedString::from("Right-click for more options.")
 9278        };
 9279        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9280            .icon_size(IconSize::XSmall)
 9281            .size(ui::ButtonSize::None)
 9282            .when(is_rejected, |this| {
 9283                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9284            })
 9285            .icon_color(color)
 9286            .style(ButtonStyle::Transparent)
 9287            .on_click(cx.listener({
 9288                move |editor, event: &ClickEvent, window, cx| {
 9289                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9290                        BreakpointEditAction::InvertState
 9291                    } else {
 9292                        BreakpointEditAction::Toggle
 9293                    };
 9294
 9295                    window.focus(&editor.focus_handle(cx), cx);
 9296                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9297                    editor.edit_breakpoint_at_anchor(
 9298                        position,
 9299                        breakpoint.as_ref().clone(),
 9300                        edit_action,
 9301                        cx,
 9302                    );
 9303                }
 9304            }))
 9305            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9306                editor.set_breakpoint_context_menu(
 9307                    row,
 9308                    Some(position),
 9309                    event.position(),
 9310                    window,
 9311                    cx,
 9312                );
 9313            }))
 9314            .tooltip(move |_window, cx| {
 9315                Tooltip::with_meta_in(
 9316                    primary_action_text,
 9317                    Some(&ToggleBreakpoint),
 9318                    meta.clone(),
 9319                    &focus_handle,
 9320                    cx,
 9321                )
 9322            })
 9323    }
 9324
 9325    fn build_tasks_context(
 9326        project: &Entity<Project>,
 9327        buffer: &Entity<Buffer>,
 9328        buffer_row: u32,
 9329        tasks: &Arc<RunnableTasks>,
 9330        cx: &mut Context<Self>,
 9331    ) -> Task<Option<task::TaskContext>> {
 9332        let position = Point::new(buffer_row, tasks.column);
 9333        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9334        let location = Location {
 9335            buffer: buffer.clone(),
 9336            range: range_start..range_start,
 9337        };
 9338        // Fill in the environmental variables from the tree-sitter captures
 9339        let mut captured_task_variables = TaskVariables::default();
 9340        for (capture_name, value) in tasks.extra_variables.clone() {
 9341            captured_task_variables.insert(
 9342                task::VariableName::Custom(capture_name.into()),
 9343                value.clone(),
 9344            );
 9345        }
 9346        project.update(cx, |project, cx| {
 9347            project.task_store().update(cx, |task_store, cx| {
 9348                task_store.task_context_for_location(captured_task_variables, location, cx)
 9349            })
 9350        })
 9351    }
 9352
 9353    pub fn context_menu_visible(&self) -> bool {
 9354        !self.edit_prediction_preview_is_active()
 9355            && self
 9356                .context_menu
 9357                .borrow()
 9358                .as_ref()
 9359                .is_some_and(|menu| menu.visible())
 9360    }
 9361
 9362    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9363        self.context_menu
 9364            .borrow()
 9365            .as_ref()
 9366            .map(|menu| menu.origin())
 9367    }
 9368
 9369    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9370        self.context_menu_options = Some(options);
 9371    }
 9372
 9373    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9374    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9375
 9376    fn render_edit_prediction_popover(
 9377        &mut self,
 9378        text_bounds: &Bounds<Pixels>,
 9379        content_origin: gpui::Point<Pixels>,
 9380        right_margin: Pixels,
 9381        editor_snapshot: &EditorSnapshot,
 9382        visible_row_range: Range<DisplayRow>,
 9383        scroll_top: ScrollOffset,
 9384        scroll_bottom: ScrollOffset,
 9385        line_layouts: &[LineWithInvisibles],
 9386        line_height: Pixels,
 9387        scroll_position: gpui::Point<ScrollOffset>,
 9388        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9389        newest_selection_head: Option<DisplayPoint>,
 9390        editor_width: Pixels,
 9391        style: &EditorStyle,
 9392        window: &mut Window,
 9393        cx: &mut App,
 9394    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9395        if self.mode().is_minimap() {
 9396            return None;
 9397        }
 9398        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9399
 9400        if self.edit_prediction_visible_in_cursor_popover(true) {
 9401            return None;
 9402        }
 9403
 9404        match &active_edit_prediction.completion {
 9405            EditPrediction::MoveWithin { target, .. } => {
 9406                let target_display_point = target.to_display_point(editor_snapshot);
 9407
 9408                if self.edit_prediction_requires_modifier() {
 9409                    if !self.edit_prediction_preview_is_active() {
 9410                        return None;
 9411                    }
 9412
 9413                    self.render_edit_prediction_modifier_jump_popover(
 9414                        text_bounds,
 9415                        content_origin,
 9416                        visible_row_range,
 9417                        line_layouts,
 9418                        line_height,
 9419                        scroll_pixel_position,
 9420                        newest_selection_head,
 9421                        target_display_point,
 9422                        window,
 9423                        cx,
 9424                    )
 9425                } else {
 9426                    self.render_edit_prediction_eager_jump_popover(
 9427                        text_bounds,
 9428                        content_origin,
 9429                        editor_snapshot,
 9430                        visible_row_range,
 9431                        scroll_top,
 9432                        scroll_bottom,
 9433                        line_height,
 9434                        scroll_pixel_position,
 9435                        target_display_point,
 9436                        editor_width,
 9437                        window,
 9438                        cx,
 9439                    )
 9440                }
 9441            }
 9442            EditPrediction::Edit {
 9443                display_mode: EditDisplayMode::Inline,
 9444                ..
 9445            } => None,
 9446            EditPrediction::Edit {
 9447                display_mode: EditDisplayMode::TabAccept,
 9448                edits,
 9449                ..
 9450            } => {
 9451                let range = &edits.first()?.0;
 9452                let target_display_point = range.end.to_display_point(editor_snapshot);
 9453
 9454                self.render_edit_prediction_end_of_line_popover(
 9455                    "Accept",
 9456                    editor_snapshot,
 9457                    visible_row_range,
 9458                    target_display_point,
 9459                    line_height,
 9460                    scroll_pixel_position,
 9461                    content_origin,
 9462                    editor_width,
 9463                    window,
 9464                    cx,
 9465                )
 9466            }
 9467            EditPrediction::Edit {
 9468                edits,
 9469                edit_preview,
 9470                display_mode: EditDisplayMode::DiffPopover,
 9471                snapshot,
 9472                ..
 9473            } => self.render_edit_prediction_diff_popover(
 9474                text_bounds,
 9475                content_origin,
 9476                right_margin,
 9477                editor_snapshot,
 9478                visible_row_range,
 9479                line_layouts,
 9480                line_height,
 9481                scroll_position,
 9482                scroll_pixel_position,
 9483                newest_selection_head,
 9484                editor_width,
 9485                style,
 9486                edits,
 9487                edit_preview,
 9488                snapshot,
 9489                window,
 9490                cx,
 9491            ),
 9492            EditPrediction::MoveOutside { snapshot, .. } => {
 9493                let mut element = self
 9494                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9495                    .into_any();
 9496
 9497                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9498                let origin_x = text_bounds.size.width - size.width - px(30.);
 9499                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9500                element.prepaint_at(origin, window, cx);
 9501
 9502                Some((element, origin))
 9503            }
 9504        }
 9505    }
 9506
 9507    fn render_edit_prediction_modifier_jump_popover(
 9508        &mut self,
 9509        text_bounds: &Bounds<Pixels>,
 9510        content_origin: gpui::Point<Pixels>,
 9511        visible_row_range: Range<DisplayRow>,
 9512        line_layouts: &[LineWithInvisibles],
 9513        line_height: Pixels,
 9514        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9515        newest_selection_head: Option<DisplayPoint>,
 9516        target_display_point: DisplayPoint,
 9517        window: &mut Window,
 9518        cx: &mut App,
 9519    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9520        let scrolled_content_origin =
 9521            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9522
 9523        const SCROLL_PADDING_Y: Pixels = px(12.);
 9524
 9525        if target_display_point.row() < visible_row_range.start {
 9526            return self.render_edit_prediction_scroll_popover(
 9527                &|_| SCROLL_PADDING_Y,
 9528                IconName::ArrowUp,
 9529                visible_row_range,
 9530                line_layouts,
 9531                newest_selection_head,
 9532                scrolled_content_origin,
 9533                window,
 9534                cx,
 9535            );
 9536        } else if target_display_point.row() >= visible_row_range.end {
 9537            return self.render_edit_prediction_scroll_popover(
 9538                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9539                IconName::ArrowDown,
 9540                visible_row_range,
 9541                line_layouts,
 9542                newest_selection_head,
 9543                scrolled_content_origin,
 9544                window,
 9545                cx,
 9546            );
 9547        }
 9548
 9549        const POLE_WIDTH: Pixels = px(2.);
 9550
 9551        let line_layout =
 9552            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9553        let target_column = target_display_point.column() as usize;
 9554
 9555        let target_x = line_layout.x_for_index(target_column);
 9556        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9557            - scroll_pixel_position.y;
 9558
 9559        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9560
 9561        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9562        border_color.l += 0.001;
 9563
 9564        let mut element = v_flex()
 9565            .items_end()
 9566            .when(flag_on_right, |el| el.items_start())
 9567            .child(if flag_on_right {
 9568                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9569                    .rounded_bl(px(0.))
 9570                    .rounded_tl(px(0.))
 9571                    .border_l_2()
 9572                    .border_color(border_color)
 9573            } else {
 9574                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9575                    .rounded_br(px(0.))
 9576                    .rounded_tr(px(0.))
 9577                    .border_r_2()
 9578                    .border_color(border_color)
 9579            })
 9580            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9581            .into_any();
 9582
 9583        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9584
 9585        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9586            - point(
 9587                if flag_on_right {
 9588                    POLE_WIDTH
 9589                } else {
 9590                    size.width - POLE_WIDTH
 9591                },
 9592                size.height - line_height,
 9593            );
 9594
 9595        origin.x = origin.x.max(content_origin.x);
 9596
 9597        element.prepaint_at(origin, window, cx);
 9598
 9599        Some((element, origin))
 9600    }
 9601
 9602    fn render_edit_prediction_scroll_popover(
 9603        &mut self,
 9604        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9605        scroll_icon: IconName,
 9606        visible_row_range: Range<DisplayRow>,
 9607        line_layouts: &[LineWithInvisibles],
 9608        newest_selection_head: Option<DisplayPoint>,
 9609        scrolled_content_origin: gpui::Point<Pixels>,
 9610        window: &mut Window,
 9611        cx: &mut App,
 9612    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9613        let mut element = self
 9614            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9615            .into_any();
 9616
 9617        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9618
 9619        let cursor = newest_selection_head?;
 9620        let cursor_row_layout =
 9621            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9622        let cursor_column = cursor.column() as usize;
 9623
 9624        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9625
 9626        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9627
 9628        element.prepaint_at(origin, window, cx);
 9629        Some((element, origin))
 9630    }
 9631
 9632    fn render_edit_prediction_eager_jump_popover(
 9633        &mut self,
 9634        text_bounds: &Bounds<Pixels>,
 9635        content_origin: gpui::Point<Pixels>,
 9636        editor_snapshot: &EditorSnapshot,
 9637        visible_row_range: Range<DisplayRow>,
 9638        scroll_top: ScrollOffset,
 9639        scroll_bottom: ScrollOffset,
 9640        line_height: Pixels,
 9641        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9642        target_display_point: DisplayPoint,
 9643        editor_width: Pixels,
 9644        window: &mut Window,
 9645        cx: &mut App,
 9646    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9647        if target_display_point.row().as_f64() < scroll_top {
 9648            let mut element = self
 9649                .render_edit_prediction_line_popover(
 9650                    "Jump to Edit",
 9651                    Some(IconName::ArrowUp),
 9652                    window,
 9653                    cx,
 9654                )
 9655                .into_any();
 9656
 9657            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9658            let offset = point(
 9659                (text_bounds.size.width - size.width) / 2.,
 9660                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9661            );
 9662
 9663            let origin = text_bounds.origin + offset;
 9664            element.prepaint_at(origin, window, cx);
 9665            Some((element, origin))
 9666        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9667            let mut element = self
 9668                .render_edit_prediction_line_popover(
 9669                    "Jump to Edit",
 9670                    Some(IconName::ArrowDown),
 9671                    window,
 9672                    cx,
 9673                )
 9674                .into_any();
 9675
 9676            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9677            let offset = point(
 9678                (text_bounds.size.width - size.width) / 2.,
 9679                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9680            );
 9681
 9682            let origin = text_bounds.origin + offset;
 9683            element.prepaint_at(origin, window, cx);
 9684            Some((element, origin))
 9685        } else {
 9686            self.render_edit_prediction_end_of_line_popover(
 9687                "Jump to Edit",
 9688                editor_snapshot,
 9689                visible_row_range,
 9690                target_display_point,
 9691                line_height,
 9692                scroll_pixel_position,
 9693                content_origin,
 9694                editor_width,
 9695                window,
 9696                cx,
 9697            )
 9698        }
 9699    }
 9700
 9701    fn render_edit_prediction_end_of_line_popover(
 9702        self: &mut Editor,
 9703        label: &'static str,
 9704        editor_snapshot: &EditorSnapshot,
 9705        visible_row_range: Range<DisplayRow>,
 9706        target_display_point: DisplayPoint,
 9707        line_height: Pixels,
 9708        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9709        content_origin: gpui::Point<Pixels>,
 9710        editor_width: Pixels,
 9711        window: &mut Window,
 9712        cx: &mut App,
 9713    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9714        let target_line_end = DisplayPoint::new(
 9715            target_display_point.row(),
 9716            editor_snapshot.line_len(target_display_point.row()),
 9717        );
 9718
 9719        let mut element = self
 9720            .render_edit_prediction_line_popover(label, None, window, cx)
 9721            .into_any();
 9722
 9723        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9724
 9725        let line_origin =
 9726            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9727
 9728        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9729        let mut origin = start_point
 9730            + line_origin
 9731            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9732        origin.x = origin.x.max(content_origin.x);
 9733
 9734        let max_x = content_origin.x + editor_width - size.width;
 9735
 9736        if origin.x > max_x {
 9737            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9738
 9739            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9740                origin.y += offset;
 9741                IconName::ArrowUp
 9742            } else {
 9743                origin.y -= offset;
 9744                IconName::ArrowDown
 9745            };
 9746
 9747            element = self
 9748                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9749                .into_any();
 9750
 9751            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9752
 9753            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9754        }
 9755
 9756        element.prepaint_at(origin, window, cx);
 9757        Some((element, origin))
 9758    }
 9759
 9760    fn render_edit_prediction_diff_popover(
 9761        self: &Editor,
 9762        text_bounds: &Bounds<Pixels>,
 9763        content_origin: gpui::Point<Pixels>,
 9764        right_margin: Pixels,
 9765        editor_snapshot: &EditorSnapshot,
 9766        visible_row_range: Range<DisplayRow>,
 9767        line_layouts: &[LineWithInvisibles],
 9768        line_height: Pixels,
 9769        scroll_position: gpui::Point<ScrollOffset>,
 9770        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9771        newest_selection_head: Option<DisplayPoint>,
 9772        editor_width: Pixels,
 9773        style: &EditorStyle,
 9774        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9775        edit_preview: &Option<language::EditPreview>,
 9776        snapshot: &language::BufferSnapshot,
 9777        window: &mut Window,
 9778        cx: &mut App,
 9779    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9780        let edit_start = edits
 9781            .first()
 9782            .unwrap()
 9783            .0
 9784            .start
 9785            .to_display_point(editor_snapshot);
 9786        let edit_end = edits
 9787            .last()
 9788            .unwrap()
 9789            .0
 9790            .end
 9791            .to_display_point(editor_snapshot);
 9792
 9793        let is_visible = visible_row_range.contains(&edit_start.row())
 9794            || visible_row_range.contains(&edit_end.row());
 9795        if !is_visible {
 9796            return None;
 9797        }
 9798
 9799        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9800            crate::edit_prediction_edit_text(
 9801                snapshot,
 9802                edits,
 9803                edit_preview,
 9804                false,
 9805                editor_snapshot.buffer_snapshot(),
 9806                cx,
 9807            )
 9808        } else {
 9809            // Fallback for providers without edit_preview
 9810            crate::edit_prediction_fallback_text(edits, cx)
 9811        };
 9812
 9813        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9814        let line_count = highlighted_edits.text.lines().count();
 9815
 9816        const BORDER_WIDTH: Pixels = px(1.);
 9817
 9818        let keybind = self.render_edit_prediction_keybind(window, cx);
 9819        let has_keybind = keybind.is_some();
 9820
 9821        let mut element = h_flex()
 9822            .items_start()
 9823            .child(
 9824                h_flex()
 9825                    .bg(cx.theme().colors().editor_background)
 9826                    .border(BORDER_WIDTH)
 9827                    .shadow_xs()
 9828                    .border_color(cx.theme().colors().border)
 9829                    .rounded_l_lg()
 9830                    .when(line_count > 1, |el| el.rounded_br_lg())
 9831                    .pr_1()
 9832                    .child(styled_text),
 9833            )
 9834            .child(
 9835                h_flex()
 9836                    .h(line_height + BORDER_WIDTH * 2.)
 9837                    .px_1p5()
 9838                    .gap_1()
 9839                    // Workaround: For some reason, there's a gap if we don't do this
 9840                    .ml(-BORDER_WIDTH)
 9841                    .shadow(vec![gpui::BoxShadow {
 9842                        color: gpui::black().opacity(0.05),
 9843                        offset: point(px(1.), px(1.)),
 9844                        blur_radius: px(2.),
 9845                        spread_radius: px(0.),
 9846                    }])
 9847                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9848                    .border(BORDER_WIDTH)
 9849                    .border_color(cx.theme().colors().border)
 9850                    .rounded_r_lg()
 9851                    .id("edit_prediction_diff_popover_keybind")
 9852                    .when(!has_keybind, |el| {
 9853                        let status_colors = cx.theme().status();
 9854
 9855                        el.bg(status_colors.error_background)
 9856                            .border_color(status_colors.error.opacity(0.6))
 9857                            .child(Icon::new(IconName::Info).color(Color::Error))
 9858                            .cursor_default()
 9859                            .hoverable_tooltip(move |_window, cx| {
 9860                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9861                            })
 9862                    })
 9863                    .children(keybind),
 9864            )
 9865            .into_any();
 9866
 9867        let longest_row =
 9868            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9869        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9870            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9871        } else {
 9872            layout_line(
 9873                longest_row,
 9874                editor_snapshot,
 9875                style,
 9876                editor_width,
 9877                |_| false,
 9878                window,
 9879                cx,
 9880            )
 9881            .width
 9882        };
 9883
 9884        let viewport_bounds =
 9885            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9886                right: -right_margin,
 9887                ..Default::default()
 9888            });
 9889
 9890        let x_after_longest = Pixels::from(
 9891            ScrollPixelOffset::from(
 9892                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9893            ) - scroll_pixel_position.x,
 9894        );
 9895
 9896        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9897
 9898        // Fully visible if it can be displayed within the window (allow overlapping other
 9899        // panes). However, this is only allowed if the popover starts within text_bounds.
 9900        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9901            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9902
 9903        let mut origin = if can_position_to_the_right {
 9904            point(
 9905                x_after_longest,
 9906                text_bounds.origin.y
 9907                    + Pixels::from(
 9908                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9909                            - scroll_pixel_position.y,
 9910                    ),
 9911            )
 9912        } else {
 9913            let cursor_row = newest_selection_head.map(|head| head.row());
 9914            let above_edit = edit_start
 9915                .row()
 9916                .0
 9917                .checked_sub(line_count as u32)
 9918                .map(DisplayRow);
 9919            let below_edit = Some(edit_end.row() + 1);
 9920            let above_cursor =
 9921                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9922            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9923
 9924            // Place the edit popover adjacent to the edit if there is a location
 9925            // available that is onscreen and does not obscure the cursor. Otherwise,
 9926            // place it adjacent to the cursor.
 9927            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9928                .into_iter()
 9929                .flatten()
 9930                .find(|&start_row| {
 9931                    let end_row = start_row + line_count as u32;
 9932                    visible_row_range.contains(&start_row)
 9933                        && visible_row_range.contains(&end_row)
 9934                        && cursor_row
 9935                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9936                })?;
 9937
 9938            content_origin
 9939                + point(
 9940                    Pixels::from(-scroll_pixel_position.x),
 9941                    Pixels::from(
 9942                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9943                    ),
 9944                )
 9945        };
 9946
 9947        origin.x -= BORDER_WIDTH;
 9948
 9949        window.with_content_mask(
 9950            Some(gpui::ContentMask {
 9951                bounds: *text_bounds,
 9952            }),
 9953            |window| {
 9954                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9955            },
 9956        );
 9957
 9958        // Do not return an element, since it will already be drawn due to defer_draw.
 9959        None
 9960    }
 9961
 9962    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9963        px(30.)
 9964    }
 9965
 9966    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9967        if self.read_only(cx) {
 9968            cx.theme().players().read_only()
 9969        } else {
 9970            self.style.as_ref().unwrap().local_player
 9971        }
 9972    }
 9973
 9974    fn render_edit_prediction_inline_keystroke(
 9975        &self,
 9976        keystroke: &gpui::KeybindingKeystroke,
 9977        modifiers_color: Color,
 9978        cx: &App,
 9979    ) -> AnyElement {
 9980        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9981
 9982        h_flex()
 9983            .px_0p5()
 9984            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9985            .font(
 9986                theme_settings::ThemeSettings::get_global(cx)
 9987                    .buffer_font
 9988                    .clone(),
 9989            )
 9990            .text_size(TextSize::XSmall.rems(cx))
 9991            .child(h_flex().children(ui::render_modifiers(
 9992                keystroke.modifiers(),
 9993                PlatformStyle::platform(),
 9994                Some(modifiers_color),
 9995                Some(IconSize::XSmall.rems().into()),
 9996                true,
 9997            )))
 9998            .when(is_platform_style_mac, |parent| {
 9999                parent.child(keystroke.key().to_string())
10000            })
10001            .when(!is_platform_style_mac, |parent| {
10002                parent.child(
10003                    Key::new(ui::utils::capitalize(keystroke.key()), Some(Color::Default))
10004                        .size(Some(IconSize::XSmall.rems().into())),
10005                )
10006            })
10007            .into_any()
10008    }
10009
10010    fn render_edit_prediction_popover_keystroke(
10011        &self,
10012        keystroke: &gpui::KeybindingKeystroke,
10013        color: Color,
10014        cx: &App,
10015    ) -> AnyElement {
10016        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10017
10018        if keystroke.modifiers().modified() {
10019            h_flex()
10020                .font(
10021                    theme_settings::ThemeSettings::get_global(cx)
10022                        .buffer_font
10023                        .clone(),
10024                )
10025                .when(is_platform_style_mac, |parent| parent.gap_1())
10026                .child(h_flex().children(ui::render_modifiers(
10027                    keystroke.modifiers(),
10028                    PlatformStyle::platform(),
10029                    Some(color),
10030                    None,
10031                    false,
10032                )))
10033                .into_any()
10034        } else {
10035            Key::new(ui::utils::capitalize(keystroke.key()), Some(color))
10036                .size(Some(IconSize::XSmall.rems().into()))
10037                .into_any_element()
10038        }
10039    }
10040
10041    fn render_edit_prediction_keybind(
10042        &self,
10043        window: &mut Window,
10044        cx: &mut App,
10045    ) -> Option<AnyElement> {
10046        let keybind_display =
10047            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
10048        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
10049
10050        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
10051            Color::Accent
10052        } else {
10053            Color::Muted
10054        };
10055
10056        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
10057    }
10058
10059    fn render_edit_prediction_line_popover(
10060        &self,
10061        label: impl Into<SharedString>,
10062        icon: Option<IconName>,
10063        window: &mut Window,
10064        cx: &mut App,
10065    ) -> Stateful<Div> {
10066        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10067
10068        let keybind = self.render_edit_prediction_keybind(window, cx);
10069        let has_keybind = keybind.is_some();
10070        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10071
10072        h_flex()
10073            .id("ep-line-popover")
10074            .py_0p5()
10075            .pl_1()
10076            .pr(padding_right)
10077            .gap_1()
10078            .rounded_md()
10079            .border_1()
10080            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10081            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10082            .shadow_xs()
10083            .when(!has_keybind, |el| {
10084                let status_colors = cx.theme().status();
10085
10086                el.bg(status_colors.error_background)
10087                    .border_color(status_colors.error.opacity(0.6))
10088                    .pl_2()
10089                    .child(Icon::new(icons.error).color(Color::Error))
10090                    .cursor_default()
10091                    .hoverable_tooltip(move |_window, cx| {
10092                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10093                    })
10094            })
10095            .children(keybind)
10096            .child(
10097                Label::new(label)
10098                    .size(LabelSize::Small)
10099                    .when(!has_keybind, |el| {
10100                        el.color(cx.theme().status().error.into()).strikethrough()
10101                    }),
10102            )
10103            .when(!has_keybind, |el| {
10104                el.child(
10105                    h_flex().ml_1().child(
10106                        Icon::new(IconName::Info)
10107                            .size(IconSize::Small)
10108                            .color(cx.theme().status().error.into()),
10109                    ),
10110                )
10111            })
10112            .when_some(icon, |element, icon| {
10113                element.child(
10114                    div()
10115                        .mt(px(1.5))
10116                        .child(Icon::new(icon).size(IconSize::Small)),
10117                )
10118            })
10119    }
10120
10121    fn render_edit_prediction_jump_outside_popover(
10122        &self,
10123        snapshot: &BufferSnapshot,
10124        window: &mut Window,
10125        cx: &mut App,
10126    ) -> Stateful<Div> {
10127        let keybind = self.render_edit_prediction_keybind(window, cx);
10128        let has_keybind = keybind.is_some();
10129        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10130
10131        let file_name = snapshot
10132            .file()
10133            .map(|file| SharedString::new(file.file_name(cx)))
10134            .unwrap_or(SharedString::new_static("untitled"));
10135
10136        h_flex()
10137            .id("ep-jump-outside-popover")
10138            .py_1()
10139            .px_2()
10140            .gap_1()
10141            .rounded_md()
10142            .border_1()
10143            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10144            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10145            .shadow_xs()
10146            .when(!has_keybind, |el| {
10147                let status_colors = cx.theme().status();
10148
10149                el.bg(status_colors.error_background)
10150                    .border_color(status_colors.error.opacity(0.6))
10151                    .pl_2()
10152                    .child(Icon::new(icons.error).color(Color::Error))
10153                    .cursor_default()
10154                    .hoverable_tooltip(move |_window, cx| {
10155                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10156                    })
10157            })
10158            .children(keybind)
10159            .child(
10160                Label::new(file_name)
10161                    .size(LabelSize::Small)
10162                    .buffer_font(cx)
10163                    .when(!has_keybind, |el| {
10164                        el.color(cx.theme().status().error.into()).strikethrough()
10165                    }),
10166            )
10167            .when(!has_keybind, |el| {
10168                el.child(
10169                    h_flex().ml_1().child(
10170                        Icon::new(IconName::Info)
10171                            .size(IconSize::Small)
10172                            .color(cx.theme().status().error.into()),
10173                    ),
10174                )
10175            })
10176            .child(
10177                div()
10178                    .mt(px(1.5))
10179                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10180            )
10181    }
10182
10183    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10184        let accent_color = cx.theme().colors().text_accent;
10185        let editor_bg_color = cx.theme().colors().editor_background;
10186        editor_bg_color.blend(accent_color.opacity(0.1))
10187    }
10188
10189    fn edit_prediction_callout_popover_border_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.6))
10193    }
10194    fn get_prediction_provider_icons(
10195        provider: &Option<RegisteredEditPredictionDelegate>,
10196        cx: &App,
10197    ) -> edit_prediction_types::EditPredictionIconSet {
10198        match provider {
10199            Some(provider) => provider.provider.icons(cx),
10200            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10201        }
10202    }
10203
10204    fn render_edit_prediction_cursor_popover(
10205        &self,
10206        min_width: Pixels,
10207        max_width: Pixels,
10208        cursor_point: Point,
10209        style: &EditorStyle,
10210        window: &mut Window,
10211        cx: &mut Context<Editor>,
10212    ) -> Option<AnyElement> {
10213        let provider = self.edit_prediction_provider.as_ref()?;
10214        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10215
10216        let is_refreshing = provider.provider.is_refreshing(cx);
10217
10218        fn pending_completion_container(icon: IconName) -> Div {
10219            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10220        }
10221
10222        let completion = match &self.active_edit_prediction {
10223            Some(prediction) => {
10224                if !self.has_visible_completions_menu() {
10225                    const RADIUS: Pixels = px(6.);
10226                    const BORDER_WIDTH: Pixels = px(1.);
10227                    let keybind_display = self.edit_prediction_keybind_display(
10228                        EditPredictionKeybindSurface::CursorPopoverCompact,
10229                        window,
10230                        cx,
10231                    );
10232
10233                    return Some(
10234                        h_flex()
10235                            .elevation_2(cx)
10236                            .border(BORDER_WIDTH)
10237                            .border_color(cx.theme().colors().border)
10238                            .when(keybind_display.missing_accept_keystroke, |el| {
10239                                el.border_color(cx.theme().status().error)
10240                            })
10241                            .rounded(RADIUS)
10242                            .rounded_tl(px(0.))
10243                            .overflow_hidden()
10244                            .child(div().px_1p5().child(match &prediction.completion {
10245                                EditPrediction::MoveWithin { target, snapshot } => {
10246                                    use text::ToPoint as _;
10247                                    if target.text_anchor_in(&snapshot).to_point(snapshot).row
10248                                        > cursor_point.row
10249                                    {
10250                                        Icon::new(icons.down)
10251                                    } else {
10252                                        Icon::new(icons.up)
10253                                    }
10254                                }
10255                                EditPrediction::MoveOutside { .. } => {
10256                                    // TODO [zeta2] custom icon for external jump?
10257                                    Icon::new(icons.base)
10258                                }
10259                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10260                            }))
10261                            .child(
10262                                h_flex()
10263                                    .gap_1()
10264                                    .py_1()
10265                                    .px_2()
10266                                    .rounded_r(RADIUS - BORDER_WIDTH)
10267                                    .border_l_1()
10268                                    .border_color(cx.theme().colors().border)
10269                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10270                                    .when(keybind_display.show_hold_label, |el| {
10271                                        el.child(
10272                                            Label::new("Hold")
10273                                                .size(LabelSize::Small)
10274                                                .when(
10275                                                    keybind_display.missing_accept_keystroke,
10276                                                    |el| el.strikethrough(),
10277                                                )
10278                                                .line_height_style(LineHeightStyle::UiLabel),
10279                                        )
10280                                    })
10281                                    .id("edit_prediction_cursor_popover_keybind")
10282                                    .when(keybind_display.missing_accept_keystroke, |el| {
10283                                        let status_colors = cx.theme().status();
10284
10285                                        el.bg(status_colors.error_background)
10286                                            .border_color(status_colors.error.opacity(0.6))
10287                                            .child(Icon::new(IconName::Info).color(Color::Error))
10288                                            .cursor_default()
10289                                            .hoverable_tooltip(move |_window, cx| {
10290                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10291                                                    .into()
10292                                            })
10293                                    })
10294                                    .when_some(
10295                                        keybind_display.displayed_keystroke.as_ref(),
10296                                        |el, compact_keystroke| {
10297                                            el.child(self.render_edit_prediction_popover_keystroke(
10298                                                compact_keystroke,
10299                                                Color::Default,
10300                                                cx,
10301                                            ))
10302                                        },
10303                                    ),
10304                            )
10305                            .into_any(),
10306                    );
10307                }
10308
10309                self.render_edit_prediction_cursor_popover_preview(
10310                    prediction,
10311                    cursor_point,
10312                    style,
10313                    cx,
10314                )?
10315            }
10316
10317            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10318                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10319                    stale_completion,
10320                    cursor_point,
10321                    style,
10322                    cx,
10323                )?,
10324
10325                None => pending_completion_container(icons.base)
10326                    .child(Label::new("...").size(LabelSize::Small)),
10327            },
10328
10329            None => pending_completion_container(icons.base)
10330                .child(Label::new("...").size(LabelSize::Small)),
10331        };
10332
10333        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10334            completion
10335                .with_animation(
10336                    "loading-completion",
10337                    Animation::new(Duration::from_secs(2))
10338                        .repeat()
10339                        .with_easing(pulsating_between(0.4, 0.8)),
10340                    |label, delta| label.opacity(delta),
10341                )
10342                .into_any_element()
10343        } else {
10344            completion.into_any_element()
10345        };
10346
10347        let has_completion = self.active_edit_prediction.is_some();
10348        let keybind_display = self.edit_prediction_keybind_display(
10349            EditPredictionKeybindSurface::CursorPopoverExpanded,
10350            window,
10351            cx,
10352        );
10353
10354        Some(
10355            h_flex()
10356                .min_w(min_width)
10357                .max_w(max_width)
10358                .flex_1()
10359                .elevation_2(cx)
10360                .border_color(cx.theme().colors().border)
10361                .child(
10362                    div()
10363                        .flex_1()
10364                        .py_1()
10365                        .px_2()
10366                        .overflow_hidden()
10367                        .child(completion),
10368                )
10369                .when_some(
10370                    keybind_display.displayed_keystroke.as_ref(),
10371                    |el, keystroke| {
10372                        let key_color = if !has_completion {
10373                            Color::Muted
10374                        } else {
10375                            Color::Default
10376                        };
10377
10378                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10379                            el.child(
10380                                h_flex()
10381                                    .h_full()
10382                                    .border_l_1()
10383                                    .rounded_r_lg()
10384                                    .border_color(cx.theme().colors().border)
10385                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10386                                    .gap_1()
10387                                    .py_1()
10388                                    .px_2()
10389                                    .child(self.render_edit_prediction_popover_keystroke(
10390                                        keystroke, key_color, cx,
10391                                    ))
10392                                    .child(Label::new("Preview").into_any_element())
10393                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10394                            )
10395                        } else {
10396                            el.child(
10397                                h_flex()
10398                                    .h_full()
10399                                    .border_l_1()
10400                                    .rounded_r_lg()
10401                                    .border_color(cx.theme().colors().border)
10402                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10403                                    .gap_1()
10404                                    .py_1()
10405                                    .px_2()
10406                                    .child(self.render_edit_prediction_popover_keystroke(
10407                                        keystroke, key_color, cx,
10408                                    ))
10409                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10410                            )
10411                        }
10412                    },
10413                )
10414                .into_any(),
10415        )
10416    }
10417
10418    fn render_edit_prediction_cursor_popover_preview(
10419        &self,
10420        completion: &EditPredictionState,
10421        cursor_point: Point,
10422        style: &EditorStyle,
10423        cx: &mut Context<Editor>,
10424    ) -> Option<Div> {
10425        use text::ToPoint as _;
10426
10427        fn render_relative_row_jump(
10428            prefix: impl Into<String>,
10429            current_row: u32,
10430            target_row: u32,
10431        ) -> Div {
10432            let (row_diff, arrow) = if target_row < current_row {
10433                (current_row - target_row, IconName::ArrowUp)
10434            } else {
10435                (target_row - current_row, IconName::ArrowDown)
10436            };
10437
10438            h_flex()
10439                .child(
10440                    Label::new(format!("{}{}", prefix.into(), row_diff))
10441                        .color(Color::Muted)
10442                        .size(LabelSize::Small),
10443                )
10444                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10445        }
10446
10447        let supports_jump = self
10448            .edit_prediction_provider
10449            .as_ref()
10450            .map(|provider| provider.provider.supports_jump_to_edit())
10451            .unwrap_or(true);
10452
10453        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10454
10455        match &completion.completion {
10456            EditPrediction::MoveWithin {
10457                target, snapshot, ..
10458            } => {
10459                if !supports_jump {
10460                    return None;
10461                }
10462                let (target, _) = self.display_snapshot(cx).anchor_to_buffer_anchor(*target)?;
10463
10464                Some(
10465                    h_flex()
10466                        .px_2()
10467                        .gap_2()
10468                        .flex_1()
10469                        .child(if target.to_point(snapshot).row > cursor_point.row {
10470                            Icon::new(icons.down)
10471                        } else {
10472                            Icon::new(icons.up)
10473                        })
10474                        .child(Label::new("Jump to Edit")),
10475                )
10476            }
10477            EditPrediction::MoveOutside { snapshot, .. } => {
10478                let file_name = snapshot
10479                    .file()
10480                    .map(|file| file.file_name(cx))
10481                    .unwrap_or("untitled");
10482                Some(
10483                    h_flex()
10484                        .px_2()
10485                        .gap_2()
10486                        .flex_1()
10487                        .child(Icon::new(icons.base))
10488                        .child(Label::new(format!("Jump to {file_name}"))),
10489                )
10490            }
10491            EditPrediction::Edit {
10492                edits,
10493                edit_preview,
10494                snapshot,
10495                ..
10496            } => {
10497                let first_edit_row = self
10498                    .display_snapshot(cx)
10499                    .anchor_to_buffer_anchor(edits.first()?.0.start)?
10500                    .0
10501                    .to_point(snapshot)
10502                    .row;
10503
10504                let (highlighted_edits, has_more_lines) =
10505                    if let Some(edit_preview) = edit_preview.as_ref() {
10506                        crate::edit_prediction_edit_text(
10507                            snapshot,
10508                            edits,
10509                            edit_preview,
10510                            true,
10511                            &self.display_snapshot(cx),
10512                            cx,
10513                        )
10514                        .first_line_preview()
10515                    } else {
10516                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10517                    };
10518
10519                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10520                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10521
10522                let preview = h_flex()
10523                    .gap_1()
10524                    .min_w_16()
10525                    .child(styled_text)
10526                    .when(has_more_lines, |parent| parent.child(""));
10527
10528                let left = if supports_jump && first_edit_row != cursor_point.row {
10529                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10530                        .into_any_element()
10531                } else {
10532                    Icon::new(icons.base).into_any_element()
10533                };
10534
10535                Some(
10536                    h_flex()
10537                        .h_full()
10538                        .flex_1()
10539                        .gap_2()
10540                        .pr_1()
10541                        .overflow_x_hidden()
10542                        .font(
10543                            theme_settings::ThemeSettings::get_global(cx)
10544                                .buffer_font
10545                                .clone(),
10546                        )
10547                        .child(left)
10548                        .child(preview),
10549                )
10550            }
10551        }
10552    }
10553
10554    pub fn render_context_menu(
10555        &mut self,
10556        max_height_in_lines: u32,
10557        window: &mut Window,
10558        cx: &mut Context<Editor>,
10559    ) -> Option<AnyElement> {
10560        let menu = self.context_menu.borrow();
10561        let menu = menu.as_ref()?;
10562        if !menu.visible() {
10563            return None;
10564        };
10565        self.style
10566            .as_ref()
10567            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10568    }
10569
10570    fn render_context_menu_aside(
10571        &mut self,
10572        max_size: Size<Pixels>,
10573        window: &mut Window,
10574        cx: &mut Context<Editor>,
10575    ) -> Option<AnyElement> {
10576        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10577            if menu.visible() {
10578                menu.render_aside(max_size, window, cx)
10579            } else {
10580                None
10581            }
10582        })
10583    }
10584
10585    fn hide_context_menu(
10586        &mut self,
10587        window: &mut Window,
10588        cx: &mut Context<Self>,
10589    ) -> Option<CodeContextMenu> {
10590        cx.notify();
10591        self.completion_tasks.clear();
10592        let context_menu = self.context_menu.borrow_mut().take();
10593        self.stale_edit_prediction_in_menu.take();
10594        self.update_visible_edit_prediction(window, cx);
10595        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10596            && let Some(completion_provider) = &self.completion_provider
10597        {
10598            completion_provider.selection_changed(None, window, cx);
10599        }
10600        context_menu
10601    }
10602
10603    fn show_snippet_choices(
10604        &mut self,
10605        choices: &Vec<String>,
10606        selection: Range<Anchor>,
10607        cx: &mut Context<Self>,
10608    ) {
10609        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
10610        let Some((buffer_snapshot, range)) =
10611            buffer_snapshot.anchor_range_to_buffer_anchor_range(selection.clone())
10612        else {
10613            return;
10614        };
10615        let Some(buffer) = self.buffer.read(cx).buffer(buffer_snapshot.remote_id()) else {
10616            return;
10617        };
10618
10619        let id = post_inc(&mut self.next_completion_id);
10620        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10621        let mut context_menu = self.context_menu.borrow_mut();
10622        let old_menu = context_menu.take();
10623        *context_menu = Some(CodeContextMenu::Completions(
10624            CompletionsMenu::new_snippet_choices(
10625                id,
10626                true,
10627                choices,
10628                selection.start,
10629                range,
10630                buffer,
10631                old_menu.map(|menu| menu.primary_scroll_handle()),
10632                snippet_sort_order,
10633            ),
10634        ));
10635    }
10636
10637    pub fn insert_snippet(
10638        &mut self,
10639        insertion_ranges: &[Range<MultiBufferOffset>],
10640        snippet: Snippet,
10641        window: &mut Window,
10642        cx: &mut Context<Self>,
10643    ) -> Result<()> {
10644        struct Tabstop<T> {
10645            is_end_tabstop: bool,
10646            ranges: Vec<Range<T>>,
10647            choices: Option<Vec<String>>,
10648        }
10649
10650        let tabstops = self.buffer.update(cx, |buffer, cx| {
10651            let snippet_text: Arc<str> = snippet.text.clone().into();
10652            let edits = insertion_ranges
10653                .iter()
10654                .cloned()
10655                .map(|range| (range, snippet_text.clone()));
10656            let autoindent_mode = AutoindentMode::Block {
10657                original_indent_columns: Vec::new(),
10658            };
10659            buffer.edit(edits, Some(autoindent_mode), cx);
10660
10661            let snapshot = &*buffer.read(cx);
10662            let snippet = &snippet;
10663            snippet
10664                .tabstops
10665                .iter()
10666                .map(|tabstop| {
10667                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10668                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10669                    });
10670                    let mut tabstop_ranges = tabstop
10671                        .ranges
10672                        .iter()
10673                        .flat_map(|tabstop_range| {
10674                            let mut delta = 0_isize;
10675                            insertion_ranges.iter().map(move |insertion_range| {
10676                                let insertion_start = insertion_range.start + delta;
10677                                delta += snippet.text.len() as isize
10678                                    - (insertion_range.end - insertion_range.start) as isize;
10679
10680                                let start =
10681                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10682                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10683                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10684                            })
10685                        })
10686                        .collect::<Vec<_>>();
10687                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10688
10689                    Tabstop {
10690                        is_end_tabstop,
10691                        ranges: tabstop_ranges,
10692                        choices: tabstop.choices.clone(),
10693                    }
10694                })
10695                .collect::<Vec<_>>()
10696        });
10697        if let Some(tabstop) = tabstops.first() {
10698            self.change_selections(Default::default(), window, cx, |s| {
10699                // Reverse order so that the first range is the newest created selection.
10700                // Completions will use it and autoscroll will prioritize it.
10701                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10702            });
10703
10704            if let Some(choices) = &tabstop.choices
10705                && let Some(selection) = tabstop.ranges.first()
10706            {
10707                self.show_snippet_choices(choices, selection.clone(), cx)
10708            }
10709
10710            // If we're already at the last tabstop and it's at the end of the snippet,
10711            // we're done, we don't need to keep the state around.
10712            if !tabstop.is_end_tabstop {
10713                let choices = tabstops
10714                    .iter()
10715                    .map(|tabstop| tabstop.choices.clone())
10716                    .collect();
10717
10718                let ranges = tabstops
10719                    .into_iter()
10720                    .map(|tabstop| tabstop.ranges)
10721                    .collect::<Vec<_>>();
10722
10723                self.snippet_stack.push(SnippetState {
10724                    active_index: 0,
10725                    ranges,
10726                    choices,
10727                });
10728            }
10729
10730            // Check whether the just-entered snippet ends with an auto-closable bracket.
10731            if self.autoclose_regions.is_empty() {
10732                let snapshot = self.buffer.read(cx).snapshot(cx);
10733                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10734                    let selection_head = selection.head();
10735                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10736                        continue;
10737                    };
10738
10739                    let mut bracket_pair = None;
10740                    let max_lookup_length = scope
10741                        .brackets()
10742                        .map(|(pair, _)| {
10743                            pair.start
10744                                .as_str()
10745                                .chars()
10746                                .count()
10747                                .max(pair.end.as_str().chars().count())
10748                        })
10749                        .max();
10750                    if let Some(max_lookup_length) = max_lookup_length {
10751                        let next_text = snapshot
10752                            .chars_at(selection_head)
10753                            .take(max_lookup_length)
10754                            .collect::<String>();
10755                        let prev_text = snapshot
10756                            .reversed_chars_at(selection_head)
10757                            .take(max_lookup_length)
10758                            .collect::<String>();
10759
10760                        for (pair, enabled) in scope.brackets() {
10761                            if enabled
10762                                && pair.close
10763                                && prev_text.starts_with(pair.start.as_str())
10764                                && next_text.starts_with(pair.end.as_str())
10765                            {
10766                                bracket_pair = Some(pair.clone());
10767                                break;
10768                            }
10769                        }
10770                    }
10771
10772                    if let Some(pair) = bracket_pair {
10773                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10774                        let autoclose_enabled =
10775                            self.use_autoclose && snapshot_settings.use_autoclose;
10776                        if autoclose_enabled {
10777                            let start = snapshot.anchor_after(selection_head);
10778                            let end = snapshot.anchor_after(selection_head);
10779                            self.autoclose_regions.push(AutocloseRegion {
10780                                selection_id: selection.id,
10781                                range: start..end,
10782                                pair,
10783                            });
10784                        }
10785                    }
10786                }
10787            }
10788        }
10789        Ok(())
10790    }
10791
10792    pub fn move_to_next_snippet_tabstop(
10793        &mut self,
10794        window: &mut Window,
10795        cx: &mut Context<Self>,
10796    ) -> bool {
10797        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10798    }
10799
10800    pub fn move_to_prev_snippet_tabstop(
10801        &mut self,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) -> bool {
10805        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10806    }
10807
10808    pub fn move_to_snippet_tabstop(
10809        &mut self,
10810        bias: Bias,
10811        window: &mut Window,
10812        cx: &mut Context<Self>,
10813    ) -> bool {
10814        if let Some(mut snippet) = self.snippet_stack.pop() {
10815            match bias {
10816                Bias::Left => {
10817                    if snippet.active_index > 0 {
10818                        snippet.active_index -= 1;
10819                    } else {
10820                        self.snippet_stack.push(snippet);
10821                        return false;
10822                    }
10823                }
10824                Bias::Right => {
10825                    if snippet.active_index + 1 < snippet.ranges.len() {
10826                        snippet.active_index += 1;
10827                    } else {
10828                        self.snippet_stack.push(snippet);
10829                        return false;
10830                    }
10831                }
10832            }
10833            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10834                self.change_selections(Default::default(), window, cx, |s| {
10835                    // Reverse order so that the first range is the newest created selection.
10836                    // Completions will use it and autoscroll will prioritize it.
10837                    s.select_ranges(current_ranges.iter().rev().cloned())
10838                });
10839
10840                if let Some(choices) = &snippet.choices[snippet.active_index]
10841                    && let Some(selection) = current_ranges.first()
10842                {
10843                    self.show_snippet_choices(choices, selection.clone(), cx);
10844                }
10845
10846                // If snippet state is not at the last tabstop, push it back on the stack
10847                if snippet.active_index + 1 < snippet.ranges.len() {
10848                    self.snippet_stack.push(snippet);
10849                }
10850                return true;
10851            }
10852        }
10853
10854        false
10855    }
10856
10857    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10858        self.transact(window, cx, |this, window, cx| {
10859            this.select_all(&SelectAll, window, cx);
10860            this.insert("", window, cx);
10861        });
10862    }
10863
10864    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10865        if self.read_only(cx) {
10866            return;
10867        }
10868        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10869        self.transact(window, cx, |this, window, cx| {
10870            this.select_autoclose_pair(window, cx);
10871
10872            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10873
10874            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10875            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10876            for selection in &mut selections {
10877                if selection.is_empty() {
10878                    let old_head = selection.head();
10879                    let mut new_head =
10880                        movement::left(&display_map, old_head.to_display_point(&display_map))
10881                            .to_point(&display_map);
10882                    if let Some((buffer, line_buffer_range)) = display_map
10883                        .buffer_snapshot()
10884                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10885                    {
10886                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10887                        let indent_len = match indent_size.kind {
10888                            IndentKind::Space => {
10889                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10890                            }
10891                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10892                        };
10893                        if old_head.column <= indent_size.len && old_head.column > 0 {
10894                            let indent_len = indent_len.get();
10895                            new_head = cmp::min(
10896                                new_head,
10897                                MultiBufferPoint::new(
10898                                    old_head.row,
10899                                    ((old_head.column - 1) / indent_len) * indent_len,
10900                                ),
10901                            );
10902                        }
10903                    }
10904
10905                    selection.set_head(new_head, SelectionGoal::None);
10906                }
10907            }
10908
10909            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10910            this.insert("", window, cx);
10911            linked_edits.apply_with_left_expansion(cx);
10912            this.refresh_edit_prediction(true, false, window, cx);
10913            refresh_linked_ranges(this, window, cx);
10914        });
10915    }
10916
10917    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10918        if self.read_only(cx) {
10919            return;
10920        }
10921        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10922        self.transact(window, cx, |this, window, cx| {
10923            this.change_selections(Default::default(), window, cx, |s| {
10924                s.move_with(&mut |map, selection| {
10925                    if selection.is_empty() {
10926                        let cursor = movement::right(map, selection.head());
10927                        selection.end = cursor;
10928                        selection.reversed = true;
10929                        selection.goal = SelectionGoal::None;
10930                    }
10931                })
10932            });
10933            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10934            this.insert("", window, cx);
10935            linked_edits.apply(cx);
10936            this.refresh_edit_prediction(true, false, window, cx);
10937            refresh_linked_ranges(this, window, cx);
10938        });
10939    }
10940
10941    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10942        if self.mode.is_single_line() {
10943            cx.propagate();
10944            return;
10945        }
10946
10947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10948        if self.move_to_prev_snippet_tabstop(window, cx) {
10949            return;
10950        }
10951        self.outdent(&Outdent, window, cx);
10952    }
10953
10954    pub fn next_snippet_tabstop(
10955        &mut self,
10956        _: &NextSnippetTabstop,
10957        window: &mut Window,
10958        cx: &mut Context<Self>,
10959    ) {
10960        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10961            cx.propagate();
10962            return;
10963        }
10964
10965        if self.move_to_next_snippet_tabstop(window, cx) {
10966            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10967            return;
10968        }
10969        cx.propagate();
10970    }
10971
10972    pub fn previous_snippet_tabstop(
10973        &mut self,
10974        _: &PreviousSnippetTabstop,
10975        window: &mut Window,
10976        cx: &mut Context<Self>,
10977    ) {
10978        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10979            cx.propagate();
10980            return;
10981        }
10982
10983        if self.move_to_prev_snippet_tabstop(window, cx) {
10984            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10985            return;
10986        }
10987        cx.propagate();
10988    }
10989
10990    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10991        if self.mode.is_single_line() {
10992            cx.propagate();
10993            return;
10994        }
10995
10996        if self.move_to_next_snippet_tabstop(window, cx) {
10997            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10998            return;
10999        }
11000        if self.read_only(cx) {
11001            return;
11002        }
11003        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11004        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
11005        let buffer = self.buffer.read(cx);
11006        let snapshot = buffer.snapshot(cx);
11007        let rows_iter = selections.iter().map(|s| s.head().row);
11008        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
11009
11010        let has_some_cursor_in_whitespace = selections
11011            .iter()
11012            .filter(|selection| selection.is_empty())
11013            .any(|selection| {
11014                let cursor = selection.head();
11015                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11016                cursor.column < current_indent.len
11017            });
11018
11019        let mut edits = Vec::new();
11020        let mut prev_edited_row = 0;
11021        let mut row_delta = 0;
11022        for selection in &mut selections {
11023            if selection.start.row != prev_edited_row {
11024                row_delta = 0;
11025            }
11026            prev_edited_row = selection.end.row;
11027
11028            // If cursor is after a list prefix, make selection non-empty to trigger line indent
11029            if selection.is_empty() {
11030                let cursor = selection.head();
11031                let settings = buffer.language_settings_at(cursor, cx);
11032                if settings.indent_list_on_tab {
11033                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
11034                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
11035                            row_delta = Self::indent_selection(
11036                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
11037                            );
11038                            continue;
11039                        }
11040                    }
11041                }
11042            }
11043
11044            // If the selection is non-empty, then increase the indentation of the selected lines.
11045            if !selection.is_empty() {
11046                row_delta =
11047                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11048                continue;
11049            }
11050
11051            let cursor = selection.head();
11052            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11053            if let Some(suggested_indent) =
11054                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
11055            {
11056                // Don't do anything if already at suggested indent
11057                // and there is any other cursor which is not
11058                if has_some_cursor_in_whitespace
11059                    && cursor.column == current_indent.len
11060                    && current_indent.len == suggested_indent.len
11061                {
11062                    continue;
11063                }
11064
11065                // Adjust line and move cursor to suggested indent
11066                // if cursor is not at suggested indent
11067                if cursor.column < suggested_indent.len
11068                    && cursor.column <= current_indent.len
11069                    && current_indent.len <= suggested_indent.len
11070                {
11071                    selection.start = Point::new(cursor.row, suggested_indent.len);
11072                    selection.end = selection.start;
11073                    if row_delta == 0 {
11074                        edits.extend(Buffer::edit_for_indent_size_adjustment(
11075                            cursor.row,
11076                            current_indent,
11077                            suggested_indent,
11078                        ));
11079                        row_delta = suggested_indent.len - current_indent.len;
11080                    }
11081                    continue;
11082                }
11083
11084                // If current indent is more than suggested indent
11085                // only move cursor to current indent and skip indent
11086                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11087                    selection.start = Point::new(cursor.row, current_indent.len);
11088                    selection.end = selection.start;
11089                    continue;
11090                }
11091            }
11092
11093            // Otherwise, insert a hard or soft tab.
11094            let settings = buffer.language_settings_at(cursor, cx);
11095            let tab_size = if settings.hard_tabs {
11096                IndentSize::tab()
11097            } else {
11098                let tab_size = settings.tab_size.get();
11099                let indent_remainder = snapshot
11100                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11101                    .flat_map(str::chars)
11102                    .fold(row_delta % tab_size, |counter: u32, c| {
11103                        if c == '\t' {
11104                            0
11105                        } else {
11106                            (counter + 1) % tab_size
11107                        }
11108                    });
11109
11110                let chars_to_next_tab_stop = tab_size - indent_remainder;
11111                IndentSize::spaces(chars_to_next_tab_stop)
11112            };
11113            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11114            selection.end = selection.start;
11115            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11116            row_delta += tab_size.len;
11117        }
11118
11119        self.transact(window, cx, |this, window, cx| {
11120            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11121            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11122            this.refresh_edit_prediction(true, false, window, cx);
11123        });
11124    }
11125
11126    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11127        if self.read_only(cx) {
11128            return;
11129        }
11130        if self.mode.is_single_line() {
11131            cx.propagate();
11132            return;
11133        }
11134
11135        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11136        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11137        let mut prev_edited_row = 0;
11138        let mut row_delta = 0;
11139        let mut edits = Vec::new();
11140        let buffer = self.buffer.read(cx);
11141        let snapshot = buffer.snapshot(cx);
11142        for selection in &mut selections {
11143            if selection.start.row != prev_edited_row {
11144                row_delta = 0;
11145            }
11146            prev_edited_row = selection.end.row;
11147
11148            row_delta =
11149                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11150        }
11151
11152        self.transact(window, cx, |this, window, cx| {
11153            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11154            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11155        });
11156    }
11157
11158    fn indent_selection(
11159        buffer: &MultiBuffer,
11160        snapshot: &MultiBufferSnapshot,
11161        selection: &mut Selection<Point>,
11162        edits: &mut Vec<(Range<Point>, String)>,
11163        delta_for_start_row: u32,
11164        cx: &App,
11165    ) -> u32 {
11166        let settings = buffer.language_settings_at(selection.start, cx);
11167        let tab_size = settings.tab_size.get();
11168        let indent_kind = if settings.hard_tabs {
11169            IndentKind::Tab
11170        } else {
11171            IndentKind::Space
11172        };
11173        let mut start_row = selection.start.row;
11174        let mut end_row = selection.end.row + 1;
11175
11176        // If a selection ends at the beginning of a line, don't indent
11177        // that last line.
11178        if selection.end.column == 0 && selection.end.row > selection.start.row {
11179            end_row -= 1;
11180        }
11181
11182        // Avoid re-indenting a row that has already been indented by a
11183        // previous selection, but still update this selection's column
11184        // to reflect that indentation.
11185        if delta_for_start_row > 0 {
11186            start_row += 1;
11187            selection.start.column += delta_for_start_row;
11188            if selection.end.row == selection.start.row {
11189                selection.end.column += delta_for_start_row;
11190            }
11191        }
11192
11193        let mut delta_for_end_row = 0;
11194        let has_multiple_rows = start_row + 1 != end_row;
11195        for row in start_row..end_row {
11196            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11197            let indent_delta = match (current_indent.kind, indent_kind) {
11198                (IndentKind::Space, IndentKind::Space) => {
11199                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11200                    IndentSize::spaces(columns_to_next_tab_stop)
11201                }
11202                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11203                (_, IndentKind::Tab) => IndentSize::tab(),
11204            };
11205
11206            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11207                0
11208            } else {
11209                selection.start.column
11210            };
11211            let row_start = Point::new(row, start);
11212            edits.push((
11213                row_start..row_start,
11214                indent_delta.chars().collect::<String>(),
11215            ));
11216
11217            // Update this selection's endpoints to reflect the indentation.
11218            if row == selection.start.row {
11219                selection.start.column += indent_delta.len;
11220            }
11221            if row == selection.end.row {
11222                selection.end.column += indent_delta.len;
11223                delta_for_end_row = indent_delta.len;
11224            }
11225        }
11226
11227        if selection.start.row == selection.end.row {
11228            delta_for_start_row + delta_for_end_row
11229        } else {
11230            delta_for_end_row
11231        }
11232    }
11233
11234    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11235        if self.read_only(cx) {
11236            return;
11237        }
11238        if self.mode.is_single_line() {
11239            cx.propagate();
11240            return;
11241        }
11242
11243        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11244        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11245        let selections = self.selections.all::<Point>(&display_map);
11246        let mut deletion_ranges = Vec::new();
11247        let mut last_outdent = None;
11248        {
11249            let buffer = self.buffer.read(cx);
11250            let snapshot = buffer.snapshot(cx);
11251            for selection in &selections {
11252                let settings = buffer.language_settings_at(selection.start, cx);
11253                let tab_size = settings.tab_size.get();
11254                let mut rows = selection.spanned_rows(false, &display_map);
11255
11256                // Avoid re-outdenting a row that has already been outdented by a
11257                // previous selection.
11258                if let Some(last_row) = last_outdent
11259                    && last_row == rows.start
11260                {
11261                    rows.start = rows.start.next_row();
11262                }
11263                let has_multiple_rows = rows.len() > 1;
11264                for row in rows.iter_rows() {
11265                    let indent_size = snapshot.indent_size_for_line(row);
11266                    if indent_size.len > 0 {
11267                        let deletion_len = match indent_size.kind {
11268                            IndentKind::Space => {
11269                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11270                                if columns_to_prev_tab_stop == 0 {
11271                                    tab_size
11272                                } else {
11273                                    columns_to_prev_tab_stop
11274                                }
11275                            }
11276                            IndentKind::Tab => 1,
11277                        };
11278                        let start = if has_multiple_rows
11279                            || deletion_len > selection.start.column
11280                            || indent_size.len < selection.start.column
11281                        {
11282                            0
11283                        } else {
11284                            selection.start.column - deletion_len
11285                        };
11286                        deletion_ranges.push(
11287                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11288                        );
11289                        last_outdent = Some(row);
11290                    }
11291                }
11292            }
11293        }
11294
11295        self.transact(window, cx, |this, window, cx| {
11296            this.buffer.update(cx, |buffer, cx| {
11297                let empty_str: Arc<str> = Arc::default();
11298                buffer.edit(
11299                    deletion_ranges
11300                        .into_iter()
11301                        .map(|range| (range, empty_str.clone())),
11302                    None,
11303                    cx,
11304                );
11305            });
11306            let selections = this
11307                .selections
11308                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11309            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11310        });
11311    }
11312
11313    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11314        if self.read_only(cx) {
11315            return;
11316        }
11317        if self.mode.is_single_line() {
11318            cx.propagate();
11319            return;
11320        }
11321
11322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11323        let selections = self
11324            .selections
11325            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11326            .into_iter()
11327            .map(|s| s.range());
11328
11329        self.transact(window, cx, |this, window, cx| {
11330            this.buffer.update(cx, |buffer, cx| {
11331                buffer.autoindent_ranges(selections, cx);
11332            });
11333            let selections = this
11334                .selections
11335                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11336            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11337        });
11338    }
11339
11340    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11341        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11342        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11343        let selections = self.selections.all::<Point>(&display_map);
11344
11345        let mut new_cursors = Vec::new();
11346        let mut edit_ranges = Vec::new();
11347        let mut selections = selections.iter().peekable();
11348        while let Some(selection) = selections.next() {
11349            let mut rows = selection.spanned_rows(false, &display_map);
11350
11351            // Accumulate contiguous regions of rows that we want to delete.
11352            while let Some(next_selection) = selections.peek() {
11353                let next_rows = next_selection.spanned_rows(false, &display_map);
11354                if next_rows.start <= rows.end {
11355                    rows.end = next_rows.end;
11356                    selections.next().unwrap();
11357                } else {
11358                    break;
11359                }
11360            }
11361
11362            let buffer = display_map.buffer_snapshot();
11363            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11364            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11365                // If there's a line after the range, delete the \n from the end of the row range
11366                (
11367                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11368                    rows.end,
11369                )
11370            } else {
11371                // If there isn't a line after the range, delete the \n from the line before the
11372                // start of the row range
11373                edit_start = edit_start.saturating_sub_usize(1);
11374                (buffer.len(), rows.start.previous_row())
11375            };
11376
11377            let text_layout_details = self.text_layout_details(window, cx);
11378            let x = display_map.x_for_display_point(
11379                selection.head().to_display_point(&display_map),
11380                &text_layout_details,
11381            );
11382            let row = Point::new(target_row.0, 0)
11383                .to_display_point(&display_map)
11384                .row();
11385            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11386
11387            new_cursors.push((
11388                selection.id,
11389                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11390                SelectionGoal::None,
11391            ));
11392            edit_ranges.push(edit_start..edit_end);
11393        }
11394
11395        self.transact(window, cx, |this, window, cx| {
11396            let buffer = this.buffer.update(cx, |buffer, cx| {
11397                let empty_str: Arc<str> = Arc::default();
11398                buffer.edit(
11399                    edit_ranges
11400                        .into_iter()
11401                        .map(|range| (range, empty_str.clone())),
11402                    None,
11403                    cx,
11404                );
11405                buffer.snapshot(cx)
11406            });
11407            let new_selections = new_cursors
11408                .into_iter()
11409                .map(|(id, cursor, goal)| {
11410                    let cursor = cursor.to_point(&buffer);
11411                    Selection {
11412                        id,
11413                        start: cursor,
11414                        end: cursor,
11415                        reversed: false,
11416                        goal,
11417                    }
11418                })
11419                .collect();
11420
11421            this.change_selections(Default::default(), window, cx, |s| {
11422                s.select(new_selections);
11423            });
11424        });
11425    }
11426
11427    pub fn join_lines_impl(
11428        &mut self,
11429        insert_whitespace: bool,
11430        window: &mut Window,
11431        cx: &mut Context<Self>,
11432    ) {
11433        if self.read_only(cx) {
11434            return;
11435        }
11436        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11437        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11438            let start = MultiBufferRow(selection.start.row);
11439            // Treat single line selections as if they include the next line. Otherwise this action
11440            // would do nothing for single line selections individual cursors.
11441            let end = if selection.start.row == selection.end.row {
11442                MultiBufferRow(selection.start.row + 1)
11443            } else if selection.end.column == 0 {
11444                // If the selection ends at the start of a line, it's logically at the end of the
11445                // previous line (plus its newline).
11446                // Don't include the end line unless there's only one line selected.
11447                if selection.start.row + 1 == selection.end.row {
11448                    MultiBufferRow(selection.end.row)
11449                } else {
11450                    MultiBufferRow(selection.end.row - 1)
11451                }
11452            } else {
11453                MultiBufferRow(selection.end.row)
11454            };
11455
11456            if let Some(last_row_range) = row_ranges.last_mut()
11457                && start <= last_row_range.end
11458            {
11459                last_row_range.end = end;
11460                continue;
11461            }
11462            row_ranges.push(start..end);
11463        }
11464
11465        let snapshot = self.buffer.read(cx).snapshot(cx);
11466        let mut cursor_positions = Vec::new();
11467        for row_range in &row_ranges {
11468            let anchor = snapshot.anchor_before(Point::new(
11469                row_range.end.previous_row().0,
11470                snapshot.line_len(row_range.end.previous_row()),
11471            ));
11472            cursor_positions.push(anchor..anchor);
11473        }
11474
11475        self.transact(window, cx, |this, window, cx| {
11476            for row_range in row_ranges.into_iter().rev() {
11477                for row in row_range.iter_rows().rev() {
11478                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11479                    let next_line_row = row.next_row();
11480                    let indent = snapshot.indent_size_for_line(next_line_row);
11481                    let mut join_start_column = indent.len;
11482
11483                    if let Some(language_scope) =
11484                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11485                    {
11486                        let line_end =
11487                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11488                        let line_text_after_indent = snapshot
11489                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11490                            .collect::<String>();
11491
11492                        if !line_text_after_indent.is_empty() {
11493                            let block_prefix = language_scope
11494                                .block_comment()
11495                                .map(|c| c.prefix.as_ref())
11496                                .filter(|p| !p.is_empty());
11497                            let doc_prefix = language_scope
11498                                .documentation_comment()
11499                                .map(|c| c.prefix.as_ref())
11500                                .filter(|p| !p.is_empty());
11501                            let all_prefixes = language_scope
11502                                .line_comment_prefixes()
11503                                .iter()
11504                                .map(|p| p.as_ref())
11505                                .chain(block_prefix)
11506                                .chain(doc_prefix)
11507                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11508
11509                            let mut longest_prefix_len = None;
11510                            for prefix in all_prefixes {
11511                                let trimmed = prefix.trim_end();
11512                                if line_text_after_indent.starts_with(trimmed) {
11513                                    let candidate_len =
11514                                        if line_text_after_indent.starts_with(prefix) {
11515                                            prefix.len()
11516                                        } else {
11517                                            trimmed.len()
11518                                        };
11519                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11520                                        longest_prefix_len = Some(candidate_len);
11521                                    }
11522                                }
11523                            }
11524
11525                            if let Some(prefix_len) = longest_prefix_len {
11526                                join_start_column =
11527                                    join_start_column.saturating_add(prefix_len as u32);
11528                            }
11529                        }
11530                    }
11531
11532                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11533
11534                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11535                        && insert_whitespace
11536                    {
11537                        " "
11538                    } else {
11539                        ""
11540                    };
11541
11542                    this.buffer.update(cx, |buffer, cx| {
11543                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11544                    });
11545                }
11546            }
11547
11548            this.change_selections(Default::default(), window, cx, |s| {
11549                s.select_anchor_ranges(cursor_positions)
11550            });
11551        });
11552    }
11553
11554    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11556        self.join_lines_impl(true, window, cx);
11557    }
11558
11559    pub fn sort_lines_case_sensitive(
11560        &mut self,
11561        _: &SortLinesCaseSensitive,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11566    }
11567
11568    pub fn sort_lines_by_length(
11569        &mut self,
11570        _: &SortLinesByLength,
11571        window: &mut Window,
11572        cx: &mut Context<Self>,
11573    ) {
11574        self.manipulate_immutable_lines(window, cx, |lines| {
11575            lines.sort_by_key(|&line| line.chars().count())
11576        })
11577    }
11578
11579    pub fn sort_lines_case_insensitive(
11580        &mut self,
11581        _: &SortLinesCaseInsensitive,
11582        window: &mut Window,
11583        cx: &mut Context<Self>,
11584    ) {
11585        self.manipulate_immutable_lines(window, cx, |lines| {
11586            lines.sort_by_key(|line| line.to_lowercase())
11587        })
11588    }
11589
11590    pub fn unique_lines_case_insensitive(
11591        &mut self,
11592        _: &UniqueLinesCaseInsensitive,
11593        window: &mut Window,
11594        cx: &mut Context<Self>,
11595    ) {
11596        self.manipulate_immutable_lines(window, cx, |lines| {
11597            let mut seen = HashSet::default();
11598            lines.retain(|line| seen.insert(line.to_lowercase()));
11599        })
11600    }
11601
11602    pub fn unique_lines_case_sensitive(
11603        &mut self,
11604        _: &UniqueLinesCaseSensitive,
11605        window: &mut Window,
11606        cx: &mut Context<Self>,
11607    ) {
11608        self.manipulate_immutable_lines(window, cx, |lines| {
11609            let mut seen = HashSet::default();
11610            lines.retain(|line| seen.insert(*line));
11611        })
11612    }
11613
11614    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11615        let snapshot = self.buffer.read(cx).snapshot(cx);
11616        for selection in self.selections.disjoint_anchors_arc().iter() {
11617            if snapshot
11618                .language_at(selection.start)
11619                .and_then(|lang| lang.config().wrap_characters.as_ref())
11620                .is_some()
11621            {
11622                return true;
11623            }
11624        }
11625        false
11626    }
11627
11628    fn wrap_selections_in_tag(
11629        &mut self,
11630        _: &WrapSelectionsInTag,
11631        window: &mut Window,
11632        cx: &mut Context<Self>,
11633    ) {
11634        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11635
11636        let snapshot = self.buffer.read(cx).snapshot(cx);
11637
11638        let mut edits = Vec::new();
11639        let mut boundaries = Vec::new();
11640
11641        for selection in self
11642            .selections
11643            .all_adjusted(&self.display_snapshot(cx))
11644            .iter()
11645        {
11646            let Some(wrap_config) = snapshot
11647                .language_at(selection.start)
11648                .and_then(|lang| lang.config().wrap_characters.clone())
11649            else {
11650                continue;
11651            };
11652
11653            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11654            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11655
11656            let start_before = snapshot.anchor_before(selection.start);
11657            let end_after = snapshot.anchor_after(selection.end);
11658
11659            edits.push((start_before..start_before, open_tag));
11660            edits.push((end_after..end_after, close_tag));
11661
11662            boundaries.push((
11663                start_before,
11664                end_after,
11665                wrap_config.start_prefix.len(),
11666                wrap_config.end_suffix.len(),
11667            ));
11668        }
11669
11670        if edits.is_empty() {
11671            return;
11672        }
11673
11674        self.transact(window, cx, |this, window, cx| {
11675            let buffer = this.buffer.update(cx, |buffer, cx| {
11676                buffer.edit(edits, None, cx);
11677                buffer.snapshot(cx)
11678            });
11679
11680            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11681            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11682                boundaries.into_iter()
11683            {
11684                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11685                let close_offset = end_after
11686                    .to_offset(&buffer)
11687                    .saturating_sub_usize(end_suffix_len);
11688                new_selections.push(open_offset..open_offset);
11689                new_selections.push(close_offset..close_offset);
11690            }
11691
11692            this.change_selections(Default::default(), window, cx, |s| {
11693                s.select_ranges(new_selections);
11694            });
11695
11696            this.request_autoscroll(Autoscroll::fit(), cx);
11697        });
11698    }
11699
11700    pub fn toggle_read_only(
11701        &mut self,
11702        _: &workspace::ToggleReadOnlyFile,
11703        _: &mut Window,
11704        cx: &mut Context<Self>,
11705    ) {
11706        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11707            buffer.update(cx, |buffer, cx| {
11708                buffer.set_capability(
11709                    match buffer.capability() {
11710                        Capability::ReadWrite => Capability::Read,
11711                        Capability::Read => Capability::ReadWrite,
11712                        Capability::ReadOnly => Capability::ReadOnly,
11713                    },
11714                    cx,
11715                );
11716            })
11717        }
11718    }
11719
11720    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11721        let Some(project) = self.project.clone() else {
11722            return;
11723        };
11724        let task = self.reload(project, window, cx);
11725        self.detach_and_notify_err(task, window, cx);
11726    }
11727
11728    pub fn restore_file(
11729        &mut self,
11730        _: &::git::RestoreFile,
11731        window: &mut Window,
11732        cx: &mut Context<Self>,
11733    ) {
11734        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11735        let mut buffer_ids = HashSet::default();
11736        let snapshot = self.buffer().read(cx).snapshot(cx);
11737        for selection in self
11738            .selections
11739            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11740        {
11741            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11742        }
11743
11744        let buffer = self.buffer().read(cx);
11745        let ranges = buffer_ids
11746            .into_iter()
11747            .flat_map(|buffer_id| buffer.range_for_buffer(buffer_id, cx))
11748            .collect::<Vec<_>>();
11749
11750        self.restore_hunks_in_ranges(ranges, window, cx);
11751    }
11752
11753    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11754        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11755        let selections = self
11756            .selections
11757            .all(&self.display_snapshot(cx))
11758            .into_iter()
11759            .map(|s| s.range())
11760            .collect();
11761        self.restore_hunks_in_ranges(selections, window, cx);
11762    }
11763
11764    /// Restores the diff hunks in the editor's selections and moves the cursor
11765    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11766    /// not all diff hunks are expanded.
11767    pub fn restore_and_next(
11768        &mut self,
11769        _: &::git::RestoreAndNext,
11770        window: &mut Window,
11771        cx: &mut Context<Self>,
11772    ) {
11773        let selections = self
11774            .selections
11775            .all(&self.display_snapshot(cx))
11776            .into_iter()
11777            .map(|selection| selection.range())
11778            .collect();
11779
11780        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11781        self.restore_hunks_in_ranges(selections, window, cx);
11782
11783        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11784        let wrap_around = !all_diff_hunks_expanded;
11785        let snapshot = self.snapshot(window, cx);
11786        let position = self
11787            .selections
11788            .newest::<Point>(&snapshot.display_snapshot)
11789            .head();
11790
11791        self.go_to_hunk_before_or_after_position(
11792            &snapshot,
11793            position,
11794            Direction::Next,
11795            wrap_around,
11796            window,
11797            cx,
11798        );
11799    }
11800
11801    pub fn restore_hunks_in_ranges(
11802        &mut self,
11803        ranges: Vec<Range<Point>>,
11804        window: &mut Window,
11805        cx: &mut Context<Editor>,
11806    ) {
11807        if self.delegate_stage_and_restore {
11808            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11809            if !hunks.is_empty() {
11810                cx.emit(EditorEvent::RestoreRequested { hunks });
11811            }
11812            return;
11813        }
11814        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11815        self.transact(window, cx, |editor, window, cx| {
11816            editor.restore_diff_hunks(hunks, cx);
11817            let selections = editor
11818                .selections
11819                .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
11820            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11821                s.select(selections);
11822            });
11823        });
11824    }
11825
11826    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11827        let mut revert_changes = HashMap::default();
11828        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11829        for (buffer_id, hunks) in &chunk_by {
11830            let hunks = hunks.collect::<Vec<_>>();
11831            for hunk in &hunks {
11832                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11833            }
11834            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11835        }
11836        if !revert_changes.is_empty() {
11837            self.buffer().update(cx, |multi_buffer, cx| {
11838                for (buffer_id, changes) in revert_changes {
11839                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11840                        buffer.update(cx, |buffer, cx| {
11841                            buffer.edit(
11842                                changes
11843                                    .into_iter()
11844                                    .map(|(range, text)| (range, text.to_string())),
11845                                None,
11846                                cx,
11847                            );
11848                        });
11849                    }
11850                }
11851            });
11852        }
11853    }
11854
11855    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11856        if let Some(status) = self
11857            .addons
11858            .iter()
11859            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11860        {
11861            return Some(status);
11862        }
11863        self.project
11864            .as_ref()?
11865            .read(cx)
11866            .status_for_buffer_id(buffer_id, cx)
11867    }
11868
11869    pub fn open_active_item_in_terminal(
11870        &mut self,
11871        _: &OpenInTerminal,
11872        window: &mut Window,
11873        cx: &mut Context<Self>,
11874    ) {
11875        if let Some(working_directory) = self.active_buffer(cx).and_then(|buffer| {
11876            let project_path = buffer.read(cx).project_path(cx)?;
11877            let project = self.project()?.read(cx);
11878            let entry = project.entry_for_path(&project_path, cx)?;
11879            let parent = match &entry.canonical_path {
11880                Some(canonical_path) => canonical_path.to_path_buf(),
11881                None => project.absolute_path(&project_path, cx)?,
11882            }
11883            .parent()?
11884            .to_path_buf();
11885            Some(parent)
11886        }) {
11887            window.dispatch_action(
11888                OpenTerminal {
11889                    working_directory,
11890                    local: false,
11891                }
11892                .boxed_clone(),
11893                cx,
11894            );
11895        }
11896    }
11897
11898    fn set_breakpoint_context_menu(
11899        &mut self,
11900        display_row: DisplayRow,
11901        position: Option<Anchor>,
11902        clicked_point: gpui::Point<Pixels>,
11903        window: &mut Window,
11904        cx: &mut Context<Self>,
11905    ) {
11906        let source = self
11907            .buffer
11908            .read(cx)
11909            .snapshot(cx)
11910            .anchor_before(Point::new(display_row.0, 0u32));
11911
11912        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11913
11914        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11915            self,
11916            source,
11917            clicked_point,
11918            context_menu,
11919            window,
11920            cx,
11921        );
11922    }
11923
11924    fn add_edit_breakpoint_block(
11925        &mut self,
11926        anchor: Anchor,
11927        breakpoint: &Breakpoint,
11928        edit_action: BreakpointPromptEditAction,
11929        window: &mut Window,
11930        cx: &mut Context<Self>,
11931    ) {
11932        let weak_editor = cx.weak_entity();
11933        let bp_prompt = cx.new(|cx| {
11934            BreakpointPromptEditor::new(
11935                weak_editor,
11936                anchor,
11937                breakpoint.clone(),
11938                edit_action,
11939                window,
11940                cx,
11941            )
11942        });
11943
11944        let height = bp_prompt.update(cx, |this, cx| {
11945            this.prompt
11946                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11947        });
11948        let cloned_prompt = bp_prompt.clone();
11949        let blocks = vec![BlockProperties {
11950            style: BlockStyle::Sticky,
11951            placement: BlockPlacement::Above(anchor),
11952            height: Some(height),
11953            render: Arc::new(move |cx| {
11954                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11955                cloned_prompt.clone().into_any_element()
11956            }),
11957            priority: 0,
11958        }];
11959
11960        let focus_handle = bp_prompt.focus_handle(cx);
11961        window.focus(&focus_handle, cx);
11962
11963        let block_ids = self.insert_blocks(blocks, None, cx);
11964        bp_prompt.update(cx, |prompt, _| {
11965            prompt.add_block_ids(block_ids);
11966        });
11967    }
11968
11969    pub(crate) fn breakpoint_at_row(
11970        &self,
11971        row: u32,
11972        window: &mut Window,
11973        cx: &mut Context<Self>,
11974    ) -> Option<(Anchor, Breakpoint)> {
11975        let snapshot = self.snapshot(window, cx);
11976        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11977
11978        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11979    }
11980
11981    pub(crate) fn breakpoint_at_anchor(
11982        &self,
11983        breakpoint_position: Anchor,
11984        snapshot: &EditorSnapshot,
11985        cx: &mut Context<Self>,
11986    ) -> Option<(Anchor, Breakpoint)> {
11987        let (breakpoint_position, _) = snapshot
11988            .buffer_snapshot()
11989            .anchor_to_buffer_anchor(breakpoint_position)?;
11990        let buffer = self.buffer.read(cx).buffer(breakpoint_position.buffer_id)?;
11991
11992        let buffer_snapshot = buffer.read(cx).snapshot();
11993
11994        let row = buffer_snapshot
11995            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position)
11996            .row;
11997
11998        let line_len = buffer_snapshot.line_len(row);
11999        let anchor_end = buffer_snapshot.anchor_after(Point::new(row, line_len));
12000
12001        self.breakpoint_store
12002            .as_ref()?
12003            .read_with(cx, |breakpoint_store, cx| {
12004                breakpoint_store
12005                    .breakpoints(
12006                        &buffer,
12007                        Some(breakpoint_position..anchor_end),
12008                        &buffer_snapshot,
12009                        cx,
12010                    )
12011                    .next()
12012                    .and_then(|(bp, _)| {
12013                        let breakpoint_row = buffer_snapshot
12014                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
12015                            .row;
12016
12017                        if breakpoint_row == row {
12018                            snapshot
12019                                .buffer_snapshot()
12020                                .anchor_in_excerpt(bp.position)
12021                                .map(|position| (position, bp.bp.clone()))
12022                        } else {
12023                            None
12024                        }
12025                    })
12026            })
12027    }
12028
12029    pub fn edit_log_breakpoint(
12030        &mut self,
12031        _: &EditLogBreakpoint,
12032        window: &mut Window,
12033        cx: &mut Context<Self>,
12034    ) {
12035        if self.breakpoint_store.is_none() {
12036            return;
12037        }
12038
12039        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12040            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
12041                message: None,
12042                state: BreakpointState::Enabled,
12043                condition: None,
12044                hit_condition: None,
12045            });
12046
12047            self.add_edit_breakpoint_block(
12048                anchor,
12049                &breakpoint,
12050                BreakpointPromptEditAction::Log,
12051                window,
12052                cx,
12053            );
12054        }
12055    }
12056
12057    fn breakpoints_at_cursors(
12058        &self,
12059        window: &mut Window,
12060        cx: &mut Context<Self>,
12061    ) -> Vec<(Anchor, Option<Breakpoint>)> {
12062        let snapshot = self.snapshot(window, cx);
12063        let cursors = self
12064            .selections
12065            .disjoint_anchors_arc()
12066            .iter()
12067            .map(|selection| {
12068                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12069
12070                let breakpoint_position = self
12071                    .breakpoint_at_row(cursor_position.row, window, cx)
12072                    .map(|bp| bp.0)
12073                    .unwrap_or_else(|| {
12074                        snapshot
12075                            .display_snapshot
12076                            .buffer_snapshot()
12077                            .anchor_after(Point::new(cursor_position.row, 0))
12078                    });
12079
12080                let breakpoint = self
12081                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12082                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12083
12084                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12085            })
12086            // 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.
12087            .collect::<HashMap<Anchor, _>>();
12088
12089        cursors.into_iter().collect()
12090    }
12091
12092    pub fn enable_breakpoint(
12093        &mut self,
12094        _: &crate::actions::EnableBreakpoint,
12095        window: &mut Window,
12096        cx: &mut Context<Self>,
12097    ) {
12098        if self.breakpoint_store.is_none() {
12099            return;
12100        }
12101
12102        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12103            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12104                continue;
12105            };
12106            self.edit_breakpoint_at_anchor(
12107                anchor,
12108                breakpoint,
12109                BreakpointEditAction::InvertState,
12110                cx,
12111            );
12112        }
12113    }
12114
12115    pub fn align_selections(
12116        &mut self,
12117        _: &crate::actions::AlignSelections,
12118        window: &mut Window,
12119        cx: &mut Context<Self>,
12120    ) {
12121        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12122
12123        let display_snapshot = self.display_snapshot(cx);
12124
12125        struct CursorData {
12126            anchor: Anchor,
12127            point: Point,
12128        }
12129        let cursor_data: Vec<CursorData> = self
12130            .selections
12131            .disjoint_anchors()
12132            .iter()
12133            .map(|selection| {
12134                let anchor = if selection.reversed {
12135                    selection.head()
12136                } else {
12137                    selection.tail()
12138                };
12139                CursorData {
12140                    anchor: anchor,
12141                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12142                }
12143            })
12144            .collect();
12145
12146        let rows_anchors_count: Vec<usize> = cursor_data
12147            .iter()
12148            .map(|cursor| cursor.point.row)
12149            .chunk_by(|&row| row)
12150            .into_iter()
12151            .map(|(_, group)| group.count())
12152            .collect();
12153        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12154        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12155        let mut edits = Vec::new();
12156
12157        for column_idx in 0..max_columns {
12158            let mut cursor_index = 0;
12159
12160            // Calculate target_column => position that the selections will go
12161            let mut target_column = 0;
12162            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12163                // Skip rows that don't have this column
12164                if column_idx >= *cursor_count {
12165                    cursor_index += cursor_count;
12166                    continue;
12167                }
12168
12169                let point = &cursor_data[cursor_index + column_idx].point;
12170                let adjusted_column = point.column + rows_column_offset[row_idx];
12171                if adjusted_column > target_column {
12172                    target_column = adjusted_column;
12173                }
12174                cursor_index += cursor_count;
12175            }
12176
12177            // Collect edits for this column
12178            cursor_index = 0;
12179            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12180                // Skip rows that don't have this column
12181                if column_idx >= *cursor_count {
12182                    cursor_index += *cursor_count;
12183                    continue;
12184                }
12185
12186                let point = &cursor_data[cursor_index + column_idx].point;
12187                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12188                if spaces_needed > 0 {
12189                    let anchor = cursor_data[cursor_index + column_idx]
12190                        .anchor
12191                        .bias_left(&display_snapshot);
12192                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12193                }
12194                rows_column_offset[row_idx] += spaces_needed;
12195
12196                cursor_index += *cursor_count;
12197            }
12198        }
12199
12200        if !edits.is_empty() {
12201            self.transact(window, cx, |editor, _window, cx| {
12202                editor.edit(edits, cx);
12203            });
12204        }
12205    }
12206
12207    pub fn disable_breakpoint(
12208        &mut self,
12209        _: &crate::actions::DisableBreakpoint,
12210        window: &mut Window,
12211        cx: &mut Context<Self>,
12212    ) {
12213        if self.breakpoint_store.is_none() {
12214            return;
12215        }
12216
12217        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12218            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12219                continue;
12220            };
12221            self.edit_breakpoint_at_anchor(
12222                anchor,
12223                breakpoint,
12224                BreakpointEditAction::InvertState,
12225                cx,
12226            );
12227        }
12228    }
12229
12230    pub fn toggle_breakpoint(
12231        &mut self,
12232        _: &crate::actions::ToggleBreakpoint,
12233        window: &mut Window,
12234        cx: &mut Context<Self>,
12235    ) {
12236        if self.breakpoint_store.is_none() {
12237            return;
12238        }
12239
12240        let snapshot = self.snapshot(window, cx);
12241        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12242            if self.gutter_breakpoint_indicator.0.is_some() {
12243                let display_row = anchor
12244                    .to_point(snapshot.buffer_snapshot())
12245                    .to_display_point(&snapshot.display_snapshot)
12246                    .row();
12247                self.update_breakpoint_collision_on_toggle(
12248                    display_row,
12249                    &BreakpointEditAction::Toggle,
12250                );
12251            }
12252
12253            if let Some(breakpoint) = breakpoint {
12254                self.edit_breakpoint_at_anchor(
12255                    anchor,
12256                    breakpoint,
12257                    BreakpointEditAction::Toggle,
12258                    cx,
12259                );
12260            } else {
12261                self.edit_breakpoint_at_anchor(
12262                    anchor,
12263                    Breakpoint::new_standard(),
12264                    BreakpointEditAction::Toggle,
12265                    cx,
12266                );
12267            }
12268        }
12269    }
12270
12271    fn update_breakpoint_collision_on_toggle(
12272        &mut self,
12273        display_row: DisplayRow,
12274        edit_action: &BreakpointEditAction,
12275    ) {
12276        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12277            if breakpoint_indicator.display_row == display_row
12278                && matches!(edit_action, BreakpointEditAction::Toggle)
12279            {
12280                breakpoint_indicator.collides_with_existing_breakpoint =
12281                    !breakpoint_indicator.collides_with_existing_breakpoint;
12282            }
12283        }
12284    }
12285
12286    pub fn edit_breakpoint_at_anchor(
12287        &mut self,
12288        breakpoint_position: Anchor,
12289        breakpoint: Breakpoint,
12290        edit_action: BreakpointEditAction,
12291        cx: &mut Context<Self>,
12292    ) {
12293        let Some(breakpoint_store) = &self.breakpoint_store else {
12294            return;
12295        };
12296        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12297        let Some((position, _)) = buffer_snapshot.anchor_to_buffer_anchor(breakpoint_position)
12298        else {
12299            return;
12300        };
12301        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
12302            return;
12303        };
12304
12305        breakpoint_store.update(cx, |breakpoint_store, cx| {
12306            breakpoint_store.toggle_breakpoint(
12307                buffer,
12308                BreakpointWithPosition {
12309                    position,
12310                    bp: breakpoint,
12311                },
12312                edit_action,
12313                cx,
12314            );
12315        });
12316
12317        cx.notify();
12318    }
12319
12320    #[cfg(any(test, feature = "test-support"))]
12321    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12322        self.breakpoint_store.clone()
12323    }
12324
12325    pub fn prepare_restore_change(
12326        &self,
12327        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12328        hunk: &MultiBufferDiffHunk,
12329        cx: &mut App,
12330    ) -> Option<()> {
12331        if hunk.is_created_file() {
12332            return None;
12333        }
12334        let multi_buffer = self.buffer.read(cx);
12335        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
12336        let diff_snapshot = multi_buffer_snapshot.diff_for_buffer_id(hunk.buffer_id)?;
12337        let original_text = diff_snapshot
12338            .base_text()
12339            .as_rope()
12340            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12341        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
12342        let buffer = buffer.read(cx);
12343        let buffer_snapshot = buffer.snapshot();
12344        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12345        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12346            probe
12347                .0
12348                .start
12349                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12350                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12351        }) {
12352            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12353            Some(())
12354        } else {
12355            None
12356        }
12357    }
12358
12359    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12360        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12361    }
12362
12363    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12364        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12365    }
12366
12367    pub fn rotate_selections_forward(
12368        &mut self,
12369        _: &RotateSelectionsForward,
12370        window: &mut Window,
12371        cx: &mut Context<Self>,
12372    ) {
12373        self.rotate_selections(window, cx, false)
12374    }
12375
12376    pub fn rotate_selections_backward(
12377        &mut self,
12378        _: &RotateSelectionsBackward,
12379        window: &mut Window,
12380        cx: &mut Context<Self>,
12381    ) {
12382        self.rotate_selections(window, cx, true)
12383    }
12384
12385    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12387        let display_snapshot = self.display_snapshot(cx);
12388        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12389
12390        if selections.len() < 2 {
12391            return;
12392        }
12393
12394        let (edits, new_selections) = {
12395            let buffer = self.buffer.read(cx).read(cx);
12396            let has_selections = selections.iter().any(|s| !s.is_empty());
12397            if has_selections {
12398                let mut selected_texts: Vec<String> = selections
12399                    .iter()
12400                    .map(|selection| {
12401                        buffer
12402                            .text_for_range(selection.start..selection.end)
12403                            .collect()
12404                    })
12405                    .collect();
12406
12407                if reverse {
12408                    selected_texts.rotate_left(1);
12409                } else {
12410                    selected_texts.rotate_right(1);
12411                }
12412
12413                let mut offset_delta: i64 = 0;
12414                let mut new_selections = Vec::new();
12415                let edits: Vec<_> = selections
12416                    .iter()
12417                    .zip(selected_texts.iter())
12418                    .map(|(selection, new_text)| {
12419                        let old_len = (selection.end.0 - selection.start.0) as i64;
12420                        let new_len = new_text.len() as i64;
12421                        let adjusted_start =
12422                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12423                        let adjusted_end =
12424                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12425
12426                        new_selections.push(Selection {
12427                            id: selection.id,
12428                            start: adjusted_start,
12429                            end: adjusted_end,
12430                            reversed: selection.reversed,
12431                            goal: selection.goal,
12432                        });
12433
12434                        offset_delta += new_len - old_len;
12435                        (selection.start..selection.end, new_text.clone())
12436                    })
12437                    .collect();
12438                (edits, new_selections)
12439            } else {
12440                let mut all_rows: Vec<u32> = selections
12441                    .iter()
12442                    .map(|selection| buffer.offset_to_point(selection.start).row)
12443                    .collect();
12444                all_rows.sort_unstable();
12445                all_rows.dedup();
12446
12447                if all_rows.len() < 2 {
12448                    return;
12449                }
12450
12451                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12452                    .iter()
12453                    .map(|&row| {
12454                        let start = Point::new(row, 0);
12455                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12456                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12457                    })
12458                    .collect();
12459
12460                let mut line_texts: Vec<String> = line_ranges
12461                    .iter()
12462                    .map(|range| buffer.text_for_range(range.clone()).collect())
12463                    .collect();
12464
12465                if reverse {
12466                    line_texts.rotate_left(1);
12467                } else {
12468                    line_texts.rotate_right(1);
12469                }
12470
12471                let edits = line_ranges
12472                    .iter()
12473                    .zip(line_texts.iter())
12474                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12475                    .collect();
12476
12477                let num_rows = all_rows.len();
12478                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12479                    .iter()
12480                    .enumerate()
12481                    .map(|(i, &row)| (row, i))
12482                    .collect();
12483
12484                // Compute new line start offsets after rotation (handles CRLF)
12485                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12486                let first_line_start = line_ranges[0].start.0;
12487                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12488                for text in line_texts.iter().take(num_rows - 1) {
12489                    let prev_start = *new_line_starts.last().unwrap();
12490                    new_line_starts.push(prev_start + text.len() + newline_len);
12491                }
12492
12493                let new_selections = selections
12494                    .iter()
12495                    .map(|selection| {
12496                        let point = buffer.offset_to_point(selection.start);
12497                        let old_index = row_to_index[&point.row];
12498                        let new_index = if reverse {
12499                            (old_index + num_rows - 1) % num_rows
12500                        } else {
12501                            (old_index + 1) % num_rows
12502                        };
12503                        let new_offset =
12504                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12505                        Selection {
12506                            id: selection.id,
12507                            start: new_offset,
12508                            end: new_offset,
12509                            reversed: selection.reversed,
12510                            goal: selection.goal,
12511                        }
12512                    })
12513                    .collect();
12514
12515                (edits, new_selections)
12516            }
12517        };
12518
12519        self.transact(window, cx, |this, window, cx| {
12520            this.buffer.update(cx, |buffer, cx| {
12521                buffer.edit(edits, None, cx);
12522            });
12523            this.change_selections(Default::default(), window, cx, |s| {
12524                s.select(new_selections);
12525            });
12526        });
12527    }
12528
12529    fn manipulate_lines<M>(
12530        &mut self,
12531        window: &mut Window,
12532        cx: &mut Context<Self>,
12533        mut manipulate: M,
12534    ) where
12535        M: FnMut(&str) -> LineManipulationResult,
12536    {
12537        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12538
12539        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12540        let buffer = self.buffer.read(cx).snapshot(cx);
12541
12542        let mut edits = Vec::new();
12543
12544        let selections = self.selections.all::<Point>(&display_map);
12545        let mut selections = selections.iter().peekable();
12546        let mut contiguous_row_selections = Vec::new();
12547        let mut new_selections = Vec::new();
12548        let mut added_lines = 0;
12549        let mut removed_lines = 0;
12550
12551        while let Some(selection) = selections.next() {
12552            let (start_row, end_row) = consume_contiguous_rows(
12553                &mut contiguous_row_selections,
12554                selection,
12555                &display_map,
12556                &mut selections,
12557            );
12558
12559            let start_point = Point::new(start_row.0, 0);
12560            let end_point = Point::new(
12561                end_row.previous_row().0,
12562                buffer.line_len(end_row.previous_row()),
12563            );
12564            let text = buffer
12565                .text_for_range(start_point..end_point)
12566                .collect::<String>();
12567
12568            let LineManipulationResult {
12569                new_text,
12570                line_count_before,
12571                line_count_after,
12572            } = manipulate(&text);
12573
12574            edits.push((start_point..end_point, new_text));
12575
12576            // Selections must change based on added and removed line count
12577            let start_row =
12578                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12579            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12580            new_selections.push(Selection {
12581                id: selection.id,
12582                start: start_row,
12583                end: end_row,
12584                goal: SelectionGoal::None,
12585                reversed: selection.reversed,
12586            });
12587
12588            if line_count_after > line_count_before {
12589                added_lines += line_count_after - line_count_before;
12590            } else if line_count_before > line_count_after {
12591                removed_lines += line_count_before - line_count_after;
12592            }
12593        }
12594
12595        self.transact(window, cx, |this, window, cx| {
12596            let buffer = this.buffer.update(cx, |buffer, cx| {
12597                buffer.edit(edits, None, cx);
12598                buffer.snapshot(cx)
12599            });
12600
12601            // Recalculate offsets on newly edited buffer
12602            let new_selections = new_selections
12603                .iter()
12604                .map(|s| {
12605                    let start_point = Point::new(s.start.0, 0);
12606                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12607                    Selection {
12608                        id: s.id,
12609                        start: buffer.point_to_offset(start_point),
12610                        end: buffer.point_to_offset(end_point),
12611                        goal: s.goal,
12612                        reversed: s.reversed,
12613                    }
12614                })
12615                .collect();
12616
12617            this.change_selections(Default::default(), window, cx, |s| {
12618                s.select(new_selections);
12619            });
12620
12621            this.request_autoscroll(Autoscroll::fit(), cx);
12622        });
12623    }
12624
12625    fn manipulate_immutable_lines<Fn>(
12626        &mut self,
12627        window: &mut Window,
12628        cx: &mut Context<Self>,
12629        mut callback: Fn,
12630    ) where
12631        Fn: FnMut(&mut Vec<&str>),
12632    {
12633        self.manipulate_lines(window, cx, |text| {
12634            let mut lines: Vec<&str> = text.split('\n').collect();
12635            let line_count_before = lines.len();
12636
12637            callback(&mut lines);
12638
12639            LineManipulationResult {
12640                new_text: lines.join("\n"),
12641                line_count_before,
12642                line_count_after: lines.len(),
12643            }
12644        });
12645    }
12646
12647    fn manipulate_mutable_lines<Fn>(
12648        &mut self,
12649        window: &mut Window,
12650        cx: &mut Context<Self>,
12651        mut callback: Fn,
12652    ) where
12653        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12654    {
12655        self.manipulate_lines(window, cx, |text| {
12656            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12657            let line_count_before = lines.len();
12658
12659            callback(&mut lines);
12660
12661            LineManipulationResult {
12662                new_text: lines.join("\n"),
12663                line_count_before,
12664                line_count_after: lines.len(),
12665            }
12666        });
12667    }
12668
12669    pub fn convert_indentation_to_spaces(
12670        &mut self,
12671        _: &ConvertIndentationToSpaces,
12672        window: &mut Window,
12673        cx: &mut Context<Self>,
12674    ) {
12675        let settings = self.buffer.read(cx).language_settings(cx);
12676        let tab_size = settings.tab_size.get() as usize;
12677
12678        self.manipulate_mutable_lines(window, cx, |lines| {
12679            // Allocates a reasonably sized scratch buffer once for the whole loop
12680            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12681            // Avoids recomputing spaces that could be inserted many times
12682            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12683                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12684                .collect();
12685
12686            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12687                let mut chars = line.as_ref().chars();
12688                let mut col = 0;
12689                let mut changed = false;
12690
12691                for ch in chars.by_ref() {
12692                    match ch {
12693                        ' ' => {
12694                            reindented_line.push(' ');
12695                            col += 1;
12696                        }
12697                        '\t' => {
12698                            // \t are converted to spaces depending on the current column
12699                            let spaces_len = tab_size - (col % tab_size);
12700                            reindented_line.extend(&space_cache[spaces_len - 1]);
12701                            col += spaces_len;
12702                            changed = true;
12703                        }
12704                        _ => {
12705                            // If we dont append before break, the character is consumed
12706                            reindented_line.push(ch);
12707                            break;
12708                        }
12709                    }
12710                }
12711
12712                if !changed {
12713                    reindented_line.clear();
12714                    continue;
12715                }
12716                // Append the rest of the line and replace old reference with new one
12717                reindented_line.extend(chars);
12718                *line = Cow::Owned(reindented_line.clone());
12719                reindented_line.clear();
12720            }
12721        });
12722    }
12723
12724    pub fn convert_indentation_to_tabs(
12725        &mut self,
12726        _: &ConvertIndentationToTabs,
12727        window: &mut Window,
12728        cx: &mut Context<Self>,
12729    ) {
12730        let settings = self.buffer.read(cx).language_settings(cx);
12731        let tab_size = settings.tab_size.get() as usize;
12732
12733        self.manipulate_mutable_lines(window, cx, |lines| {
12734            // Allocates a reasonably sized buffer once for the whole loop
12735            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12736            // Avoids recomputing spaces that could be inserted many times
12737            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12738                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12739                .collect();
12740
12741            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12742                let mut chars = line.chars();
12743                let mut spaces_count = 0;
12744                let mut first_non_indent_char = None;
12745                let mut changed = false;
12746
12747                for ch in chars.by_ref() {
12748                    match ch {
12749                        ' ' => {
12750                            // Keep track of spaces. Append \t when we reach tab_size
12751                            spaces_count += 1;
12752                            changed = true;
12753                            if spaces_count == tab_size {
12754                                reindented_line.push('\t');
12755                                spaces_count = 0;
12756                            }
12757                        }
12758                        '\t' => {
12759                            reindented_line.push('\t');
12760                            spaces_count = 0;
12761                        }
12762                        _ => {
12763                            // Dont append it yet, we might have remaining spaces
12764                            first_non_indent_char = Some(ch);
12765                            break;
12766                        }
12767                    }
12768                }
12769
12770                if !changed {
12771                    reindented_line.clear();
12772                    continue;
12773                }
12774                // Remaining spaces that didn't make a full tab stop
12775                if spaces_count > 0 {
12776                    reindented_line.extend(&space_cache[spaces_count - 1]);
12777                }
12778                // If we consume an extra character that was not indentation, add it back
12779                if let Some(extra_char) = first_non_indent_char {
12780                    reindented_line.push(extra_char);
12781                }
12782                // Append the rest of the line and replace old reference with new one
12783                reindented_line.extend(chars);
12784                *line = Cow::Owned(reindented_line.clone());
12785                reindented_line.clear();
12786            }
12787        });
12788    }
12789
12790    pub fn convert_to_upper_case(
12791        &mut self,
12792        _: &ConvertToUpperCase,
12793        window: &mut Window,
12794        cx: &mut Context<Self>,
12795    ) {
12796        self.manipulate_text(window, cx, |text| text.to_uppercase())
12797    }
12798
12799    pub fn convert_to_lower_case(
12800        &mut self,
12801        _: &ConvertToLowerCase,
12802        window: &mut Window,
12803        cx: &mut Context<Self>,
12804    ) {
12805        self.manipulate_text(window, cx, |text| text.to_lowercase())
12806    }
12807
12808    pub fn convert_to_title_case(
12809        &mut self,
12810        _: &ConvertToTitleCase,
12811        window: &mut Window,
12812        cx: &mut Context<Self>,
12813    ) {
12814        self.manipulate_text(window, cx, |text| {
12815            Self::convert_text_case(text, Case::Title)
12816        })
12817    }
12818
12819    pub fn convert_to_snake_case(
12820        &mut self,
12821        _: &ConvertToSnakeCase,
12822        window: &mut Window,
12823        cx: &mut Context<Self>,
12824    ) {
12825        self.manipulate_text(window, cx, |text| {
12826            Self::convert_text_case(text, Case::Snake)
12827        })
12828    }
12829
12830    pub fn convert_to_kebab_case(
12831        &mut self,
12832        _: &ConvertToKebabCase,
12833        window: &mut Window,
12834        cx: &mut Context<Self>,
12835    ) {
12836        self.manipulate_text(window, cx, |text| {
12837            Self::convert_text_case(text, Case::Kebab)
12838        })
12839    }
12840
12841    pub fn convert_to_upper_camel_case(
12842        &mut self,
12843        _: &ConvertToUpperCamelCase,
12844        window: &mut Window,
12845        cx: &mut Context<Self>,
12846    ) {
12847        self.manipulate_text(window, cx, |text| {
12848            Self::convert_text_case(text, Case::UpperCamel)
12849        })
12850    }
12851
12852    pub fn convert_to_lower_camel_case(
12853        &mut self,
12854        _: &ConvertToLowerCamelCase,
12855        window: &mut Window,
12856        cx: &mut Context<Self>,
12857    ) {
12858        self.manipulate_text(window, cx, |text| {
12859            Self::convert_text_case(text, Case::Camel)
12860        })
12861    }
12862
12863    pub fn convert_to_opposite_case(
12864        &mut self,
12865        _: &ConvertToOppositeCase,
12866        window: &mut Window,
12867        cx: &mut Context<Self>,
12868    ) {
12869        self.manipulate_text(window, cx, |text| {
12870            text.chars()
12871                .fold(String::with_capacity(text.len()), |mut t, c| {
12872                    if c.is_uppercase() {
12873                        t.extend(c.to_lowercase());
12874                    } else {
12875                        t.extend(c.to_uppercase());
12876                    }
12877                    t
12878                })
12879        })
12880    }
12881
12882    pub fn convert_to_sentence_case(
12883        &mut self,
12884        _: &ConvertToSentenceCase,
12885        window: &mut Window,
12886        cx: &mut Context<Self>,
12887    ) {
12888        self.manipulate_text(window, cx, |text| {
12889            Self::convert_text_case(text, Case::Sentence)
12890        })
12891    }
12892
12893    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12894        self.manipulate_text(window, cx, |text| {
12895            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12896            if has_upper_case_characters {
12897                text.to_lowercase()
12898            } else {
12899                text.to_uppercase()
12900            }
12901        })
12902    }
12903
12904    pub fn convert_to_rot13(
12905        &mut self,
12906        _: &ConvertToRot13,
12907        window: &mut Window,
12908        cx: &mut Context<Self>,
12909    ) {
12910        self.manipulate_text(window, cx, |text| {
12911            text.chars()
12912                .map(|c| match c {
12913                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12914                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12915                    _ => c,
12916                })
12917                .collect()
12918        })
12919    }
12920
12921    fn convert_text_case(text: &str, case: Case) -> String {
12922        text.lines()
12923            .map(|line| {
12924                let trimmed_start = line.trim_start();
12925                let leading = &line[..line.len() - trimmed_start.len()];
12926                let trimmed = trimmed_start.trim_end();
12927                let trailing = &trimmed_start[trimmed.len()..];
12928                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12929            })
12930            .join("\n")
12931    }
12932
12933    pub fn convert_to_rot47(
12934        &mut self,
12935        _: &ConvertToRot47,
12936        window: &mut Window,
12937        cx: &mut Context<Self>,
12938    ) {
12939        self.manipulate_text(window, cx, |text| {
12940            text.chars()
12941                .map(|c| {
12942                    let code_point = c as u32;
12943                    if code_point >= 33 && code_point <= 126 {
12944                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12945                    }
12946                    c
12947                })
12948                .collect()
12949        })
12950    }
12951
12952    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12953    where
12954        Fn: FnMut(&str) -> String,
12955    {
12956        let buffer = self.buffer.read(cx).snapshot(cx);
12957
12958        let mut new_selections = Vec::new();
12959        let mut edits = Vec::new();
12960        let mut selection_adjustment = 0isize;
12961
12962        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12963            let selection_is_empty = selection.is_empty();
12964
12965            let (start, end) = if selection_is_empty {
12966                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12967                (word_range.start, word_range.end)
12968            } else {
12969                (
12970                    buffer.point_to_offset(selection.start),
12971                    buffer.point_to_offset(selection.end),
12972                )
12973            };
12974
12975            let text = buffer.text_for_range(start..end).collect::<String>();
12976            let old_length = text.len() as isize;
12977            let text = callback(&text);
12978
12979            new_selections.push(Selection {
12980                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12981                end: MultiBufferOffset(
12982                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12983                ),
12984                goal: SelectionGoal::None,
12985                id: selection.id,
12986                reversed: selection.reversed,
12987            });
12988
12989            selection_adjustment += old_length - text.len() as isize;
12990
12991            edits.push((start..end, text));
12992        }
12993
12994        self.transact(window, cx, |this, window, cx| {
12995            this.buffer.update(cx, |buffer, cx| {
12996                buffer.edit(edits, None, cx);
12997            });
12998
12999            this.change_selections(Default::default(), window, cx, |s| {
13000                s.select(new_selections);
13001            });
13002
13003            this.request_autoscroll(Autoscroll::fit(), cx);
13004        });
13005    }
13006
13007    pub fn move_selection_on_drop(
13008        &mut self,
13009        selection: &Selection<Anchor>,
13010        target: DisplayPoint,
13011        is_cut: bool,
13012        window: &mut Window,
13013        cx: &mut Context<Self>,
13014    ) {
13015        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13016        let buffer = display_map.buffer_snapshot();
13017        let mut edits = Vec::new();
13018        let insert_point = display_map
13019            .clip_point(target, Bias::Left)
13020            .to_point(&display_map);
13021        let text = buffer
13022            .text_for_range(selection.start..selection.end)
13023            .collect::<String>();
13024        if is_cut {
13025            edits.push(((selection.start..selection.end), String::new()));
13026        }
13027        let insert_anchor = buffer.anchor_before(insert_point);
13028        edits.push(((insert_anchor..insert_anchor), text));
13029        let last_edit_start = insert_anchor.bias_left(buffer);
13030        let last_edit_end = insert_anchor.bias_right(buffer);
13031        self.transact(window, cx, |this, window, cx| {
13032            this.buffer.update(cx, |buffer, cx| {
13033                buffer.edit(edits, None, cx);
13034            });
13035            this.change_selections(Default::default(), window, cx, |s| {
13036                s.select_anchor_ranges([last_edit_start..last_edit_end]);
13037            });
13038        });
13039    }
13040
13041    pub fn clear_selection_drag_state(&mut self) {
13042        self.selection_drag_state = SelectionDragState::None;
13043    }
13044
13045    pub fn duplicate(
13046        &mut self,
13047        upwards: bool,
13048        whole_lines: bool,
13049        window: &mut Window,
13050        cx: &mut Context<Self>,
13051    ) {
13052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13053
13054        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13055        let buffer = display_map.buffer_snapshot();
13056        let selections = self.selections.all::<Point>(&display_map);
13057
13058        let mut edits = Vec::new();
13059        let mut selections_iter = selections.iter().peekable();
13060        while let Some(selection) = selections_iter.next() {
13061            let mut rows = selection.spanned_rows(false, &display_map);
13062            // duplicate line-wise
13063            if whole_lines || selection.start == selection.end {
13064                // Avoid duplicating the same lines twice.
13065                while let Some(next_selection) = selections_iter.peek() {
13066                    let next_rows = next_selection.spanned_rows(false, &display_map);
13067                    if next_rows.start < rows.end {
13068                        rows.end = next_rows.end;
13069                        selections_iter.next().unwrap();
13070                    } else {
13071                        break;
13072                    }
13073                }
13074
13075                // Copy the text from the selected row region and splice it either at the start
13076                // or end of the region.
13077                let start = Point::new(rows.start.0, 0);
13078                let end = Point::new(
13079                    rows.end.previous_row().0,
13080                    buffer.line_len(rows.end.previous_row()),
13081                );
13082
13083                let mut text = buffer.text_for_range(start..end).collect::<String>();
13084
13085                let insert_location = if upwards {
13086                    // When duplicating upward, we need to insert before the current line.
13087                    // If we're on the last line and it doesn't end with a newline,
13088                    // we need to add a newline before the duplicated content.
13089                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13090                        && buffer.max_point().column > 0
13091                        && !text.ends_with('\n');
13092
13093                    if needs_leading_newline {
13094                        text.insert(0, '\n');
13095                        end
13096                    } else {
13097                        text.push('\n');
13098                        Point::new(rows.start.0, 0)
13099                    }
13100                } else {
13101                    text.push('\n');
13102                    start
13103                };
13104                edits.push((insert_location..insert_location, text));
13105            } else {
13106                // duplicate character-wise
13107                let start = selection.start;
13108                let end = selection.end;
13109                let text = buffer.text_for_range(start..end).collect::<String>();
13110                edits.push((selection.end..selection.end, text));
13111            }
13112        }
13113
13114        self.transact(window, cx, |this, window, cx| {
13115            this.buffer.update(cx, |buffer, cx| {
13116                buffer.edit(edits, None, cx);
13117            });
13118
13119            // When duplicating upward with whole lines, move the cursor to the duplicated line
13120            if upwards && whole_lines {
13121                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13122
13123                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13124                    let mut new_ranges = Vec::new();
13125                    let selections = s.all::<Point>(&display_map);
13126                    let mut selections_iter = selections.iter().peekable();
13127
13128                    while let Some(first_selection) = selections_iter.next() {
13129                        // Group contiguous selections together to find the total row span
13130                        let mut group_selections = vec![first_selection];
13131                        let mut rows = first_selection.spanned_rows(false, &display_map);
13132
13133                        while let Some(next_selection) = selections_iter.peek() {
13134                            let next_rows = next_selection.spanned_rows(false, &display_map);
13135                            if next_rows.start < rows.end {
13136                                rows.end = next_rows.end;
13137                                group_selections.push(selections_iter.next().unwrap());
13138                            } else {
13139                                break;
13140                            }
13141                        }
13142
13143                        let row_count = rows.end.0 - rows.start.0;
13144
13145                        // Move all selections in this group up by the total number of duplicated rows
13146                        for selection in group_selections {
13147                            let new_start = Point::new(
13148                                selection.start.row.saturating_sub(row_count),
13149                                selection.start.column,
13150                            );
13151
13152                            let new_end = Point::new(
13153                                selection.end.row.saturating_sub(row_count),
13154                                selection.end.column,
13155                            );
13156
13157                            new_ranges.push(new_start..new_end);
13158                        }
13159                    }
13160
13161                    s.select_ranges(new_ranges);
13162                });
13163            }
13164
13165            this.request_autoscroll(Autoscroll::fit(), cx);
13166        });
13167    }
13168
13169    pub fn duplicate_line_up(
13170        &mut self,
13171        _: &DuplicateLineUp,
13172        window: &mut Window,
13173        cx: &mut Context<Self>,
13174    ) {
13175        self.duplicate(true, true, window, cx);
13176    }
13177
13178    pub fn duplicate_line_down(
13179        &mut self,
13180        _: &DuplicateLineDown,
13181        window: &mut Window,
13182        cx: &mut Context<Self>,
13183    ) {
13184        self.duplicate(false, true, window, cx);
13185    }
13186
13187    pub fn duplicate_selection(
13188        &mut self,
13189        _: &DuplicateSelection,
13190        window: &mut Window,
13191        cx: &mut Context<Self>,
13192    ) {
13193        self.duplicate(false, false, window, cx);
13194    }
13195
13196    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13197        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13198        if self.mode.is_single_line() {
13199            cx.propagate();
13200            return;
13201        }
13202
13203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13204        let buffer = self.buffer.read(cx).snapshot(cx);
13205
13206        let mut edits = Vec::new();
13207        let mut unfold_ranges = Vec::new();
13208        let mut refold_creases = Vec::new();
13209
13210        let selections = self.selections.all::<Point>(&display_map);
13211        let mut selections = selections.iter().peekable();
13212        let mut contiguous_row_selections = Vec::new();
13213        let mut new_selections = Vec::new();
13214
13215        while let Some(selection) = selections.next() {
13216            // Find all the selections that span a contiguous row range
13217            let (start_row, end_row) = consume_contiguous_rows(
13218                &mut contiguous_row_selections,
13219                selection,
13220                &display_map,
13221                &mut selections,
13222            );
13223
13224            // Move the text spanned by the row range to be before the line preceding the row range
13225            if start_row.0 > 0 {
13226                let range_to_move = Point::new(
13227                    start_row.previous_row().0,
13228                    buffer.line_len(start_row.previous_row()),
13229                )
13230                    ..Point::new(
13231                        end_row.previous_row().0,
13232                        buffer.line_len(end_row.previous_row()),
13233                    );
13234                let insertion_point = display_map
13235                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13236                    .0;
13237
13238                // Don't move lines across excerpts
13239                if buffer
13240                    .excerpt_containing(insertion_point..range_to_move.end)
13241                    .is_some()
13242                {
13243                    let text = buffer
13244                        .text_for_range(range_to_move.clone())
13245                        .flat_map(|s| s.chars())
13246                        .skip(1)
13247                        .chain(['\n'])
13248                        .collect::<String>();
13249
13250                    edits.push((
13251                        buffer.anchor_after(range_to_move.start)
13252                            ..buffer.anchor_before(range_to_move.end),
13253                        String::new(),
13254                    ));
13255                    let insertion_anchor = buffer.anchor_after(insertion_point);
13256                    edits.push((insertion_anchor..insertion_anchor, text));
13257
13258                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13259
13260                    // Move selections up
13261                    new_selections.extend(contiguous_row_selections.drain(..).map(
13262                        |mut selection| {
13263                            selection.start.row -= row_delta;
13264                            selection.end.row -= row_delta;
13265                            selection
13266                        },
13267                    ));
13268
13269                    // Move folds up
13270                    unfold_ranges.push(range_to_move.clone());
13271                    for fold in display_map.folds_in_range(
13272                        buffer.anchor_before(range_to_move.start)
13273                            ..buffer.anchor_after(range_to_move.end),
13274                    ) {
13275                        let mut start = fold.range.start.to_point(&buffer);
13276                        let mut end = fold.range.end.to_point(&buffer);
13277                        start.row -= row_delta;
13278                        end.row -= row_delta;
13279                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13280                    }
13281                }
13282            }
13283
13284            // If we didn't move line(s), preserve the existing selections
13285            new_selections.append(&mut contiguous_row_selections);
13286        }
13287
13288        self.transact(window, cx, |this, window, cx| {
13289            this.unfold_ranges(&unfold_ranges, true, true, cx);
13290            this.buffer.update(cx, |buffer, cx| {
13291                for (range, text) in edits {
13292                    buffer.edit([(range, text)], None, cx);
13293                }
13294            });
13295            this.fold_creases(refold_creases, true, window, cx);
13296            this.change_selections(Default::default(), window, cx, |s| {
13297                s.select(new_selections);
13298            })
13299        });
13300    }
13301
13302    pub fn move_line_down(
13303        &mut self,
13304        _: &MoveLineDown,
13305        window: &mut Window,
13306        cx: &mut Context<Self>,
13307    ) {
13308        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13309        if self.mode.is_single_line() {
13310            cx.propagate();
13311            return;
13312        }
13313
13314        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13315        let buffer = self.buffer.read(cx).snapshot(cx);
13316
13317        let mut edits = Vec::new();
13318        let mut unfold_ranges = Vec::new();
13319        let mut refold_creases = Vec::new();
13320
13321        let selections = self.selections.all::<Point>(&display_map);
13322        let mut selections = selections.iter().peekable();
13323        let mut contiguous_row_selections = Vec::new();
13324        let mut new_selections = Vec::new();
13325
13326        while let Some(selection) = selections.next() {
13327            // Find all the selections that span a contiguous row range
13328            let (start_row, end_row) = consume_contiguous_rows(
13329                &mut contiguous_row_selections,
13330                selection,
13331                &display_map,
13332                &mut selections,
13333            );
13334
13335            // Move the text spanned by the row range to be after the last line of the row range
13336            if end_row.0 <= buffer.max_point().row {
13337                let range_to_move =
13338                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13339                let insertion_point = display_map
13340                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13341                    .0;
13342
13343                // Don't move lines across excerpt boundaries
13344                if buffer
13345                    .excerpt_containing(range_to_move.start..insertion_point)
13346                    .is_some()
13347                {
13348                    let mut text = String::from("\n");
13349                    text.extend(buffer.text_for_range(range_to_move.clone()));
13350                    text.pop(); // Drop trailing newline
13351                    edits.push((
13352                        buffer.anchor_after(range_to_move.start)
13353                            ..buffer.anchor_before(range_to_move.end),
13354                        String::new(),
13355                    ));
13356                    let insertion_anchor = buffer.anchor_after(insertion_point);
13357                    edits.push((insertion_anchor..insertion_anchor, text));
13358
13359                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13360
13361                    // Move selections down
13362                    new_selections.extend(contiguous_row_selections.drain(..).map(
13363                        |mut selection| {
13364                            selection.start.row += row_delta;
13365                            selection.end.row += row_delta;
13366                            selection
13367                        },
13368                    ));
13369
13370                    // Move folds down
13371                    unfold_ranges.push(range_to_move.clone());
13372                    for fold in display_map.folds_in_range(
13373                        buffer.anchor_before(range_to_move.start)
13374                            ..buffer.anchor_after(range_to_move.end),
13375                    ) {
13376                        let mut start = fold.range.start.to_point(&buffer);
13377                        let mut end = fold.range.end.to_point(&buffer);
13378                        start.row += row_delta;
13379                        end.row += row_delta;
13380                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13381                    }
13382                }
13383            }
13384
13385            // If we didn't move line(s), preserve the existing selections
13386            new_selections.append(&mut contiguous_row_selections);
13387        }
13388
13389        self.transact(window, cx, |this, window, cx| {
13390            this.unfold_ranges(&unfold_ranges, true, true, cx);
13391            this.buffer.update(cx, |buffer, cx| {
13392                for (range, text) in edits {
13393                    buffer.edit([(range, text)], None, cx);
13394                }
13395            });
13396            this.fold_creases(refold_creases, true, window, cx);
13397            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13398        });
13399    }
13400
13401    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13402        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13403        let text_layout_details = &self.text_layout_details(window, cx);
13404        self.transact(window, cx, |this, window, cx| {
13405            let edits = this.change_selections(Default::default(), window, cx, |s| {
13406                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13407                s.move_with(&mut |display_map, selection| {
13408                    if !selection.is_empty() {
13409                        return;
13410                    }
13411
13412                    let mut head = selection.head();
13413                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13414                    if head.column() == display_map.line_len(head.row()) {
13415                        transpose_offset = display_map
13416                            .buffer_snapshot()
13417                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13418                    }
13419
13420                    if transpose_offset == MultiBufferOffset(0) {
13421                        return;
13422                    }
13423
13424                    *head.column_mut() += 1;
13425                    head = display_map.clip_point(head, Bias::Right);
13426                    let goal = SelectionGoal::HorizontalPosition(
13427                        display_map
13428                            .x_for_display_point(head, text_layout_details)
13429                            .into(),
13430                    );
13431                    selection.collapse_to(head, goal);
13432
13433                    let transpose_start = display_map
13434                        .buffer_snapshot()
13435                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13436                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13437                        let transpose_end = display_map
13438                            .buffer_snapshot()
13439                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13440                        if let Some(ch) = display_map
13441                            .buffer_snapshot()
13442                            .chars_at(transpose_start)
13443                            .next()
13444                        {
13445                            edits.push((transpose_start..transpose_offset, String::new()));
13446                            edits.push((transpose_end..transpose_end, ch.to_string()));
13447                        }
13448                    }
13449                });
13450                edits
13451            });
13452            this.buffer
13453                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13454            let selections = this
13455                .selections
13456                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13457            this.change_selections(Default::default(), window, cx, |s| {
13458                s.select(selections);
13459            });
13460        });
13461    }
13462
13463    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13464        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13465        if self.mode.is_single_line() {
13466            cx.propagate();
13467            return;
13468        }
13469
13470        self.rewrap_impl(RewrapOptions::default(), cx)
13471    }
13472
13473    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13474        let buffer = self.buffer.read(cx).snapshot(cx);
13475        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13476
13477        #[derive(Clone, Debug, PartialEq)]
13478        enum CommentFormat {
13479            /// single line comment, with prefix for line
13480            Line(String),
13481            /// single line within a block comment, with prefix for line
13482            BlockLine(String),
13483            /// a single line of a block comment that includes the initial delimiter
13484            BlockCommentWithStart(BlockCommentConfig),
13485            /// a single line of a block comment that includes the ending delimiter
13486            BlockCommentWithEnd(BlockCommentConfig),
13487        }
13488
13489        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13490        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13491            let language_settings = buffer.language_settings_at(selection.head(), cx);
13492            let language_scope = buffer.language_scope_at(selection.head());
13493
13494            let indent_and_prefix_for_row =
13495                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13496                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13497                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13498                        &language_scope
13499                    {
13500                        let indent_end = Point::new(row, indent.len);
13501                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13502                        let line_text_after_indent = buffer
13503                            .text_for_range(indent_end..line_end)
13504                            .collect::<String>();
13505
13506                        let is_within_comment_override = buffer
13507                            .language_scope_at(indent_end)
13508                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13509                        let comment_delimiters = if is_within_comment_override {
13510                            // we are within a comment syntax node, but we don't
13511                            // yet know what kind of comment: block, doc or line
13512                            match (
13513                                language_scope.documentation_comment(),
13514                                language_scope.block_comment(),
13515                            ) {
13516                                (Some(config), _) | (_, Some(config))
13517                                    if buffer.contains_str_at(indent_end, &config.start) =>
13518                                {
13519                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13520                                }
13521                                (Some(config), _) | (_, Some(config))
13522                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13523                                {
13524                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13525                                }
13526                                (Some(config), _) | (_, Some(config))
13527                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13528                                {
13529                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13530                                }
13531                                (_, _) => language_scope
13532                                    .line_comment_prefixes()
13533                                    .iter()
13534                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13535                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13536                            }
13537                        } else {
13538                            // we not in an overridden comment node, but we may
13539                            // be within a non-overridden line comment node
13540                            language_scope
13541                                .line_comment_prefixes()
13542                                .iter()
13543                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13544                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13545                        };
13546
13547                        let rewrap_prefix = language_scope
13548                            .rewrap_prefixes()
13549                            .iter()
13550                            .find_map(|prefix_regex| {
13551                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13552                                    if mat.start() == 0 {
13553                                        Some(mat.as_str().to_string())
13554                                    } else {
13555                                        None
13556                                    }
13557                                })
13558                            })
13559                            .flatten();
13560                        (comment_delimiters, rewrap_prefix)
13561                    } else {
13562                        (None, None)
13563                    };
13564                    (indent, comment_prefix, rewrap_prefix)
13565                };
13566
13567            let mut start_row = selection.start.row;
13568            let mut end_row = selection.end.row;
13569
13570            if selection.is_empty() {
13571                let cursor_row = selection.start.row;
13572
13573                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13574                let line_prefix = match &comment_prefix {
13575                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13576                        Some(prefix.as_str())
13577                    }
13578                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13579                        prefix, ..
13580                    })) => Some(prefix.as_ref()),
13581                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13582                        start: _,
13583                        end: _,
13584                        prefix,
13585                        tab_size,
13586                    })) => {
13587                        indent_size.len += tab_size;
13588                        Some(prefix.as_ref())
13589                    }
13590                    None => None,
13591                };
13592                let indent_prefix = indent_size.chars().collect::<String>();
13593                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13594
13595                'expand_upwards: while start_row > 0 {
13596                    let prev_row = start_row - 1;
13597                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13598                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13599                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13600                    {
13601                        start_row = prev_row;
13602                    } else {
13603                        break 'expand_upwards;
13604                    }
13605                }
13606
13607                'expand_downwards: while end_row < buffer.max_point().row {
13608                    let next_row = end_row + 1;
13609                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13610                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13611                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13612                    {
13613                        end_row = next_row;
13614                    } else {
13615                        break 'expand_downwards;
13616                    }
13617                }
13618            }
13619
13620            let mut non_blank_rows_iter = (start_row..=end_row)
13621                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13622                .peekable();
13623
13624            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13625                row
13626            } else {
13627                return Vec::new();
13628            };
13629
13630            let mut ranges = Vec::new();
13631
13632            let mut current_range_start = first_row;
13633            let mut prev_row = first_row;
13634            let (
13635                mut current_range_indent,
13636                mut current_range_comment_delimiters,
13637                mut current_range_rewrap_prefix,
13638            ) = indent_and_prefix_for_row(first_row);
13639
13640            for row in non_blank_rows_iter.skip(1) {
13641                let has_paragraph_break = row > prev_row + 1;
13642
13643                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13644                    indent_and_prefix_for_row(row);
13645
13646                let has_indent_change = row_indent != current_range_indent;
13647                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13648
13649                let has_boundary_change = has_comment_change
13650                    || row_rewrap_prefix.is_some()
13651                    || (has_indent_change && current_range_comment_delimiters.is_some());
13652
13653                if has_paragraph_break || has_boundary_change {
13654                    ranges.push((
13655                        language_settings.clone(),
13656                        Point::new(current_range_start, 0)
13657                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13658                        current_range_indent,
13659                        current_range_comment_delimiters.clone(),
13660                        current_range_rewrap_prefix.clone(),
13661                    ));
13662                    current_range_start = row;
13663                    current_range_indent = row_indent;
13664                    current_range_comment_delimiters = row_comment_delimiters;
13665                    current_range_rewrap_prefix = row_rewrap_prefix;
13666                }
13667                prev_row = row;
13668            }
13669
13670            ranges.push((
13671                language_settings.clone(),
13672                Point::new(current_range_start, 0)
13673                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13674                current_range_indent,
13675                current_range_comment_delimiters,
13676                current_range_rewrap_prefix,
13677            ));
13678
13679            ranges
13680        });
13681
13682        let mut edits = Vec::new();
13683        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13684
13685        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13686            wrap_ranges
13687        {
13688            let start_row = wrap_range.start.row;
13689            let end_row = wrap_range.end.row;
13690
13691            // Skip selections that overlap with a range that has already been rewrapped.
13692            let selection_range = start_row..end_row;
13693            if rewrapped_row_ranges
13694                .iter()
13695                .any(|range| range.overlaps(&selection_range))
13696            {
13697                continue;
13698            }
13699
13700            let tab_size = language_settings.tab_size;
13701
13702            let (line_prefix, inside_comment) = match &comment_prefix {
13703                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13704                    (Some(prefix.as_str()), true)
13705                }
13706                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13707                    (Some(prefix.as_ref()), true)
13708                }
13709                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13710                    start: _,
13711                    end: _,
13712                    prefix,
13713                    tab_size,
13714                })) => {
13715                    indent_size.len += tab_size;
13716                    (Some(prefix.as_ref()), true)
13717                }
13718                None => (None, false),
13719            };
13720            let indent_prefix = indent_size.chars().collect::<String>();
13721            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13722
13723            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13724                RewrapBehavior::InComments => inside_comment,
13725                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13726                RewrapBehavior::Anywhere => true,
13727            };
13728
13729            let should_rewrap = options.override_language_settings
13730                || allow_rewrap_based_on_language
13731                || self.hard_wrap.is_some();
13732            if !should_rewrap {
13733                continue;
13734            }
13735
13736            let start = Point::new(start_row, 0);
13737            let start_offset = ToOffset::to_offset(&start, &buffer);
13738            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13739            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13740            let mut first_line_delimiter = None;
13741            let mut last_line_delimiter = None;
13742            let Some(lines_without_prefixes) = selection_text
13743                .lines()
13744                .enumerate()
13745                .map(|(ix, line)| {
13746                    let line_trimmed = line.trim_start();
13747                    if rewrap_prefix.is_some() && ix > 0 {
13748                        Ok(line_trimmed)
13749                    } else if let Some(
13750                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13751                            start,
13752                            prefix,
13753                            end,
13754                            tab_size,
13755                        })
13756                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13757                            start,
13758                            prefix,
13759                            end,
13760                            tab_size,
13761                        }),
13762                    ) = &comment_prefix
13763                    {
13764                        let line_trimmed = line_trimmed
13765                            .strip_prefix(start.as_ref())
13766                            .map(|s| {
13767                                let mut indent_size = indent_size;
13768                                indent_size.len -= tab_size;
13769                                let indent_prefix: String = indent_size.chars().collect();
13770                                first_line_delimiter = Some((indent_prefix, start));
13771                                s.trim_start()
13772                            })
13773                            .unwrap_or(line_trimmed);
13774                        let line_trimmed = line_trimmed
13775                            .strip_suffix(end.as_ref())
13776                            .map(|s| {
13777                                last_line_delimiter = Some(end);
13778                                s.trim_end()
13779                            })
13780                            .unwrap_or(line_trimmed);
13781                        let line_trimmed = line_trimmed
13782                            .strip_prefix(prefix.as_ref())
13783                            .unwrap_or(line_trimmed);
13784                        Ok(line_trimmed)
13785                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13786                        line_trimmed.strip_prefix(prefix).with_context(|| {
13787                            format!("line did not start with prefix {prefix:?}: {line:?}")
13788                        })
13789                    } else {
13790                        line_trimmed
13791                            .strip_prefix(&line_prefix.trim_start())
13792                            .with_context(|| {
13793                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13794                            })
13795                    }
13796                })
13797                .collect::<Result<Vec<_>, _>>()
13798                .log_err()
13799            else {
13800                continue;
13801            };
13802
13803            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13804                buffer
13805                    .language_settings_at(Point::new(start_row, 0), cx)
13806                    .preferred_line_length as usize
13807            });
13808
13809            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13810                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13811            } else {
13812                line_prefix.clone()
13813            };
13814
13815            let wrapped_text = {
13816                let mut wrapped_text = wrap_with_prefix(
13817                    line_prefix,
13818                    subsequent_lines_prefix,
13819                    lines_without_prefixes.join("\n"),
13820                    wrap_column,
13821                    tab_size,
13822                    options.preserve_existing_whitespace,
13823                );
13824
13825                if let Some((indent, delimiter)) = first_line_delimiter {
13826                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13827                }
13828                if let Some(last_line) = last_line_delimiter {
13829                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13830                }
13831
13832                wrapped_text
13833            };
13834
13835            // TODO: should always use char-based diff while still supporting cursor behavior that
13836            // matches vim.
13837            let mut diff_options = DiffOptions::default();
13838            if options.override_language_settings {
13839                diff_options.max_word_diff_len = 0;
13840                diff_options.max_word_diff_line_count = 0;
13841            } else {
13842                diff_options.max_word_diff_len = usize::MAX;
13843                diff_options.max_word_diff_line_count = usize::MAX;
13844            }
13845
13846            for (old_range, new_text) in
13847                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13848            {
13849                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13850                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13851                edits.push((edit_start..edit_end, new_text));
13852            }
13853
13854            rewrapped_row_ranges.push(start_row..=end_row);
13855        }
13856
13857        self.buffer
13858            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13859    }
13860
13861    pub fn cut_common(
13862        &mut self,
13863        cut_no_selection_line: bool,
13864        window: &mut Window,
13865        cx: &mut Context<Self>,
13866    ) -> ClipboardItem {
13867        let mut text = String::new();
13868        let buffer = self.buffer.read(cx).snapshot(cx);
13869        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13870        let mut clipboard_selections = Vec::with_capacity(selections.len());
13871        {
13872            let max_point = buffer.max_point();
13873            let mut is_first = true;
13874            let mut prev_selection_was_entire_line = false;
13875            for selection in &mut selections {
13876                let is_entire_line =
13877                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13878                if is_entire_line {
13879                    selection.start = Point::new(selection.start.row, 0);
13880                    if !selection.is_empty() && selection.end.column == 0 {
13881                        selection.end = cmp::min(max_point, selection.end);
13882                    } else {
13883                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13884                    }
13885                    selection.goal = SelectionGoal::None;
13886                }
13887                if is_first {
13888                    is_first = false;
13889                } else if !prev_selection_was_entire_line {
13890                    text += "\n";
13891                }
13892                prev_selection_was_entire_line = is_entire_line;
13893                let mut len = 0;
13894                for chunk in buffer.text_for_range(selection.start..selection.end) {
13895                    text.push_str(chunk);
13896                    len += chunk.len();
13897                }
13898
13899                clipboard_selections.push(ClipboardSelection::for_buffer(
13900                    len,
13901                    is_entire_line,
13902                    selection.range(),
13903                    &buffer,
13904                    self.project.as_ref(),
13905                    cx,
13906                ));
13907            }
13908        }
13909
13910        self.transact(window, cx, |this, window, cx| {
13911            this.change_selections(Default::default(), window, cx, |s| {
13912                s.select(selections);
13913            });
13914            this.insert("", window, cx);
13915        });
13916        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13917    }
13918
13919    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13920        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13921        let item = self.cut_common(true, window, cx);
13922        cx.write_to_clipboard(item);
13923    }
13924
13925    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13927        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13928            s.move_with(&mut |snapshot, sel| {
13929                if sel.is_empty() {
13930                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13931                }
13932                if sel.is_empty() {
13933                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13934                }
13935            });
13936        });
13937        let item = self.cut_common(false, window, cx);
13938        cx.set_global(KillRing(item))
13939    }
13940
13941    pub fn kill_ring_yank(
13942        &mut self,
13943        _: &KillRingYank,
13944        window: &mut Window,
13945        cx: &mut Context<Self>,
13946    ) {
13947        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13948        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13949            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13950                (kill_ring.text().to_string(), kill_ring.metadata_json())
13951            } else {
13952                return;
13953            }
13954        } else {
13955            return;
13956        };
13957        self.do_paste(&text, metadata, false, window, cx);
13958    }
13959
13960    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13961        self.do_copy(true, cx);
13962    }
13963
13964    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13965        self.do_copy(false, cx);
13966    }
13967
13968    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13969        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13970        let buffer = self.buffer.read(cx).read(cx);
13971        let mut text = String::new();
13972        let mut clipboard_selections = Vec::with_capacity(selections.len());
13973
13974        let max_point = buffer.max_point();
13975        let mut is_first = true;
13976        for selection in &selections {
13977            let mut start = selection.start;
13978            let mut end = selection.end;
13979            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13980            let mut add_trailing_newline = false;
13981            if is_entire_line {
13982                start = Point::new(start.row, 0);
13983                let next_line_start = Point::new(end.row + 1, 0);
13984                if next_line_start <= max_point {
13985                    end = next_line_start;
13986                } else {
13987                    // We're on the last line without a trailing newline.
13988                    // Copy to the end of the line and add a newline afterwards.
13989                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13990                    add_trailing_newline = true;
13991                }
13992            }
13993
13994            let mut trimmed_selections = Vec::new();
13995            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13996                let row = MultiBufferRow(start.row);
13997                let first_indent = buffer.indent_size_for_line(row);
13998                if first_indent.len == 0 || start.column > first_indent.len {
13999                    trimmed_selections.push(start..end);
14000                } else {
14001                    trimmed_selections.push(
14002                        Point::new(row.0, first_indent.len)
14003                            ..Point::new(row.0, buffer.line_len(row)),
14004                    );
14005                    for row in start.row + 1..=end.row {
14006                        let mut line_len = buffer.line_len(MultiBufferRow(row));
14007                        if row == end.row {
14008                            line_len = end.column;
14009                        }
14010                        if line_len == 0 {
14011                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
14012                            continue;
14013                        }
14014                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
14015                        if row_indent_size.len >= first_indent.len {
14016                            trimmed_selections
14017                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
14018                        } else {
14019                            trimmed_selections.clear();
14020                            trimmed_selections.push(start..end);
14021                            break;
14022                        }
14023                    }
14024                }
14025            } else {
14026                trimmed_selections.push(start..end);
14027            }
14028
14029            let is_multiline_trim = trimmed_selections.len() > 1;
14030            let mut selection_len: usize = 0;
14031            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
14032
14033            for trimmed_range in trimmed_selections {
14034                if is_first {
14035                    is_first = false;
14036                } else if is_multiline_trim || !prev_selection_was_entire_line {
14037                    text.push('\n');
14038                    if is_multiline_trim {
14039                        selection_len += 1;
14040                    }
14041                }
14042                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
14043                    text.push_str(chunk);
14044                    selection_len += chunk.len();
14045                }
14046                if add_trailing_newline {
14047                    text.push('\n');
14048                    selection_len += 1;
14049                }
14050            }
14051
14052            clipboard_selections.push(ClipboardSelection::for_buffer(
14053                selection_len,
14054                is_entire_line,
14055                start..end,
14056                &buffer,
14057                self.project.as_ref(),
14058                cx,
14059            ));
14060        }
14061
14062        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
14063            text,
14064            clipboard_selections,
14065        ));
14066    }
14067
14068    pub fn do_paste(
14069        &mut self,
14070        text: &String,
14071        clipboard_selections: Option<Vec<ClipboardSelection>>,
14072        handle_entire_lines: bool,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        if self.read_only(cx) {
14077            return;
14078        }
14079
14080        self.finalize_last_transaction(cx);
14081
14082        let clipboard_text = Cow::Borrowed(text.as_str());
14083
14084        self.transact(window, cx, |this, window, cx| {
14085            let had_active_edit_prediction = this.has_active_edit_prediction();
14086            let display_map = this.display_snapshot(cx);
14087            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14088            let cursor_offset = this
14089                .selections
14090                .last::<MultiBufferOffset>(&display_map)
14091                .head();
14092
14093            if let Some(mut clipboard_selections) = clipboard_selections {
14094                let all_selections_were_entire_line =
14095                    clipboard_selections.iter().all(|s| s.is_entire_line);
14096                let first_selection_indent_column =
14097                    clipboard_selections.first().map(|s| s.first_line_indent);
14098                if clipboard_selections.len() != old_selections.len() {
14099                    clipboard_selections.drain(..);
14100                }
14101                let mut auto_indent_on_paste = true;
14102
14103                this.buffer.update(cx, |buffer, cx| {
14104                    let snapshot = buffer.read(cx);
14105                    auto_indent_on_paste = snapshot
14106                        .language_settings_at(cursor_offset, cx)
14107                        .auto_indent_on_paste;
14108
14109                    let mut start_offset = 0;
14110                    let mut edits = Vec::new();
14111                    let mut original_indent_columns = Vec::new();
14112                    for (ix, selection) in old_selections.iter().enumerate() {
14113                        let to_insert;
14114                        let entire_line;
14115                        let original_indent_column;
14116                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14117                            let end_offset = start_offset + clipboard_selection.len;
14118                            to_insert = &clipboard_text[start_offset..end_offset];
14119                            entire_line = clipboard_selection.is_entire_line;
14120                            start_offset = if entire_line {
14121                                end_offset
14122                            } else {
14123                                end_offset + 1
14124                            };
14125                            original_indent_column = Some(clipboard_selection.first_line_indent);
14126                        } else {
14127                            to_insert = &*clipboard_text;
14128                            entire_line = all_selections_were_entire_line;
14129                            original_indent_column = first_selection_indent_column
14130                        }
14131
14132                        let (range, to_insert) =
14133                            if selection.is_empty() && handle_entire_lines && entire_line {
14134                                // If the corresponding selection was empty when this slice of the
14135                                // clipboard text was written, then the entire line containing the
14136                                // selection was copied. If this selection is also currently empty,
14137                                // then paste the line before the current line of the buffer.
14138                                let column = selection.start.to_point(&snapshot).column as usize;
14139                                let line_start = selection.start - column;
14140                                (line_start..line_start, Cow::Borrowed(to_insert))
14141                            } else {
14142                                let language = snapshot.language_at(selection.head());
14143                                let range = selection.range();
14144                                if let Some(language) = language
14145                                    && language.name() == "Markdown"
14146                                {
14147                                    edit_for_markdown_paste(
14148                                        &snapshot,
14149                                        range,
14150                                        to_insert,
14151                                        url::Url::parse(to_insert).ok(),
14152                                    )
14153                                } else {
14154                                    (range, Cow::Borrowed(to_insert))
14155                                }
14156                            };
14157
14158                        edits.push((range, to_insert));
14159                        original_indent_columns.push(original_indent_column);
14160                    }
14161                    drop(snapshot);
14162
14163                    buffer.edit(
14164                        edits,
14165                        if auto_indent_on_paste {
14166                            Some(AutoindentMode::Block {
14167                                original_indent_columns,
14168                            })
14169                        } else {
14170                            None
14171                        },
14172                        cx,
14173                    );
14174                });
14175
14176                let selections = this
14177                    .selections
14178                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14179                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14180            } else {
14181                let url = url::Url::parse(&clipboard_text).ok();
14182
14183                let auto_indent_mode = if !clipboard_text.is_empty() {
14184                    Some(AutoindentMode::Block {
14185                        original_indent_columns: Vec::new(),
14186                    })
14187                } else {
14188                    None
14189                };
14190
14191                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14192                    let snapshot = buffer.snapshot(cx);
14193
14194                    let anchors = old_selections
14195                        .iter()
14196                        .map(|s| {
14197                            let anchor = snapshot.anchor_after(s.head());
14198                            s.map(|_| anchor)
14199                        })
14200                        .collect::<Vec<_>>();
14201
14202                    let mut edits = Vec::new();
14203
14204                    // When pasting text without metadata (e.g. copied from an
14205                    // external editor using multiple cursors) and the number of
14206                    // lines matches the number of selections, distribute one
14207                    // line per cursor instead of pasting the whole text at each.
14208                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14209                    let distribute_lines =
14210                        old_selections.len() > 1 && lines.len() == old_selections.len();
14211
14212                    for (ix, selection) in old_selections.iter().enumerate() {
14213                        let language = snapshot.language_at(selection.head());
14214                        let range = selection.range();
14215
14216                        let text_for_cursor: &str = if distribute_lines {
14217                            lines[ix]
14218                        } else {
14219                            &clipboard_text
14220                        };
14221
14222                        let (edit_range, edit_text) = if let Some(language) = language
14223                            && language.name() == "Markdown"
14224                        {
14225                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14226                        } else {
14227                            (range, Cow::Borrowed(text_for_cursor))
14228                        };
14229
14230                        edits.push((edit_range, edit_text));
14231                    }
14232
14233                    drop(snapshot);
14234                    buffer.edit(edits, auto_indent_mode, cx);
14235
14236                    anchors
14237                });
14238
14239                this.change_selections(Default::default(), window, cx, |s| {
14240                    s.select_anchors(selection_anchors);
14241                });
14242            }
14243
14244            //   🤔                 |    ..     | show_in_menu |
14245            // | ..                  |   true        true
14246            // | had_edit_prediction |   false       true
14247
14248            let trigger_in_words =
14249                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14250
14251            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14252        });
14253    }
14254
14255    pub fn diff_clipboard_with_selection(
14256        &mut self,
14257        _: &DiffClipboardWithSelection,
14258        window: &mut Window,
14259        cx: &mut Context<Self>,
14260    ) {
14261        let selections = self
14262            .selections
14263            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14264
14265        if selections.is_empty() {
14266            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14267            return;
14268        };
14269
14270        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14271            item.entries().iter().find_map(|entry| match entry {
14272                ClipboardEntry::String(text) => Some(text.text().to_string()),
14273                _ => None,
14274            })
14275        });
14276
14277        let Some(clipboard_text) = clipboard_text else {
14278            log::warn!("Clipboard doesn't contain text.");
14279            return;
14280        };
14281
14282        window.dispatch_action(
14283            Box::new(DiffClipboardWithSelectionData {
14284                clipboard_text,
14285                editor: cx.entity(),
14286            }),
14287            cx,
14288        );
14289    }
14290
14291    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14292        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14293        if let Some(item) = cx.read_from_clipboard() {
14294            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14295                ClipboardEntry::String(s) => Some(s),
14296                _ => None,
14297            });
14298            match clipboard_string {
14299                Some(clipboard_string) => self.do_paste(
14300                    clipboard_string.text(),
14301                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14302                    true,
14303                    window,
14304                    cx,
14305                ),
14306                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14307            }
14308        }
14309    }
14310
14311    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14312        if self.read_only(cx) {
14313            return;
14314        }
14315
14316        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14317
14318        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14319            if let Some((selections, _)) =
14320                self.selection_history.transaction(transaction_id).cloned()
14321            {
14322                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14323                    s.select_anchors(selections.to_vec());
14324                });
14325            } else {
14326                log::error!(
14327                    "No entry in selection_history found for undo. \
14328                     This may correspond to a bug where undo does not update the selection. \
14329                     If this is occurring, please add details to \
14330                     https://github.com/zed-industries/zed/issues/22692"
14331                );
14332            }
14333            self.request_autoscroll(Autoscroll::fit(), cx);
14334            self.unmark_text(window, cx);
14335            self.refresh_edit_prediction(true, false, window, cx);
14336            cx.emit(EditorEvent::Edited { transaction_id });
14337            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14338        }
14339    }
14340
14341    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14342        if self.read_only(cx) {
14343            return;
14344        }
14345
14346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14347
14348        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14349            if let Some((_, Some(selections))) =
14350                self.selection_history.transaction(transaction_id).cloned()
14351            {
14352                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14353                    s.select_anchors(selections.to_vec());
14354                });
14355            } else {
14356                log::error!(
14357                    "No entry in selection_history found for redo. \
14358                     This may correspond to a bug where undo does not update the selection. \
14359                     If this is occurring, please add details to \
14360                     https://github.com/zed-industries/zed/issues/22692"
14361                );
14362            }
14363            self.request_autoscroll(Autoscroll::fit(), cx);
14364            self.unmark_text(window, cx);
14365            self.refresh_edit_prediction(true, false, window, cx);
14366            cx.emit(EditorEvent::Edited { transaction_id });
14367        }
14368    }
14369
14370    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14371        self.buffer
14372            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14373    }
14374
14375    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14376        self.buffer
14377            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14378    }
14379
14380    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14381        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14382        self.change_selections(Default::default(), window, cx, |s| {
14383            s.move_with(&mut |map, selection| {
14384                let cursor = if selection.is_empty() {
14385                    movement::left(map, selection.start)
14386                } else {
14387                    selection.start
14388                };
14389                selection.collapse_to(cursor, SelectionGoal::None);
14390            });
14391        })
14392    }
14393
14394    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14395        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14396        self.change_selections(Default::default(), window, cx, |s| {
14397            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14398        })
14399    }
14400
14401    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14403        self.change_selections(Default::default(), window, cx, |s| {
14404            s.move_with(&mut |map, selection| {
14405                let cursor = if selection.is_empty() {
14406                    movement::right(map, selection.end)
14407                } else {
14408                    selection.end
14409                };
14410                selection.collapse_to(cursor, SelectionGoal::None)
14411            });
14412        })
14413    }
14414
14415    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14416        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14417        self.change_selections(Default::default(), window, cx, |s| {
14418            s.move_heads_with(&mut |map, head, _| {
14419                (movement::right(map, head), SelectionGoal::None)
14420            });
14421        });
14422    }
14423
14424    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14425        if self.take_rename(true, window, cx).is_some() {
14426            return;
14427        }
14428
14429        if self.mode.is_single_line() {
14430            cx.propagate();
14431            return;
14432        }
14433
14434        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14435
14436        let text_layout_details = &self.text_layout_details(window, cx);
14437        let selection_count = self.selections.count();
14438        let first_selection = self.selections.first_anchor();
14439
14440        self.change_selections(Default::default(), window, cx, |s| {
14441            s.move_with(&mut |map, selection| {
14442                if !selection.is_empty() {
14443                    selection.goal = SelectionGoal::None;
14444                }
14445                let (cursor, goal) = movement::up(
14446                    map,
14447                    selection.start,
14448                    selection.goal,
14449                    false,
14450                    text_layout_details,
14451                );
14452                selection.collapse_to(cursor, goal);
14453            });
14454        });
14455
14456        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14457        {
14458            cx.propagate();
14459        }
14460    }
14461
14462    pub fn move_up_by_lines(
14463        &mut self,
14464        action: &MoveUpByLines,
14465        window: &mut Window,
14466        cx: &mut Context<Self>,
14467    ) {
14468        if self.take_rename(true, window, cx).is_some() {
14469            return;
14470        }
14471
14472        if self.mode.is_single_line() {
14473            cx.propagate();
14474            return;
14475        }
14476
14477        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14478
14479        let text_layout_details = &self.text_layout_details(window, cx);
14480
14481        self.change_selections(Default::default(), window, cx, |s| {
14482            s.move_with(&mut |map, selection| {
14483                if !selection.is_empty() {
14484                    selection.goal = SelectionGoal::None;
14485                }
14486                let (cursor, goal) = movement::up_by_rows(
14487                    map,
14488                    selection.start,
14489                    action.lines,
14490                    selection.goal,
14491                    false,
14492                    text_layout_details,
14493                );
14494                selection.collapse_to(cursor, goal);
14495            });
14496        })
14497    }
14498
14499    pub fn move_down_by_lines(
14500        &mut self,
14501        action: &MoveDownByLines,
14502        window: &mut Window,
14503        cx: &mut Context<Self>,
14504    ) {
14505        if self.take_rename(true, window, cx).is_some() {
14506            return;
14507        }
14508
14509        if self.mode.is_single_line() {
14510            cx.propagate();
14511            return;
14512        }
14513
14514        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14515
14516        let text_layout_details = &self.text_layout_details(window, cx);
14517
14518        self.change_selections(Default::default(), window, cx, |s| {
14519            s.move_with(&mut |map, selection| {
14520                if !selection.is_empty() {
14521                    selection.goal = SelectionGoal::None;
14522                }
14523                let (cursor, goal) = movement::down_by_rows(
14524                    map,
14525                    selection.start,
14526                    action.lines,
14527                    selection.goal,
14528                    false,
14529                    text_layout_details,
14530                );
14531                selection.collapse_to(cursor, goal);
14532            });
14533        })
14534    }
14535
14536    pub fn select_down_by_lines(
14537        &mut self,
14538        action: &SelectDownByLines,
14539        window: &mut Window,
14540        cx: &mut Context<Self>,
14541    ) {
14542        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14543        let text_layout_details = &self.text_layout_details(window, cx);
14544        self.change_selections(Default::default(), window, cx, |s| {
14545            s.move_heads_with(&mut |map, head, goal| {
14546                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14547            })
14548        })
14549    }
14550
14551    pub fn select_up_by_lines(
14552        &mut self,
14553        action: &SelectUpByLines,
14554        window: &mut Window,
14555        cx: &mut Context<Self>,
14556    ) {
14557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14558        let text_layout_details = &self.text_layout_details(window, cx);
14559        self.change_selections(Default::default(), window, cx, |s| {
14560            s.move_heads_with(&mut |map, head, goal| {
14561                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14562            })
14563        })
14564    }
14565
14566    pub fn select_page_up(
14567        &mut self,
14568        _: &SelectPageUp,
14569        window: &mut Window,
14570        cx: &mut Context<Self>,
14571    ) {
14572        let Some(row_count) = self.visible_row_count() else {
14573            return;
14574        };
14575
14576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14577
14578        let text_layout_details = &self.text_layout_details(window, cx);
14579
14580        self.change_selections(Default::default(), window, cx, |s| {
14581            s.move_heads_with(&mut |map, head, goal| {
14582                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14583            })
14584        })
14585    }
14586
14587    pub fn move_page_up(
14588        &mut self,
14589        action: &MovePageUp,
14590        window: &mut Window,
14591        cx: &mut Context<Self>,
14592    ) {
14593        if self.take_rename(true, window, cx).is_some() {
14594            return;
14595        }
14596
14597        if self
14598            .context_menu
14599            .borrow_mut()
14600            .as_mut()
14601            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14602            .unwrap_or(false)
14603        {
14604            return;
14605        }
14606
14607        if matches!(self.mode, EditorMode::SingleLine) {
14608            cx.propagate();
14609            return;
14610        }
14611
14612        let Some(row_count) = self.visible_row_count() else {
14613            return;
14614        };
14615
14616        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14617
14618        let effects = if action.center_cursor {
14619            SelectionEffects::scroll(Autoscroll::center())
14620        } else {
14621            SelectionEffects::default()
14622        };
14623
14624        let text_layout_details = &self.text_layout_details(window, cx);
14625
14626        self.change_selections(effects, window, cx, |s| {
14627            s.move_with(&mut |map, selection| {
14628                if !selection.is_empty() {
14629                    selection.goal = SelectionGoal::None;
14630                }
14631                let (cursor, goal) = movement::up_by_rows(
14632                    map,
14633                    selection.end,
14634                    row_count,
14635                    selection.goal,
14636                    false,
14637                    text_layout_details,
14638                );
14639                selection.collapse_to(cursor, goal);
14640            });
14641        });
14642    }
14643
14644    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14646        let text_layout_details = &self.text_layout_details(window, cx);
14647        self.change_selections(Default::default(), window, cx, |s| {
14648            s.move_heads_with(&mut |map, head, goal| {
14649                movement::up(map, head, goal, false, text_layout_details)
14650            })
14651        })
14652    }
14653
14654    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14655        self.take_rename(true, window, cx);
14656
14657        if self.mode.is_single_line() {
14658            cx.propagate();
14659            return;
14660        }
14661
14662        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14663
14664        let text_layout_details = &self.text_layout_details(window, cx);
14665        let selection_count = self.selections.count();
14666        let first_selection = self.selections.first_anchor();
14667
14668        self.change_selections(Default::default(), window, cx, |s| {
14669            s.move_with(&mut |map, selection| {
14670                if !selection.is_empty() {
14671                    selection.goal = SelectionGoal::None;
14672                }
14673                let (cursor, goal) = movement::down(
14674                    map,
14675                    selection.end,
14676                    selection.goal,
14677                    false,
14678                    text_layout_details,
14679                );
14680                selection.collapse_to(cursor, goal);
14681            });
14682        });
14683
14684        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14685        {
14686            cx.propagate();
14687        }
14688    }
14689
14690    pub fn select_page_down(
14691        &mut self,
14692        _: &SelectPageDown,
14693        window: &mut Window,
14694        cx: &mut Context<Self>,
14695    ) {
14696        let Some(row_count) = self.visible_row_count() else {
14697            return;
14698        };
14699
14700        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14701
14702        let text_layout_details = &self.text_layout_details(window, cx);
14703
14704        self.change_selections(Default::default(), window, cx, |s| {
14705            s.move_heads_with(&mut |map, head, goal| {
14706                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14707            })
14708        })
14709    }
14710
14711    pub fn move_page_down(
14712        &mut self,
14713        action: &MovePageDown,
14714        window: &mut Window,
14715        cx: &mut Context<Self>,
14716    ) {
14717        if self.take_rename(true, window, cx).is_some() {
14718            return;
14719        }
14720
14721        if self
14722            .context_menu
14723            .borrow_mut()
14724            .as_mut()
14725            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14726            .unwrap_or(false)
14727        {
14728            return;
14729        }
14730
14731        if matches!(self.mode, EditorMode::SingleLine) {
14732            cx.propagate();
14733            return;
14734        }
14735
14736        let Some(row_count) = self.visible_row_count() else {
14737            return;
14738        };
14739
14740        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14741
14742        let effects = if action.center_cursor {
14743            SelectionEffects::scroll(Autoscroll::center())
14744        } else {
14745            SelectionEffects::default()
14746        };
14747
14748        let text_layout_details = &self.text_layout_details(window, cx);
14749        self.change_selections(effects, window, cx, |s| {
14750            s.move_with(&mut |map, selection| {
14751                if !selection.is_empty() {
14752                    selection.goal = SelectionGoal::None;
14753                }
14754                let (cursor, goal) = movement::down_by_rows(
14755                    map,
14756                    selection.end,
14757                    row_count,
14758                    selection.goal,
14759                    false,
14760                    text_layout_details,
14761                );
14762                selection.collapse_to(cursor, goal);
14763            });
14764        });
14765    }
14766
14767    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14768        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14769        let text_layout_details = &self.text_layout_details(window, cx);
14770        self.change_selections(Default::default(), window, cx, |s| {
14771            s.move_heads_with(&mut |map, head, goal| {
14772                movement::down(map, head, goal, false, text_layout_details)
14773            })
14774        });
14775    }
14776
14777    pub fn context_menu_first(
14778        &mut self,
14779        _: &ContextMenuFirst,
14780        window: &mut Window,
14781        cx: &mut Context<Self>,
14782    ) {
14783        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14784            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14785        }
14786    }
14787
14788    pub fn context_menu_prev(
14789        &mut self,
14790        _: &ContextMenuPrevious,
14791        window: &mut Window,
14792        cx: &mut Context<Self>,
14793    ) {
14794        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14795            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14796        }
14797    }
14798
14799    pub fn context_menu_next(
14800        &mut self,
14801        _: &ContextMenuNext,
14802        window: &mut Window,
14803        cx: &mut Context<Self>,
14804    ) {
14805        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14806            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14807        }
14808    }
14809
14810    pub fn context_menu_last(
14811        &mut self,
14812        _: &ContextMenuLast,
14813        window: &mut Window,
14814        cx: &mut Context<Self>,
14815    ) {
14816        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14817            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14818        }
14819    }
14820
14821    pub fn signature_help_prev(
14822        &mut self,
14823        _: &SignatureHelpPrevious,
14824        _: &mut Window,
14825        cx: &mut Context<Self>,
14826    ) {
14827        if let Some(popover) = self.signature_help_state.popover_mut() {
14828            if popover.current_signature == 0 {
14829                popover.current_signature = popover.signatures.len() - 1;
14830            } else {
14831                popover.current_signature -= 1;
14832            }
14833            cx.notify();
14834        }
14835    }
14836
14837    pub fn signature_help_next(
14838        &mut self,
14839        _: &SignatureHelpNext,
14840        _: &mut Window,
14841        cx: &mut Context<Self>,
14842    ) {
14843        if let Some(popover) = self.signature_help_state.popover_mut() {
14844            if popover.current_signature + 1 == popover.signatures.len() {
14845                popover.current_signature = 0;
14846            } else {
14847                popover.current_signature += 1;
14848            }
14849            cx.notify();
14850        }
14851    }
14852
14853    pub fn move_to_previous_word_start(
14854        &mut self,
14855        _: &MoveToPreviousWordStart,
14856        window: &mut Window,
14857        cx: &mut Context<Self>,
14858    ) {
14859        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14860        self.change_selections(Default::default(), window, cx, |s| {
14861            s.move_cursors_with(&mut |map, head, _| {
14862                (
14863                    movement::previous_word_start(map, head),
14864                    SelectionGoal::None,
14865                )
14866            });
14867        })
14868    }
14869
14870    pub fn move_to_previous_subword_start(
14871        &mut self,
14872        _: &MoveToPreviousSubwordStart,
14873        window: &mut Window,
14874        cx: &mut Context<Self>,
14875    ) {
14876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14877        self.change_selections(Default::default(), window, cx, |s| {
14878            s.move_cursors_with(&mut |map, head, _| {
14879                (
14880                    movement::previous_subword_start(map, head),
14881                    SelectionGoal::None,
14882                )
14883            });
14884        })
14885    }
14886
14887    pub fn select_to_previous_word_start(
14888        &mut self,
14889        _: &SelectToPreviousWordStart,
14890        window: &mut Window,
14891        cx: &mut Context<Self>,
14892    ) {
14893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14894        self.change_selections(Default::default(), window, cx, |s| {
14895            s.move_heads_with(&mut |map, head, _| {
14896                (
14897                    movement::previous_word_start(map, head),
14898                    SelectionGoal::None,
14899                )
14900            });
14901        })
14902    }
14903
14904    pub fn select_to_previous_subword_start(
14905        &mut self,
14906        _: &SelectToPreviousSubwordStart,
14907        window: &mut Window,
14908        cx: &mut Context<Self>,
14909    ) {
14910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14911        self.change_selections(Default::default(), window, cx, |s| {
14912            s.move_heads_with(&mut |map, head, _| {
14913                (
14914                    movement::previous_subword_start(map, head),
14915                    SelectionGoal::None,
14916                )
14917            });
14918        })
14919    }
14920
14921    pub fn delete_to_previous_word_start(
14922        &mut self,
14923        action: &DeleteToPreviousWordStart,
14924        window: &mut Window,
14925        cx: &mut Context<Self>,
14926    ) {
14927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14928        self.transact(window, cx, |this, window, cx| {
14929            this.select_autoclose_pair(window, cx);
14930            this.change_selections(Default::default(), window, cx, |s| {
14931                s.move_with(&mut |map, selection| {
14932                    if selection.is_empty() {
14933                        let mut cursor = if action.ignore_newlines {
14934                            movement::previous_word_start(map, selection.head())
14935                        } else {
14936                            movement::previous_word_start_or_newline(map, selection.head())
14937                        };
14938                        cursor = movement::adjust_greedy_deletion(
14939                            map,
14940                            selection.head(),
14941                            cursor,
14942                            action.ignore_brackets,
14943                        );
14944                        selection.set_head(cursor, SelectionGoal::None);
14945                    }
14946                });
14947            });
14948            this.insert("", window, cx);
14949        });
14950    }
14951
14952    pub fn delete_to_previous_subword_start(
14953        &mut self,
14954        action: &DeleteToPreviousSubwordStart,
14955        window: &mut Window,
14956        cx: &mut Context<Self>,
14957    ) {
14958        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14959        self.transact(window, cx, |this, window, cx| {
14960            this.select_autoclose_pair(window, cx);
14961            this.change_selections(Default::default(), window, cx, |s| {
14962                s.move_with(&mut |map, selection| {
14963                    if selection.is_empty() {
14964                        let mut cursor = if action.ignore_newlines {
14965                            movement::previous_subword_start(map, selection.head())
14966                        } else {
14967                            movement::previous_subword_start_or_newline(map, selection.head())
14968                        };
14969                        cursor = movement::adjust_greedy_deletion(
14970                            map,
14971                            selection.head(),
14972                            cursor,
14973                            action.ignore_brackets,
14974                        );
14975                        selection.set_head(cursor, SelectionGoal::None);
14976                    }
14977                });
14978            });
14979            this.insert("", window, cx);
14980        });
14981    }
14982
14983    pub fn move_to_next_word_end(
14984        &mut self,
14985        _: &MoveToNextWordEnd,
14986        window: &mut Window,
14987        cx: &mut Context<Self>,
14988    ) {
14989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14990        self.change_selections(Default::default(), window, cx, |s| {
14991            s.move_cursors_with(&mut |map, head, _| {
14992                (movement::next_word_end(map, head), SelectionGoal::None)
14993            });
14994        })
14995    }
14996
14997    pub fn move_to_next_subword_end(
14998        &mut self,
14999        _: &MoveToNextSubwordEnd,
15000        window: &mut Window,
15001        cx: &mut Context<Self>,
15002    ) {
15003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15004        self.change_selections(Default::default(), window, cx, |s| {
15005            s.move_cursors_with(&mut |map, head, _| {
15006                (movement::next_subword_end(map, head), SelectionGoal::None)
15007            });
15008        })
15009    }
15010
15011    pub fn select_to_next_word_end(
15012        &mut self,
15013        _: &SelectToNextWordEnd,
15014        window: &mut Window,
15015        cx: &mut Context<Self>,
15016    ) {
15017        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15018        self.change_selections(Default::default(), window, cx, |s| {
15019            s.move_heads_with(&mut |map, head, _| {
15020                (movement::next_word_end(map, head), SelectionGoal::None)
15021            });
15022        })
15023    }
15024
15025    pub fn select_to_next_subword_end(
15026        &mut self,
15027        _: &SelectToNextSubwordEnd,
15028        window: &mut Window,
15029        cx: &mut Context<Self>,
15030    ) {
15031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15032        self.change_selections(Default::default(), window, cx, |s| {
15033            s.move_heads_with(&mut |map, head, _| {
15034                (movement::next_subword_end(map, head), SelectionGoal::None)
15035            });
15036        })
15037    }
15038
15039    pub fn delete_to_next_word_end(
15040        &mut self,
15041        action: &DeleteToNextWordEnd,
15042        window: &mut Window,
15043        cx: &mut Context<Self>,
15044    ) {
15045        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15046        self.transact(window, cx, |this, window, cx| {
15047            this.change_selections(Default::default(), window, cx, |s| {
15048                s.move_with(&mut |map, selection| {
15049                    if selection.is_empty() {
15050                        let mut cursor = if action.ignore_newlines {
15051                            movement::next_word_end(map, selection.head())
15052                        } else {
15053                            movement::next_word_end_or_newline(map, selection.head())
15054                        };
15055                        cursor = movement::adjust_greedy_deletion(
15056                            map,
15057                            selection.head(),
15058                            cursor,
15059                            action.ignore_brackets,
15060                        );
15061                        selection.set_head(cursor, SelectionGoal::None);
15062                    }
15063                });
15064            });
15065            this.insert("", window, cx);
15066        });
15067    }
15068
15069    pub fn delete_to_next_subword_end(
15070        &mut self,
15071        action: &DeleteToNextSubwordEnd,
15072        window: &mut Window,
15073        cx: &mut Context<Self>,
15074    ) {
15075        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15076        self.transact(window, cx, |this, window, cx| {
15077            this.change_selections(Default::default(), window, cx, |s| {
15078                s.move_with(&mut |map, selection| {
15079                    if selection.is_empty() {
15080                        let mut cursor = if action.ignore_newlines {
15081                            movement::next_subword_end(map, selection.head())
15082                        } else {
15083                            movement::next_subword_end_or_newline(map, selection.head())
15084                        };
15085                        cursor = movement::adjust_greedy_deletion(
15086                            map,
15087                            selection.head(),
15088                            cursor,
15089                            action.ignore_brackets,
15090                        );
15091                        selection.set_head(cursor, SelectionGoal::None);
15092                    }
15093                });
15094            });
15095            this.insert("", window, cx);
15096        });
15097    }
15098
15099    pub fn move_to_beginning_of_line(
15100        &mut self,
15101        action: &MoveToBeginningOfLine,
15102        window: &mut Window,
15103        cx: &mut Context<Self>,
15104    ) {
15105        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15107        self.change_selections(Default::default(), window, cx, |s| {
15108            s.move_cursors_with(&mut |map, head, _| {
15109                (
15110                    movement::indented_line_beginning(
15111                        map,
15112                        head,
15113                        action.stop_at_soft_wraps,
15114                        stop_at_indent,
15115                    ),
15116                    SelectionGoal::None,
15117                )
15118            });
15119        })
15120    }
15121
15122    pub fn select_to_beginning_of_line(
15123        &mut self,
15124        action: &SelectToBeginningOfLine,
15125        window: &mut Window,
15126        cx: &mut Context<Self>,
15127    ) {
15128        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15129        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15130        self.change_selections(Default::default(), window, cx, |s| {
15131            s.move_heads_with(&mut |map, head, _| {
15132                (
15133                    movement::indented_line_beginning(
15134                        map,
15135                        head,
15136                        action.stop_at_soft_wraps,
15137                        stop_at_indent,
15138                    ),
15139                    SelectionGoal::None,
15140                )
15141            });
15142        });
15143    }
15144
15145    pub fn delete_to_beginning_of_line(
15146        &mut self,
15147        action: &DeleteToBeginningOfLine,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15152        self.transact(window, cx, |this, window, cx| {
15153            this.change_selections(Default::default(), window, cx, |s| {
15154                s.move_with(&mut |_, selection| {
15155                    selection.reversed = true;
15156                });
15157            });
15158
15159            this.select_to_beginning_of_line(
15160                &SelectToBeginningOfLine {
15161                    stop_at_soft_wraps: false,
15162                    stop_at_indent: action.stop_at_indent,
15163                },
15164                window,
15165                cx,
15166            );
15167            this.backspace(&Backspace, window, cx);
15168        });
15169    }
15170
15171    pub fn move_to_end_of_line(
15172        &mut self,
15173        action: &MoveToEndOfLine,
15174        window: &mut Window,
15175        cx: &mut Context<Self>,
15176    ) {
15177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15178        self.change_selections(Default::default(), window, cx, |s| {
15179            s.move_cursors_with(&mut |map, head, _| {
15180                (
15181                    movement::line_end(map, head, action.stop_at_soft_wraps),
15182                    SelectionGoal::None,
15183                )
15184            });
15185        })
15186    }
15187
15188    pub fn select_to_end_of_line(
15189        &mut self,
15190        action: &SelectToEndOfLine,
15191        window: &mut Window,
15192        cx: &mut Context<Self>,
15193    ) {
15194        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15195        self.change_selections(Default::default(), window, cx, |s| {
15196            s.move_heads_with(&mut |map, head, _| {
15197                (
15198                    movement::line_end(map, head, action.stop_at_soft_wraps),
15199                    SelectionGoal::None,
15200                )
15201            });
15202        })
15203    }
15204
15205    pub fn delete_to_end_of_line(
15206        &mut self,
15207        _: &DeleteToEndOfLine,
15208        window: &mut Window,
15209        cx: &mut Context<Self>,
15210    ) {
15211        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15212        self.transact(window, cx, |this, window, cx| {
15213            this.select_to_end_of_line(
15214                &SelectToEndOfLine {
15215                    stop_at_soft_wraps: false,
15216                },
15217                window,
15218                cx,
15219            );
15220            this.delete(&Delete, window, cx);
15221        });
15222    }
15223
15224    pub fn cut_to_end_of_line(
15225        &mut self,
15226        action: &CutToEndOfLine,
15227        window: &mut Window,
15228        cx: &mut Context<Self>,
15229    ) {
15230        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15231        self.transact(window, cx, |this, window, cx| {
15232            this.select_to_end_of_line(
15233                &SelectToEndOfLine {
15234                    stop_at_soft_wraps: false,
15235                },
15236                window,
15237                cx,
15238            );
15239            if !action.stop_at_newlines {
15240                this.change_selections(Default::default(), window, cx, |s| {
15241                    s.move_with(&mut |_, sel| {
15242                        if sel.is_empty() {
15243                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15244                        }
15245                    });
15246                });
15247            }
15248            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15249            let item = this.cut_common(false, window, cx);
15250            cx.write_to_clipboard(item);
15251        });
15252    }
15253
15254    pub fn move_to_start_of_paragraph(
15255        &mut self,
15256        _: &MoveToStartOfParagraph,
15257        window: &mut Window,
15258        cx: &mut Context<Self>,
15259    ) {
15260        if matches!(self.mode, EditorMode::SingleLine) {
15261            cx.propagate();
15262            return;
15263        }
15264        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15265        self.change_selections(Default::default(), window, cx, |s| {
15266            s.move_with(&mut |map, selection| {
15267                selection.collapse_to(
15268                    movement::start_of_paragraph(map, selection.head(), 1),
15269                    SelectionGoal::None,
15270                )
15271            });
15272        })
15273    }
15274
15275    pub fn move_to_end_of_paragraph(
15276        &mut self,
15277        _: &MoveToEndOfParagraph,
15278        window: &mut Window,
15279        cx: &mut Context<Self>,
15280    ) {
15281        if matches!(self.mode, EditorMode::SingleLine) {
15282            cx.propagate();
15283            return;
15284        }
15285        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15286        self.change_selections(Default::default(), window, cx, |s| {
15287            s.move_with(&mut |map, selection| {
15288                selection.collapse_to(
15289                    movement::end_of_paragraph(map, selection.head(), 1),
15290                    SelectionGoal::None,
15291                )
15292            });
15293        })
15294    }
15295
15296    pub fn select_to_start_of_paragraph(
15297        &mut self,
15298        _: &SelectToStartOfParagraph,
15299        window: &mut Window,
15300        cx: &mut Context<Self>,
15301    ) {
15302        if matches!(self.mode, EditorMode::SingleLine) {
15303            cx.propagate();
15304            return;
15305        }
15306        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15307        self.change_selections(Default::default(), window, cx, |s| {
15308            s.move_heads_with(&mut |map, head, _| {
15309                (
15310                    movement::start_of_paragraph(map, head, 1),
15311                    SelectionGoal::None,
15312                )
15313            });
15314        })
15315    }
15316
15317    pub fn select_to_end_of_paragraph(
15318        &mut self,
15319        _: &SelectToEndOfParagraph,
15320        window: &mut Window,
15321        cx: &mut Context<Self>,
15322    ) {
15323        if matches!(self.mode, EditorMode::SingleLine) {
15324            cx.propagate();
15325            return;
15326        }
15327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15328        self.change_selections(Default::default(), window, cx, |s| {
15329            s.move_heads_with(&mut |map, head, _| {
15330                (
15331                    movement::end_of_paragraph(map, head, 1),
15332                    SelectionGoal::None,
15333                )
15334            });
15335        })
15336    }
15337
15338    pub fn move_to_start_of_excerpt(
15339        &mut self,
15340        _: &MoveToStartOfExcerpt,
15341        window: &mut Window,
15342        cx: &mut Context<Self>,
15343    ) {
15344        if matches!(self.mode, EditorMode::SingleLine) {
15345            cx.propagate();
15346            return;
15347        }
15348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15349        self.change_selections(Default::default(), window, cx, |s| {
15350            s.move_with(&mut |map, selection| {
15351                selection.collapse_to(
15352                    movement::start_of_excerpt(
15353                        map,
15354                        selection.head(),
15355                        workspace::searchable::Direction::Prev,
15356                    ),
15357                    SelectionGoal::None,
15358                )
15359            });
15360        })
15361    }
15362
15363    pub fn move_to_start_of_next_excerpt(
15364        &mut self,
15365        _: &MoveToStartOfNextExcerpt,
15366        window: &mut Window,
15367        cx: &mut Context<Self>,
15368    ) {
15369        if matches!(self.mode, EditorMode::SingleLine) {
15370            cx.propagate();
15371            return;
15372        }
15373
15374        self.change_selections(Default::default(), window, cx, |s| {
15375            s.move_with(&mut |map, selection| {
15376                selection.collapse_to(
15377                    movement::start_of_excerpt(
15378                        map,
15379                        selection.head(),
15380                        workspace::searchable::Direction::Next,
15381                    ),
15382                    SelectionGoal::None,
15383                )
15384            });
15385        })
15386    }
15387
15388    pub fn move_to_end_of_excerpt(
15389        &mut self,
15390        _: &MoveToEndOfExcerpt,
15391        window: &mut Window,
15392        cx: &mut Context<Self>,
15393    ) {
15394        if matches!(self.mode, EditorMode::SingleLine) {
15395            cx.propagate();
15396            return;
15397        }
15398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15399        self.change_selections(Default::default(), window, cx, |s| {
15400            s.move_with(&mut |map, selection| {
15401                selection.collapse_to(
15402                    movement::end_of_excerpt(
15403                        map,
15404                        selection.head(),
15405                        workspace::searchable::Direction::Next,
15406                    ),
15407                    SelectionGoal::None,
15408                )
15409            });
15410        })
15411    }
15412
15413    pub fn move_to_end_of_previous_excerpt(
15414        &mut self,
15415        _: &MoveToEndOfPreviousExcerpt,
15416        window: &mut Window,
15417        cx: &mut Context<Self>,
15418    ) {
15419        if matches!(self.mode, EditorMode::SingleLine) {
15420            cx.propagate();
15421            return;
15422        }
15423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15424        self.change_selections(Default::default(), window, cx, |s| {
15425            s.move_with(&mut |map, selection| {
15426                selection.collapse_to(
15427                    movement::end_of_excerpt(
15428                        map,
15429                        selection.head(),
15430                        workspace::searchable::Direction::Prev,
15431                    ),
15432                    SelectionGoal::None,
15433                )
15434            });
15435        })
15436    }
15437
15438    pub fn select_to_start_of_excerpt(
15439        &mut self,
15440        _: &SelectToStartOfExcerpt,
15441        window: &mut Window,
15442        cx: &mut Context<Self>,
15443    ) {
15444        if matches!(self.mode, EditorMode::SingleLine) {
15445            cx.propagate();
15446            return;
15447        }
15448        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15449        self.change_selections(Default::default(), window, cx, |s| {
15450            s.move_heads_with(&mut |map, head, _| {
15451                (
15452                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15453                    SelectionGoal::None,
15454                )
15455            });
15456        })
15457    }
15458
15459    pub fn select_to_start_of_next_excerpt(
15460        &mut self,
15461        _: &SelectToStartOfNextExcerpt,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) {
15465        if matches!(self.mode, EditorMode::SingleLine) {
15466            cx.propagate();
15467            return;
15468        }
15469        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15470        self.change_selections(Default::default(), window, cx, |s| {
15471            s.move_heads_with(&mut |map, head, _| {
15472                (
15473                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15474                    SelectionGoal::None,
15475                )
15476            });
15477        })
15478    }
15479
15480    pub fn select_to_end_of_excerpt(
15481        &mut self,
15482        _: &SelectToEndOfExcerpt,
15483        window: &mut Window,
15484        cx: &mut Context<Self>,
15485    ) {
15486        if matches!(self.mode, EditorMode::SingleLine) {
15487            cx.propagate();
15488            return;
15489        }
15490        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15491        self.change_selections(Default::default(), window, cx, |s| {
15492            s.move_heads_with(&mut |map, head, _| {
15493                (
15494                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15495                    SelectionGoal::None,
15496                )
15497            });
15498        })
15499    }
15500
15501    pub fn select_to_end_of_previous_excerpt(
15502        &mut self,
15503        _: &SelectToEndOfPreviousExcerpt,
15504        window: &mut Window,
15505        cx: &mut Context<Self>,
15506    ) {
15507        if matches!(self.mode, EditorMode::SingleLine) {
15508            cx.propagate();
15509            return;
15510        }
15511        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15512        self.change_selections(Default::default(), window, cx, |s| {
15513            s.move_heads_with(&mut |map, head, _| {
15514                (
15515                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15516                    SelectionGoal::None,
15517                )
15518            });
15519        })
15520    }
15521
15522    pub fn move_to_beginning(
15523        &mut self,
15524        _: &MoveToBeginning,
15525        window: &mut Window,
15526        cx: &mut Context<Self>,
15527    ) {
15528        if matches!(self.mode, EditorMode::SingleLine) {
15529            cx.propagate();
15530            return;
15531        }
15532        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15533        self.change_selections(Default::default(), window, cx, |s| {
15534            s.select_ranges(vec![Anchor::Min..Anchor::Min]);
15535        });
15536    }
15537
15538    pub fn select_to_beginning(
15539        &mut self,
15540        _: &SelectToBeginning,
15541        window: &mut Window,
15542        cx: &mut Context<Self>,
15543    ) {
15544        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15545        selection.set_head(Point::zero(), SelectionGoal::None);
15546        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15547        self.change_selections(Default::default(), window, cx, |s| {
15548            s.select(vec![selection]);
15549        });
15550    }
15551
15552    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15553        if matches!(self.mode, EditorMode::SingleLine) {
15554            cx.propagate();
15555            return;
15556        }
15557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15558        let cursor = self.buffer.read(cx).read(cx).len();
15559        self.change_selections(Default::default(), window, cx, |s| {
15560            s.select_ranges(vec![cursor..cursor])
15561        });
15562    }
15563
15564    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15565        self.nav_history = nav_history;
15566    }
15567
15568    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15569        self.nav_history.as_ref()
15570    }
15571
15572    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15573        self.push_to_nav_history(
15574            self.selections.newest_anchor().head(),
15575            None,
15576            false,
15577            true,
15578            cx,
15579        );
15580    }
15581
15582    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15583        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15584        let buffer = self.buffer.read(cx).read(cx);
15585        let cursor_position = cursor_anchor.to_point(&buffer);
15586        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15587        let scroll_top_row = scroll_anchor.top_row(&buffer);
15588        drop(buffer);
15589
15590        NavigationData {
15591            cursor_anchor,
15592            cursor_position,
15593            scroll_anchor,
15594            scroll_top_row,
15595        }
15596    }
15597
15598    fn navigation_entry(
15599        &self,
15600        cursor_anchor: Anchor,
15601        cx: &mut Context<Self>,
15602    ) -> Option<NavigationEntry> {
15603        let Some(history) = self.nav_history.clone() else {
15604            return None;
15605        };
15606        let data = self.navigation_data(cursor_anchor, cx);
15607        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15608    }
15609
15610    fn push_to_nav_history(
15611        &mut self,
15612        cursor_anchor: Anchor,
15613        new_position: Option<Point>,
15614        is_deactivate: bool,
15615        always: bool,
15616        cx: &mut Context<Self>,
15617    ) {
15618        let data = self.navigation_data(cursor_anchor, cx);
15619        if let Some(nav_history) = self.nav_history.as_mut() {
15620            if let Some(new_position) = new_position {
15621                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15622                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15623                    return;
15624                }
15625            }
15626
15627            let cursor_row = data.cursor_position.row;
15628            nav_history.push(Some(data), Some(cursor_row), cx);
15629            cx.emit(EditorEvent::PushedToNavHistory {
15630                anchor: cursor_anchor,
15631                is_deactivate,
15632            })
15633        }
15634    }
15635
15636    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15637        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15638        let buffer = self.buffer.read(cx).snapshot(cx);
15639        let mut selection = self
15640            .selections
15641            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15642        selection.set_head(buffer.len(), SelectionGoal::None);
15643        self.change_selections(Default::default(), window, cx, |s| {
15644            s.select(vec![selection]);
15645        });
15646    }
15647
15648    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15650        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15651            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
15652        });
15653    }
15654
15655    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15657        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15658        let mut selections = self.selections.all::<Point>(&display_map);
15659        let max_point = display_map.buffer_snapshot().max_point();
15660        for selection in &mut selections {
15661            let rows = selection.spanned_rows(true, &display_map);
15662            selection.start = Point::new(rows.start.0, 0);
15663            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15664            selection.reversed = false;
15665        }
15666        self.change_selections(Default::default(), window, cx, |s| {
15667            s.select(selections);
15668        });
15669    }
15670
15671    pub fn split_selection_into_lines(
15672        &mut self,
15673        action: &SplitSelectionIntoLines,
15674        window: &mut Window,
15675        cx: &mut Context<Self>,
15676    ) {
15677        let selections = self
15678            .selections
15679            .all::<Point>(&self.display_snapshot(cx))
15680            .into_iter()
15681            .map(|selection| selection.start..selection.end)
15682            .collect::<Vec<_>>();
15683        self.unfold_ranges(&selections, true, false, cx);
15684
15685        let mut new_selection_ranges = Vec::new();
15686        {
15687            let buffer = self.buffer.read(cx).read(cx);
15688            for selection in selections {
15689                for row in selection.start.row..selection.end.row {
15690                    let line_start = Point::new(row, 0);
15691                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15692
15693                    if action.keep_selections {
15694                        // Keep the selection range for each line
15695                        let selection_start = if row == selection.start.row {
15696                            selection.start
15697                        } else {
15698                            line_start
15699                        };
15700                        new_selection_ranges.push(selection_start..line_end);
15701                    } else {
15702                        // Collapse to cursor at end of line
15703                        new_selection_ranges.push(line_end..line_end);
15704                    }
15705                }
15706
15707                let is_multiline_selection = selection.start.row != selection.end.row;
15708                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15709                // so this action feels more ergonomic when paired with other selection operations
15710                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15711                if !should_skip_last {
15712                    if action.keep_selections {
15713                        if is_multiline_selection {
15714                            let line_start = Point::new(selection.end.row, 0);
15715                            new_selection_ranges.push(line_start..selection.end);
15716                        } else {
15717                            new_selection_ranges.push(selection.start..selection.end);
15718                        }
15719                    } else {
15720                        new_selection_ranges.push(selection.end..selection.end);
15721                    }
15722                }
15723            }
15724        }
15725        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15726            s.select_ranges(new_selection_ranges);
15727        });
15728    }
15729
15730    pub fn add_selection_above(
15731        &mut self,
15732        action: &AddSelectionAbove,
15733        window: &mut Window,
15734        cx: &mut Context<Self>,
15735    ) {
15736        self.add_selection(true, action.skip_soft_wrap, window, cx);
15737    }
15738
15739    pub fn add_selection_below(
15740        &mut self,
15741        action: &AddSelectionBelow,
15742        window: &mut Window,
15743        cx: &mut Context<Self>,
15744    ) {
15745        self.add_selection(false, action.skip_soft_wrap, window, cx);
15746    }
15747
15748    fn add_selection(
15749        &mut self,
15750        above: bool,
15751        skip_soft_wrap: bool,
15752        window: &mut Window,
15753        cx: &mut Context<Self>,
15754    ) {
15755        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15756
15757        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15758        let all_selections = self.selections.all::<Point>(&display_map);
15759        let text_layout_details = self.text_layout_details(window, cx);
15760
15761        let (mut columnar_selections, new_selections_to_columnarize) = {
15762            if let Some(state) = self.add_selections_state.as_ref() {
15763                let columnar_selection_ids: HashSet<_> = state
15764                    .groups
15765                    .iter()
15766                    .flat_map(|group| group.stack.iter())
15767                    .copied()
15768                    .collect();
15769
15770                all_selections
15771                    .into_iter()
15772                    .partition(|s| columnar_selection_ids.contains(&s.id))
15773            } else {
15774                (Vec::new(), all_selections)
15775            }
15776        };
15777
15778        let mut state = self
15779            .add_selections_state
15780            .take()
15781            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15782
15783        for selection in new_selections_to_columnarize {
15784            let range = selection.display_range(&display_map).sorted();
15785            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15786            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15787            let positions = start_x.min(end_x)..start_x.max(end_x);
15788            let mut stack = Vec::new();
15789            for row in range.start.row().0..=range.end.row().0 {
15790                if let Some(selection) = self.selections.build_columnar_selection(
15791                    &display_map,
15792                    DisplayRow(row),
15793                    &positions,
15794                    selection.reversed,
15795                    &text_layout_details,
15796                ) {
15797                    stack.push(selection.id);
15798                    columnar_selections.push(selection);
15799                }
15800            }
15801            if !stack.is_empty() {
15802                if above {
15803                    stack.reverse();
15804                }
15805                state.groups.push(AddSelectionsGroup { above, stack });
15806            }
15807        }
15808
15809        let mut final_selections = Vec::new();
15810        let end_row = if above {
15811            DisplayRow(0)
15812        } else {
15813            display_map.max_point().row()
15814        };
15815
15816        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15817        // positions to place new selections, so we need to keep track of the
15818        // column range of the oldest selection in each group, because
15819        // intermediate selections may have been clamped to shorter lines.
15820        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15821            let mut map = HashMap::default();
15822            for group in state.groups.iter() {
15823                if let Some(oldest_id) = group.stack.first() {
15824                    if let Some(oldest_selection) =
15825                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15826                    {
15827                        let snapshot = display_map.buffer_snapshot();
15828                        let start_col =
15829                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15830                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15831                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15832                        for id in &group.stack {
15833                            map.insert(*id, goal_columns.clone());
15834                        }
15835                    }
15836                }
15837            }
15838            map
15839        } else {
15840            HashMap::default()
15841        };
15842
15843        let mut last_added_item_per_group = HashMap::default();
15844        for group in state.groups.iter_mut() {
15845            if let Some(last_id) = group.stack.last() {
15846                last_added_item_per_group.insert(*last_id, group);
15847            }
15848        }
15849
15850        for selection in columnar_selections {
15851            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15852                if above == group.above {
15853                    let range = selection.display_range(&display_map).sorted();
15854                    debug_assert_eq!(range.start.row(), range.end.row());
15855                    let row = range.start.row();
15856                    let positions =
15857                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15858                            Pixels::from(start)..Pixels::from(end)
15859                        } else {
15860                            let start_x =
15861                                display_map.x_for_display_point(range.start, &text_layout_details);
15862                            let end_x =
15863                                display_map.x_for_display_point(range.end, &text_layout_details);
15864                            start_x.min(end_x)..start_x.max(end_x)
15865                        };
15866
15867                    let maybe_new_selection = if skip_soft_wrap {
15868                        let goal_columns = goal_columns_by_selection_id
15869                            .remove(&selection.id)
15870                            .unwrap_or_else(|| {
15871                                let snapshot = display_map.buffer_snapshot();
15872                                let start_col =
15873                                    snapshot.point_to_point_utf16(selection.start).column;
15874                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15875                                start_col.min(end_col)..start_col.max(end_col)
15876                            });
15877                        self.selections.find_next_columnar_selection_by_buffer_row(
15878                            &display_map,
15879                            row,
15880                            end_row,
15881                            above,
15882                            &goal_columns,
15883                            selection.reversed,
15884                            &text_layout_details,
15885                        )
15886                    } else {
15887                        self.selections.find_next_columnar_selection_by_display_row(
15888                            &display_map,
15889                            row,
15890                            end_row,
15891                            above,
15892                            &positions,
15893                            selection.reversed,
15894                            &text_layout_details,
15895                        )
15896                    };
15897
15898                    if let Some(new_selection) = maybe_new_selection {
15899                        group.stack.push(new_selection.id);
15900                        if above {
15901                            final_selections.push(new_selection);
15902                            final_selections.push(selection);
15903                        } else {
15904                            final_selections.push(selection);
15905                            final_selections.push(new_selection);
15906                        }
15907                    } else {
15908                        final_selections.push(selection);
15909                    }
15910                } else {
15911                    group.stack.pop();
15912                }
15913            } else {
15914                final_selections.push(selection);
15915            }
15916        }
15917
15918        self.change_selections(Default::default(), window, cx, |s| {
15919            s.select(final_selections);
15920        });
15921
15922        let final_selection_ids: HashSet<_> = self
15923            .selections
15924            .all::<Point>(&display_map)
15925            .iter()
15926            .map(|s| s.id)
15927            .collect();
15928        state.groups.retain_mut(|group| {
15929            // selections might get merged above so we remove invalid items from stacks
15930            group.stack.retain(|id| final_selection_ids.contains(id));
15931
15932            // single selection in stack can be treated as initial state
15933            group.stack.len() > 1
15934        });
15935
15936        if !state.groups.is_empty() {
15937            self.add_selections_state = Some(state);
15938        }
15939    }
15940
15941    pub fn insert_snippet_at_selections(
15942        &mut self,
15943        action: &InsertSnippet,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) {
15947        self.try_insert_snippet_at_selections(action, window, cx)
15948            .log_err();
15949    }
15950
15951    fn try_insert_snippet_at_selections(
15952        &mut self,
15953        action: &InsertSnippet,
15954        window: &mut Window,
15955        cx: &mut Context<Self>,
15956    ) -> Result<()> {
15957        let insertion_ranges = self
15958            .selections
15959            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15960            .into_iter()
15961            .map(|selection| selection.range())
15962            .collect_vec();
15963
15964        let snippet = if let Some(snippet_body) = &action.snippet {
15965            if action.language.is_none() && action.name.is_none() {
15966                Snippet::parse(snippet_body)?
15967            } else {
15968                bail!("`snippet` is mutually exclusive with `language` and `name`")
15969            }
15970        } else if let Some(name) = &action.name {
15971            let project = self.project().context("no project")?;
15972            let snippet_store = project.read(cx).snippets().read(cx);
15973            let snippet = snippet_store
15974                .snippets_for(action.language.clone(), cx)
15975                .into_iter()
15976                .find(|snippet| snippet.name == *name)
15977                .context("snippet not found")?;
15978            Snippet::parse(&snippet.body)?
15979        } else {
15980            // todo(andrew): open modal to select snippet
15981            bail!("`name` or `snippet` is required")
15982        };
15983
15984        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15985    }
15986
15987    fn select_match_ranges(
15988        &mut self,
15989        range: Range<MultiBufferOffset>,
15990        reversed: bool,
15991        replace_newest: bool,
15992        auto_scroll: Option<Autoscroll>,
15993        window: &mut Window,
15994        cx: &mut Context<Editor>,
15995    ) {
15996        self.unfold_ranges(
15997            std::slice::from_ref(&range),
15998            false,
15999            auto_scroll.is_some(),
16000            cx,
16001        );
16002        let effects = if let Some(scroll) = auto_scroll {
16003            SelectionEffects::scroll(scroll)
16004        } else {
16005            SelectionEffects::no_scroll()
16006        };
16007        self.change_selections(effects, window, cx, |s| {
16008            if replace_newest {
16009                s.delete(s.newest_anchor().id);
16010            }
16011            if reversed {
16012                s.insert_range(range.end..range.start);
16013            } else {
16014                s.insert_range(range);
16015            }
16016        });
16017    }
16018
16019    pub fn select_next_match_internal(
16020        &mut self,
16021        display_map: &DisplaySnapshot,
16022        replace_newest: bool,
16023        autoscroll: Option<Autoscroll>,
16024        window: &mut Window,
16025        cx: &mut Context<Self>,
16026    ) -> Result<()> {
16027        let buffer = display_map.buffer_snapshot();
16028        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16029        if let Some(mut select_next_state) = self.select_next_state.take() {
16030            let query = &select_next_state.query;
16031            if !select_next_state.done {
16032                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16033                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16034                let mut next_selected_range = None;
16035
16036                let bytes_after_last_selection =
16037                    buffer.bytes_in_range(last_selection.end..buffer.len());
16038                let bytes_before_first_selection =
16039                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
16040                let query_matches = query
16041                    .stream_find_iter(bytes_after_last_selection)
16042                    .map(|result| (last_selection.end, result))
16043                    .chain(
16044                        query
16045                            .stream_find_iter(bytes_before_first_selection)
16046                            .map(|result| (MultiBufferOffset(0), result)),
16047                    );
16048
16049                for (start_offset, query_match) in query_matches {
16050                    let query_match = query_match.unwrap(); // can only fail due to I/O
16051                    let offset_range =
16052                        start_offset + query_match.start()..start_offset + query_match.end();
16053
16054                    if !select_next_state.wordwise
16055                        || (!buffer.is_inside_word(offset_range.start, None)
16056                            && !buffer.is_inside_word(offset_range.end, None))
16057                    {
16058                        let idx = selections
16059                            .partition_point(|selection| selection.end <= offset_range.start);
16060                        let overlaps = selections
16061                            .get(idx)
16062                            .map_or(false, |selection| selection.start < offset_range.end);
16063
16064                        if !overlaps {
16065                            next_selected_range = Some(offset_range);
16066                            break;
16067                        }
16068                    }
16069                }
16070
16071                if let Some(next_selected_range) = next_selected_range {
16072                    self.select_match_ranges(
16073                        next_selected_range,
16074                        last_selection.reversed,
16075                        replace_newest,
16076                        autoscroll,
16077                        window,
16078                        cx,
16079                    );
16080                } else {
16081                    select_next_state.done = true;
16082                }
16083            }
16084
16085            self.select_next_state = Some(select_next_state);
16086        } else {
16087            let mut only_carets = true;
16088            let mut same_text_selected = true;
16089            let mut selected_text = None;
16090
16091            let mut selections_iter = selections.iter().peekable();
16092            while let Some(selection) = selections_iter.next() {
16093                if selection.start != selection.end {
16094                    only_carets = false;
16095                }
16096
16097                if same_text_selected {
16098                    if selected_text.is_none() {
16099                        selected_text =
16100                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16101                    }
16102
16103                    if let Some(next_selection) = selections_iter.peek() {
16104                        if next_selection.len() == selection.len() {
16105                            let next_selected_text = buffer
16106                                .text_for_range(next_selection.range())
16107                                .collect::<String>();
16108                            if Some(next_selected_text) != selected_text {
16109                                same_text_selected = false;
16110                                selected_text = None;
16111                            }
16112                        } else {
16113                            same_text_selected = false;
16114                            selected_text = None;
16115                        }
16116                    }
16117                }
16118            }
16119
16120            if only_carets {
16121                for selection in &mut selections {
16122                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16123                    selection.start = word_range.start;
16124                    selection.end = word_range.end;
16125                    selection.goal = SelectionGoal::None;
16126                    selection.reversed = false;
16127                    self.select_match_ranges(
16128                        selection.start..selection.end,
16129                        selection.reversed,
16130                        replace_newest,
16131                        autoscroll,
16132                        window,
16133                        cx,
16134                    );
16135                }
16136
16137                if selections.len() == 1 {
16138                    let selection = selections
16139                        .last()
16140                        .expect("ensured that there's only one selection");
16141                    let query = buffer
16142                        .text_for_range(selection.start..selection.end)
16143                        .collect::<String>();
16144                    let is_empty = query.is_empty();
16145                    let select_state = SelectNextState {
16146                        query: self.build_query(&[query], cx)?,
16147                        wordwise: true,
16148                        done: is_empty,
16149                    };
16150                    self.select_next_state = Some(select_state);
16151                } else {
16152                    self.select_next_state = None;
16153                }
16154            } else if let Some(selected_text) = selected_text {
16155                self.select_next_state = Some(SelectNextState {
16156                    query: self.build_query(&[selected_text], cx)?,
16157                    wordwise: false,
16158                    done: false,
16159                });
16160                self.select_next_match_internal(
16161                    display_map,
16162                    replace_newest,
16163                    autoscroll,
16164                    window,
16165                    cx,
16166                )?;
16167            }
16168        }
16169        Ok(())
16170    }
16171
16172    pub fn select_all_matches(
16173        &mut self,
16174        _action: &SelectAllMatches,
16175        window: &mut Window,
16176        cx: &mut Context<Self>,
16177    ) -> Result<()> {
16178        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16179
16180        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16181
16182        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16183        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16184        else {
16185            return Ok(());
16186        };
16187
16188        let mut new_selections = Vec::new();
16189        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
16190        let reversed = initial_selection.reversed;
16191        let buffer = display_map.buffer_snapshot();
16192        let query_matches = select_next_state
16193            .query
16194            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16195
16196        for query_match in query_matches.into_iter() {
16197            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16198            let offset_range = if reversed {
16199                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16200            } else {
16201                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16202            };
16203
16204            let is_partial_word_match = select_next_state.wordwise
16205                && (buffer.is_inside_word(offset_range.start, None)
16206                    || buffer.is_inside_word(offset_range.end, None));
16207
16208            let is_initial_selection = MultiBufferOffset(query_match.start())
16209                == initial_selection.start
16210                && MultiBufferOffset(query_match.end()) == initial_selection.end;
16211
16212            if !is_partial_word_match && !is_initial_selection {
16213                new_selections.push(offset_range);
16214            }
16215        }
16216
16217        // Ensure that the initial range is the last selection, as
16218        // `MutableSelectionsCollection::select_ranges` makes the last selection
16219        // the newest selection, which the editor then relies on as the primary
16220        // cursor for scroll targeting. Without this, the last match would then
16221        // be automatically focused when the user started editing the selected
16222        // matches.
16223        let initial_directed_range = if reversed {
16224            initial_selection.end..initial_selection.start
16225        } else {
16226            initial_selection.start..initial_selection.end
16227        };
16228        new_selections.push(initial_directed_range);
16229
16230        select_next_state.done = true;
16231        self.unfold_ranges(&new_selections, false, false, cx);
16232        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16233            selections.select_ranges(new_selections)
16234        });
16235
16236        Ok(())
16237    }
16238
16239    pub fn select_next(
16240        &mut self,
16241        action: &SelectNext,
16242        window: &mut Window,
16243        cx: &mut Context<Self>,
16244    ) -> Result<()> {
16245        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16246        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16247        self.select_next_match_internal(
16248            &display_map,
16249            action.replace_newest,
16250            Some(Autoscroll::newest()),
16251            window,
16252            cx,
16253        )
16254    }
16255
16256    pub fn select_previous(
16257        &mut self,
16258        action: &SelectPrevious,
16259        window: &mut Window,
16260        cx: &mut Context<Self>,
16261    ) -> Result<()> {
16262        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16263        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16264        let buffer = display_map.buffer_snapshot();
16265        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16266        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16267            let query = &select_prev_state.query;
16268            if !select_prev_state.done {
16269                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16270                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16271                let mut next_selected_range = None;
16272                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16273                let bytes_before_last_selection =
16274                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16275                let bytes_after_first_selection =
16276                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16277                let query_matches = query
16278                    .stream_find_iter(bytes_before_last_selection)
16279                    .map(|result| (last_selection.start, result))
16280                    .chain(
16281                        query
16282                            .stream_find_iter(bytes_after_first_selection)
16283                            .map(|result| (buffer.len(), result)),
16284                    );
16285                for (end_offset, query_match) in query_matches {
16286                    let query_match = query_match.unwrap(); // can only fail due to I/O
16287                    let offset_range =
16288                        end_offset - query_match.end()..end_offset - query_match.start();
16289
16290                    if !select_prev_state.wordwise
16291                        || (!buffer.is_inside_word(offset_range.start, None)
16292                            && !buffer.is_inside_word(offset_range.end, None))
16293                    {
16294                        next_selected_range = Some(offset_range);
16295                        break;
16296                    }
16297                }
16298
16299                if let Some(next_selected_range) = next_selected_range {
16300                    self.select_match_ranges(
16301                        next_selected_range,
16302                        last_selection.reversed,
16303                        action.replace_newest,
16304                        Some(Autoscroll::newest()),
16305                        window,
16306                        cx,
16307                    );
16308                } else {
16309                    select_prev_state.done = true;
16310                }
16311            }
16312
16313            self.select_prev_state = Some(select_prev_state);
16314        } else {
16315            let mut only_carets = true;
16316            let mut same_text_selected = true;
16317            let mut selected_text = None;
16318
16319            let mut selections_iter = selections.iter().peekable();
16320            while let Some(selection) = selections_iter.next() {
16321                if selection.start != selection.end {
16322                    only_carets = false;
16323                }
16324
16325                if same_text_selected {
16326                    if selected_text.is_none() {
16327                        selected_text =
16328                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16329                    }
16330
16331                    if let Some(next_selection) = selections_iter.peek() {
16332                        if next_selection.len() == selection.len() {
16333                            let next_selected_text = buffer
16334                                .text_for_range(next_selection.range())
16335                                .collect::<String>();
16336                            if Some(next_selected_text) != selected_text {
16337                                same_text_selected = false;
16338                                selected_text = None;
16339                            }
16340                        } else {
16341                            same_text_selected = false;
16342                            selected_text = None;
16343                        }
16344                    }
16345                }
16346            }
16347
16348            if only_carets {
16349                for selection in &mut selections {
16350                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16351                    selection.start = word_range.start;
16352                    selection.end = word_range.end;
16353                    selection.goal = SelectionGoal::None;
16354                    selection.reversed = false;
16355                    self.select_match_ranges(
16356                        selection.start..selection.end,
16357                        selection.reversed,
16358                        action.replace_newest,
16359                        Some(Autoscroll::newest()),
16360                        window,
16361                        cx,
16362                    );
16363                }
16364                if selections.len() == 1 {
16365                    let selection = selections
16366                        .last()
16367                        .expect("ensured that there's only one selection");
16368                    let query = buffer
16369                        .text_for_range(selection.start..selection.end)
16370                        .collect::<String>();
16371                    let is_empty = query.is_empty();
16372                    let select_state = SelectNextState {
16373                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16374                        wordwise: true,
16375                        done: is_empty,
16376                    };
16377                    self.select_prev_state = Some(select_state);
16378                } else {
16379                    self.select_prev_state = None;
16380                }
16381            } else if let Some(selected_text) = selected_text {
16382                self.select_prev_state = Some(SelectNextState {
16383                    query: self
16384                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16385                    wordwise: false,
16386                    done: false,
16387                });
16388                self.select_previous(action, window, cx)?;
16389            }
16390        }
16391        Ok(())
16392    }
16393
16394    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16395    /// setting the case sensitivity based on the global
16396    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16397    /// editor's settings.
16398    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16399    where
16400        I: IntoIterator<Item = P>,
16401        P: AsRef<[u8]>,
16402    {
16403        let case_sensitive = self
16404            .select_next_is_case_sensitive
16405            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16406
16407        let mut builder = AhoCorasickBuilder::new();
16408        builder.ascii_case_insensitive(!case_sensitive);
16409        builder.build(patterns)
16410    }
16411
16412    pub fn find_next_match(
16413        &mut self,
16414        _: &FindNextMatch,
16415        window: &mut Window,
16416        cx: &mut Context<Self>,
16417    ) -> Result<()> {
16418        let selections = self.selections.disjoint_anchors_arc();
16419        match selections.first() {
16420            Some(first) if selections.len() >= 2 => {
16421                self.change_selections(Default::default(), window, cx, |s| {
16422                    s.select_ranges([first.range()]);
16423                });
16424            }
16425            _ => self.select_next(
16426                &SelectNext {
16427                    replace_newest: true,
16428                },
16429                window,
16430                cx,
16431            )?,
16432        }
16433        Ok(())
16434    }
16435
16436    pub fn find_previous_match(
16437        &mut self,
16438        _: &FindPreviousMatch,
16439        window: &mut Window,
16440        cx: &mut Context<Self>,
16441    ) -> Result<()> {
16442        let selections = self.selections.disjoint_anchors_arc();
16443        match selections.last() {
16444            Some(last) if selections.len() >= 2 => {
16445                self.change_selections(Default::default(), window, cx, |s| {
16446                    s.select_ranges([last.range()]);
16447                });
16448            }
16449            _ => self.select_previous(
16450                &SelectPrevious {
16451                    replace_newest: true,
16452                },
16453                window,
16454                cx,
16455            )?,
16456        }
16457        Ok(())
16458    }
16459
16460    pub fn toggle_comments(
16461        &mut self,
16462        action: &ToggleComments,
16463        window: &mut Window,
16464        cx: &mut Context<Self>,
16465    ) {
16466        if self.read_only(cx) {
16467            return;
16468        }
16469        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16470        let text_layout_details = &self.text_layout_details(window, cx);
16471        self.transact(window, cx, |this, window, cx| {
16472            let mut selections = this
16473                .selections
16474                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16475            let mut edits = Vec::new();
16476            let mut selection_edit_ranges = Vec::new();
16477            let mut last_toggled_row = None;
16478            let snapshot = this.buffer.read(cx).read(cx);
16479            let empty_str: Arc<str> = Arc::default();
16480            let mut suffixes_inserted = Vec::new();
16481            let ignore_indent = action.ignore_indent;
16482
16483            fn comment_prefix_range(
16484                snapshot: &MultiBufferSnapshot,
16485                row: MultiBufferRow,
16486                comment_prefix: &str,
16487                comment_prefix_whitespace: &str,
16488                ignore_indent: bool,
16489            ) -> Range<Point> {
16490                let indent_size = if ignore_indent {
16491                    0
16492                } else {
16493                    snapshot.indent_size_for_line(row).len
16494                };
16495
16496                let start = Point::new(row.0, indent_size);
16497
16498                let mut line_bytes = snapshot
16499                    .bytes_in_range(start..snapshot.max_point())
16500                    .flatten()
16501                    .copied();
16502
16503                // If this line currently begins with the line comment prefix, then record
16504                // the range containing the prefix.
16505                if line_bytes
16506                    .by_ref()
16507                    .take(comment_prefix.len())
16508                    .eq(comment_prefix.bytes())
16509                {
16510                    // Include any whitespace that matches the comment prefix.
16511                    let matching_whitespace_len = line_bytes
16512                        .zip(comment_prefix_whitespace.bytes())
16513                        .take_while(|(a, b)| a == b)
16514                        .count() as u32;
16515                    let end = Point::new(
16516                        start.row,
16517                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16518                    );
16519                    start..end
16520                } else {
16521                    start..start
16522                }
16523            }
16524
16525            fn comment_suffix_range(
16526                snapshot: &MultiBufferSnapshot,
16527                row: MultiBufferRow,
16528                comment_suffix: &str,
16529                comment_suffix_has_leading_space: bool,
16530            ) -> Range<Point> {
16531                let end = Point::new(row.0, snapshot.line_len(row));
16532                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16533
16534                let mut line_end_bytes = snapshot
16535                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16536                    .flatten()
16537                    .copied();
16538
16539                let leading_space_len = if suffix_start_column > 0
16540                    && line_end_bytes.next() == Some(b' ')
16541                    && comment_suffix_has_leading_space
16542                {
16543                    1
16544                } else {
16545                    0
16546                };
16547
16548                // If this line currently begins with the line comment prefix, then record
16549                // the range containing the prefix.
16550                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16551                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16552                    start..end
16553                } else {
16554                    end..end
16555                }
16556            }
16557
16558            // TODO: Handle selections that cross excerpts
16559            for selection in &mut selections {
16560                let start_column = snapshot
16561                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16562                    .len;
16563                let language = if let Some(language) =
16564                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16565                {
16566                    language
16567                } else {
16568                    continue;
16569                };
16570
16571                selection_edit_ranges.clear();
16572
16573                // If multiple selections contain a given row, avoid processing that
16574                // row more than once.
16575                let mut start_row = MultiBufferRow(selection.start.row);
16576                if last_toggled_row == Some(start_row) {
16577                    start_row = start_row.next_row();
16578                }
16579                let end_row =
16580                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16581                        MultiBufferRow(selection.end.row - 1)
16582                    } else {
16583                        MultiBufferRow(selection.end.row)
16584                    };
16585                last_toggled_row = Some(end_row);
16586
16587                if start_row > end_row {
16588                    continue;
16589                }
16590
16591                // If the language has line comments, toggle those.
16592                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16593
16594                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16595                if ignore_indent {
16596                    full_comment_prefixes = full_comment_prefixes
16597                        .into_iter()
16598                        .map(|s| Arc::from(s.trim_end()))
16599                        .collect();
16600                }
16601
16602                if !full_comment_prefixes.is_empty() {
16603                    let first_prefix = full_comment_prefixes
16604                        .first()
16605                        .expect("prefixes is non-empty");
16606                    let prefix_trimmed_lengths = full_comment_prefixes
16607                        .iter()
16608                        .map(|p| p.trim_end_matches(' ').len())
16609                        .collect::<SmallVec<[usize; 4]>>();
16610
16611                    let mut all_selection_lines_are_comments = true;
16612
16613                    for row in start_row.0..=end_row.0 {
16614                        let row = MultiBufferRow(row);
16615                        if start_row < end_row && snapshot.is_line_blank(row) {
16616                            continue;
16617                        }
16618
16619                        let prefix_range = full_comment_prefixes
16620                            .iter()
16621                            .zip(prefix_trimmed_lengths.iter().copied())
16622                            .map(|(prefix, trimmed_prefix_len)| {
16623                                comment_prefix_range(
16624                                    snapshot.deref(),
16625                                    row,
16626                                    &prefix[..trimmed_prefix_len],
16627                                    &prefix[trimmed_prefix_len..],
16628                                    ignore_indent,
16629                                )
16630                            })
16631                            .max_by_key(|range| range.end.column - range.start.column)
16632                            .expect("prefixes is non-empty");
16633
16634                        if prefix_range.is_empty() {
16635                            all_selection_lines_are_comments = false;
16636                        }
16637
16638                        selection_edit_ranges.push(prefix_range);
16639                    }
16640
16641                    if all_selection_lines_are_comments {
16642                        edits.extend(
16643                            selection_edit_ranges
16644                                .iter()
16645                                .cloned()
16646                                .map(|range| (range, empty_str.clone())),
16647                        );
16648                    } else {
16649                        let min_column = selection_edit_ranges
16650                            .iter()
16651                            .map(|range| range.start.column)
16652                            .min()
16653                            .unwrap_or(0);
16654                        edits.extend(selection_edit_ranges.iter().map(|range| {
16655                            let position = Point::new(range.start.row, min_column);
16656                            (position..position, first_prefix.clone())
16657                        }));
16658                    }
16659                } else if let Some(BlockCommentConfig {
16660                    start: full_comment_prefix,
16661                    end: comment_suffix,
16662                    ..
16663                }) = language.block_comment()
16664                {
16665                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16666                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16667                    let prefix_range = comment_prefix_range(
16668                        snapshot.deref(),
16669                        start_row,
16670                        comment_prefix,
16671                        comment_prefix_whitespace,
16672                        ignore_indent,
16673                    );
16674                    let suffix_range = comment_suffix_range(
16675                        snapshot.deref(),
16676                        end_row,
16677                        comment_suffix.trim_start_matches(' '),
16678                        comment_suffix.starts_with(' '),
16679                    );
16680
16681                    if prefix_range.is_empty() || suffix_range.is_empty() {
16682                        edits.push((
16683                            prefix_range.start..prefix_range.start,
16684                            full_comment_prefix.clone(),
16685                        ));
16686                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16687                        suffixes_inserted.push((end_row, comment_suffix.len()));
16688                    } else {
16689                        edits.push((prefix_range, empty_str.clone()));
16690                        edits.push((suffix_range, empty_str.clone()));
16691                    }
16692                } else {
16693                    continue;
16694                }
16695            }
16696
16697            drop(snapshot);
16698            this.buffer.update(cx, |buffer, cx| {
16699                buffer.edit(edits, None, cx);
16700            });
16701
16702            // Adjust selections so that they end before any comment suffixes that
16703            // were inserted.
16704            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16705            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16706            let snapshot = this.buffer.read(cx).read(cx);
16707            for selection in &mut selections {
16708                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16709                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16710                        Ordering::Less => {
16711                            suffixes_inserted.next();
16712                            continue;
16713                        }
16714                        Ordering::Greater => break,
16715                        Ordering::Equal => {
16716                            if selection.end.column == snapshot.line_len(row) {
16717                                if selection.is_empty() {
16718                                    selection.start.column -= suffix_len as u32;
16719                                }
16720                                selection.end.column -= suffix_len as u32;
16721                            }
16722                            break;
16723                        }
16724                    }
16725                }
16726            }
16727
16728            drop(snapshot);
16729            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16730
16731            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16732            let selections_on_single_row = selections.windows(2).all(|selections| {
16733                selections[0].start.row == selections[1].start.row
16734                    && selections[0].end.row == selections[1].end.row
16735                    && selections[0].start.row == selections[0].end.row
16736            });
16737            let selections_selecting = selections
16738                .iter()
16739                .any(|selection| selection.start != selection.end);
16740            let advance_downwards = action.advance_downwards
16741                && selections_on_single_row
16742                && !selections_selecting
16743                && !matches!(this.mode, EditorMode::SingleLine);
16744
16745            if advance_downwards {
16746                let snapshot = this.buffer.read(cx).snapshot(cx);
16747
16748                this.change_selections(Default::default(), window, cx, |s| {
16749                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16750                        let mut point = display_point.to_point(display_snapshot);
16751                        point.row += 1;
16752                        point = snapshot.clip_point(point, Bias::Left);
16753                        let display_point = point.to_display_point(display_snapshot);
16754                        let goal = SelectionGoal::HorizontalPosition(
16755                            display_snapshot
16756                                .x_for_display_point(display_point, text_layout_details)
16757                                .into(),
16758                        );
16759                        (display_point, goal)
16760                    })
16761                });
16762            }
16763        });
16764    }
16765
16766    pub fn select_enclosing_symbol(
16767        &mut self,
16768        _: &SelectEnclosingSymbol,
16769        window: &mut Window,
16770        cx: &mut Context<Self>,
16771    ) {
16772        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16773
16774        let buffer = self.buffer.read(cx).snapshot(cx);
16775        let old_selections = self
16776            .selections
16777            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16778            .into_boxed_slice();
16779
16780        fn update_selection(
16781            selection: &Selection<MultiBufferOffset>,
16782            buffer_snap: &MultiBufferSnapshot,
16783        ) -> Option<Selection<MultiBufferOffset>> {
16784            let cursor = selection.head();
16785            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16786            for symbol in symbols.iter().rev() {
16787                let start = symbol.range.start.to_offset(buffer_snap);
16788                let end = symbol.range.end.to_offset(buffer_snap);
16789                let new_range = start..end;
16790                if start < selection.start || end > selection.end {
16791                    return Some(Selection {
16792                        id: selection.id,
16793                        start: new_range.start,
16794                        end: new_range.end,
16795                        goal: SelectionGoal::None,
16796                        reversed: selection.reversed,
16797                    });
16798                }
16799            }
16800            None
16801        }
16802
16803        let mut selected_larger_symbol = false;
16804        let new_selections = old_selections
16805            .iter()
16806            .map(|selection| match update_selection(selection, &buffer) {
16807                Some(new_selection) => {
16808                    if new_selection.range() != selection.range() {
16809                        selected_larger_symbol = true;
16810                    }
16811                    new_selection
16812                }
16813                None => selection.clone(),
16814            })
16815            .collect::<Vec<_>>();
16816
16817        if selected_larger_symbol {
16818            self.change_selections(Default::default(), window, cx, |s| {
16819                s.select(new_selections);
16820            });
16821        }
16822    }
16823
16824    pub fn select_larger_syntax_node(
16825        &mut self,
16826        _: &SelectLargerSyntaxNode,
16827        window: &mut Window,
16828        cx: &mut Context<Self>,
16829    ) {
16830        let Some(visible_row_count) = self.visible_row_count() else {
16831            return;
16832        };
16833        let old_selections: Box<[_]> = self
16834            .selections
16835            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16836            .into();
16837        if old_selections.is_empty() {
16838            return;
16839        }
16840
16841        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16842
16843        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16844        let buffer = self.buffer.read(cx).snapshot(cx);
16845
16846        let mut selected_larger_node = false;
16847        let mut new_selections = old_selections
16848            .iter()
16849            .map(|selection| {
16850                let old_range = selection.start..selection.end;
16851
16852                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16853                    // manually select word at selection
16854                    if ["string_content", "inline"].contains(&node.kind()) {
16855                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16856                        // ignore if word is already selected
16857                        if !word_range.is_empty() && old_range != word_range {
16858                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16859                            // only select word if start and end point belongs to same word
16860                            if word_range == last_word_range {
16861                                selected_larger_node = true;
16862                                return Selection {
16863                                    id: selection.id,
16864                                    start: word_range.start,
16865                                    end: word_range.end,
16866                                    goal: SelectionGoal::None,
16867                                    reversed: selection.reversed,
16868                                };
16869                            }
16870                        }
16871                    }
16872                }
16873
16874                let mut new_range = old_range.clone();
16875                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16876                    new_range = range;
16877                    if !node.is_named() {
16878                        continue;
16879                    }
16880                    if !display_map.intersects_fold(new_range.start)
16881                        && !display_map.intersects_fold(new_range.end)
16882                    {
16883                        break;
16884                    }
16885                }
16886
16887                selected_larger_node |= new_range != old_range;
16888                Selection {
16889                    id: selection.id,
16890                    start: new_range.start,
16891                    end: new_range.end,
16892                    goal: SelectionGoal::None,
16893                    reversed: selection.reversed,
16894                }
16895            })
16896            .collect::<Vec<_>>();
16897
16898        if !selected_larger_node {
16899            return; // don't put this call in the history
16900        }
16901
16902        // scroll based on transformation done to the last selection created by the user
16903        let (last_old, last_new) = old_selections
16904            .last()
16905            .zip(new_selections.last().cloned())
16906            .expect("old_selections isn't empty");
16907
16908        let is_selection_reversed = if new_selections.len() == 1 {
16909            let should_be_reversed = last_old.start != last_new.start;
16910            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
16911            should_be_reversed
16912        } else {
16913            last_new.reversed
16914        };
16915
16916        if selected_larger_node {
16917            self.select_syntax_node_history.disable_clearing = true;
16918            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16919                s.select(new_selections.clone());
16920            });
16921            self.select_syntax_node_history.disable_clearing = false;
16922        }
16923
16924        let start_row = last_new.start.to_display_point(&display_map).row().0;
16925        let end_row = last_new.end.to_display_point(&display_map).row().0;
16926        let selection_height = end_row - start_row + 1;
16927        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16928
16929        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16930        let scroll_behavior = if fits_on_the_screen {
16931            self.request_autoscroll(Autoscroll::fit(), cx);
16932            SelectSyntaxNodeScrollBehavior::FitSelection
16933        } else if is_selection_reversed {
16934            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16935            SelectSyntaxNodeScrollBehavior::CursorTop
16936        } else {
16937            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16938            SelectSyntaxNodeScrollBehavior::CursorBottom
16939        };
16940
16941        let old_selections: Box<[Selection<Anchor>]> = old_selections
16942            .iter()
16943            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16944            .collect();
16945        self.select_syntax_node_history.push((
16946            old_selections,
16947            scroll_behavior,
16948            is_selection_reversed,
16949        ));
16950    }
16951
16952    pub fn select_smaller_syntax_node(
16953        &mut self,
16954        _: &SelectSmallerSyntaxNode,
16955        window: &mut Window,
16956        cx: &mut Context<Self>,
16957    ) {
16958        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16959
16960        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16961            self.select_syntax_node_history.pop()
16962        {
16963            if let Some(selection) = selections.last_mut() {
16964                selection.reversed = is_selection_reversed;
16965            }
16966
16967            let snapshot = self.buffer.read(cx).snapshot(cx);
16968            let selections: Vec<Selection<MultiBufferOffset>> = selections
16969                .iter()
16970                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16971                .collect();
16972
16973            self.select_syntax_node_history.disable_clearing = true;
16974            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16975                s.select(selections);
16976            });
16977            self.select_syntax_node_history.disable_clearing = false;
16978
16979            match scroll_behavior {
16980                SelectSyntaxNodeScrollBehavior::CursorTop => {
16981                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16982                }
16983                SelectSyntaxNodeScrollBehavior::FitSelection => {
16984                    self.request_autoscroll(Autoscroll::fit(), cx);
16985                }
16986                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16987                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16988                }
16989            }
16990        }
16991    }
16992
16993    pub fn unwrap_syntax_node(
16994        &mut self,
16995        _: &UnwrapSyntaxNode,
16996        window: &mut Window,
16997        cx: &mut Context<Self>,
16998    ) {
16999        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17000
17001        let buffer = self.buffer.read(cx).snapshot(cx);
17002        let selections = self
17003            .selections
17004            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17005            .into_iter()
17006            // subtracting the offset requires sorting
17007            .sorted_by_key(|i| i.start);
17008
17009        let full_edits = selections
17010            .into_iter()
17011            .filter_map(|selection| {
17012                let child = if selection.is_empty()
17013                    && let Some((_, ancestor_range)) =
17014                        buffer.syntax_ancestor(selection.start..selection.end)
17015                {
17016                    ancestor_range
17017                } else {
17018                    selection.range()
17019                };
17020
17021                let mut parent = child.clone();
17022                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
17023                    parent = ancestor_range;
17024                    if parent.start < child.start || parent.end > child.end {
17025                        break;
17026                    }
17027                }
17028
17029                if parent == child {
17030                    return None;
17031                }
17032                let text = buffer.text_for_range(child).collect::<String>();
17033                Some((selection.id, parent, text))
17034            })
17035            .collect::<Vec<_>>();
17036        if full_edits.is_empty() {
17037            return;
17038        }
17039
17040        self.transact(window, cx, |this, window, cx| {
17041            this.buffer.update(cx, |buffer, cx| {
17042                buffer.edit(
17043                    full_edits
17044                        .iter()
17045                        .map(|(_, p, t)| (p.clone(), t.clone()))
17046                        .collect::<Vec<_>>(),
17047                    None,
17048                    cx,
17049                );
17050            });
17051            this.change_selections(Default::default(), window, cx, |s| {
17052                let mut offset = 0;
17053                let mut selections = vec![];
17054                for (id, parent, text) in full_edits {
17055                    let start = parent.start - offset;
17056                    offset += (parent.end - parent.start) - text.len();
17057                    selections.push(Selection {
17058                        id,
17059                        start,
17060                        end: start + text.len(),
17061                        reversed: false,
17062                        goal: Default::default(),
17063                    });
17064                }
17065                s.select(selections);
17066            });
17067        });
17068    }
17069
17070    pub fn select_next_syntax_node(
17071        &mut self,
17072        _: &SelectNextSyntaxNode,
17073        window: &mut Window,
17074        cx: &mut Context<Self>,
17075    ) {
17076        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
17077        if old_selections.is_empty() {
17078            return;
17079        }
17080
17081        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17082
17083        let buffer = self.buffer.read(cx).snapshot(cx);
17084        let mut selected_sibling = false;
17085
17086        let new_selections = old_selections
17087            .iter()
17088            .map(|selection| {
17089                let old_range =
17090                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
17091                if let Some(results) = buffer.map_excerpt_ranges(
17092                    old_range,
17093                    |buf, _excerpt_range, input_buffer_range| {
17094                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
17095                            return Vec::new();
17096                        };
17097                        vec![(
17098                            BufferOffset(node.byte_range().start)
17099                                ..BufferOffset(node.byte_range().end),
17100                            (),
17101                        )]
17102                    },
17103                ) && let [(new_range, _)] = results.as_slice()
17104                {
17105                    selected_sibling = true;
17106                    let new_range =
17107                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
17108                    Selection {
17109                        id: selection.id,
17110                        start: new_range.start,
17111                        end: new_range.end,
17112                        goal: SelectionGoal::None,
17113                        reversed: selection.reversed,
17114                    }
17115                } else {
17116                    selection.clone()
17117                }
17118            })
17119            .collect::<Vec<_>>();
17120
17121        if selected_sibling {
17122            self.change_selections(
17123                SelectionEffects::scroll(Autoscroll::fit()),
17124                window,
17125                cx,
17126                |s| {
17127                    s.select(new_selections);
17128                },
17129            );
17130        }
17131    }
17132
17133    pub fn select_prev_syntax_node(
17134        &mut self,
17135        _: &SelectPreviousSyntaxNode,
17136        window: &mut Window,
17137        cx: &mut Context<Self>,
17138    ) {
17139        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
17140
17141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17142
17143        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
17144        let mut selected_sibling = false;
17145
17146        let new_selections = old_selections
17147            .iter()
17148            .map(|selection| {
17149                let old_range = selection.start.to_offset(&multibuffer_snapshot)
17150                    ..selection.end.to_offset(&multibuffer_snapshot);
17151                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
17152                    old_range,
17153                    |buf, _excerpt_range, input_buffer_range| {
17154                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
17155                            return Vec::new();
17156                        };
17157                        vec![(
17158                            BufferOffset(node.byte_range().start)
17159                                ..BufferOffset(node.byte_range().end),
17160                            (),
17161                        )]
17162                    },
17163                ) && let [(new_range, _)] = results.as_slice()
17164                {
17165                    selected_sibling = true;
17166                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
17167                        ..multibuffer_snapshot.anchor_before(new_range.end);
17168                    Selection {
17169                        id: selection.id,
17170                        start: new_range.start,
17171                        end: new_range.end,
17172                        goal: SelectionGoal::None,
17173                        reversed: selection.reversed,
17174                    }
17175                } else {
17176                    selection.clone()
17177                }
17178            })
17179            .collect::<Vec<_>>();
17180
17181        if selected_sibling {
17182            self.change_selections(
17183                SelectionEffects::scroll(Autoscroll::fit()),
17184                window,
17185                cx,
17186                |s| {
17187                    s.select(new_selections);
17188                },
17189            );
17190        }
17191    }
17192
17193    pub fn move_to_start_of_larger_syntax_node(
17194        &mut self,
17195        _: &MoveToStartOfLargerSyntaxNode,
17196        window: &mut Window,
17197        cx: &mut Context<Self>,
17198    ) {
17199        self.move_cursors_to_syntax_nodes(window, cx, false);
17200    }
17201
17202    pub fn move_to_end_of_larger_syntax_node(
17203        &mut self,
17204        _: &MoveToEndOfLargerSyntaxNode,
17205        window: &mut Window,
17206        cx: &mut Context<Self>,
17207    ) {
17208        self.move_cursors_to_syntax_nodes(window, cx, true);
17209    }
17210
17211    fn find_syntax_node_boundary(
17212        &self,
17213        selection_pos: MultiBufferOffset,
17214        move_to_end: bool,
17215        display_map: &DisplaySnapshot,
17216        buffer: &MultiBufferSnapshot,
17217    ) -> MultiBufferOffset {
17218        let old_range = selection_pos..selection_pos;
17219        let mut new_pos = selection_pos;
17220        let mut search_range = old_range;
17221        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17222            search_range = range.clone();
17223            if !node.is_named()
17224                || display_map.intersects_fold(range.start)
17225                || display_map.intersects_fold(range.end)
17226                // If cursor is already at the end of the syntax node, continue searching
17227                || (move_to_end && range.end == selection_pos)
17228                // If cursor is already at the start of the syntax node, continue searching
17229                || (!move_to_end && range.start == selection_pos)
17230            {
17231                continue;
17232            }
17233
17234            // If we found a string_content node, find the largest parent that is still string_content
17235            // Enables us to skip to the end of strings without taking multiple steps inside the string
17236            let (_, final_range) = if node.kind() == "string_content" {
17237                let mut current_node = node;
17238                let mut current_range = range;
17239                while let Some((parent, parent_range)) =
17240                    buffer.syntax_ancestor(current_range.clone())
17241                {
17242                    if parent.kind() == "string_content" {
17243                        current_node = parent;
17244                        current_range = parent_range;
17245                    } else {
17246                        break;
17247                    }
17248                }
17249
17250                (current_node, current_range)
17251            } else {
17252                (node, range)
17253            };
17254
17255            new_pos = if move_to_end {
17256                final_range.end
17257            } else {
17258                final_range.start
17259            };
17260
17261            break;
17262        }
17263
17264        new_pos
17265    }
17266
17267    fn move_cursors_to_syntax_nodes(
17268        &mut self,
17269        window: &mut Window,
17270        cx: &mut Context<Self>,
17271        move_to_end: bool,
17272    ) -> bool {
17273        let old_selections: Box<[_]> = self
17274            .selections
17275            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17276            .into();
17277        if old_selections.is_empty() {
17278            return false;
17279        }
17280
17281        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17282
17283        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17284        let buffer = self.buffer.read(cx).snapshot(cx);
17285
17286        let mut any_cursor_moved = false;
17287        let new_selections = old_selections
17288            .iter()
17289            .map(|selection| {
17290                if !selection.is_empty() {
17291                    return selection.clone();
17292                }
17293
17294                let selection_pos = selection.head();
17295                let new_pos = self.find_syntax_node_boundary(
17296                    selection_pos,
17297                    move_to_end,
17298                    &display_map,
17299                    &buffer,
17300                );
17301
17302                any_cursor_moved |= new_pos != selection_pos;
17303
17304                Selection {
17305                    id: selection.id,
17306                    start: new_pos,
17307                    end: new_pos,
17308                    goal: SelectionGoal::None,
17309                    reversed: false,
17310                }
17311            })
17312            .collect::<Vec<_>>();
17313
17314        self.change_selections(Default::default(), window, cx, |s| {
17315            s.select(new_selections);
17316        });
17317        self.request_autoscroll(Autoscroll::newest(), cx);
17318
17319        any_cursor_moved
17320    }
17321
17322    pub fn select_to_start_of_larger_syntax_node(
17323        &mut self,
17324        _: &SelectToStartOfLargerSyntaxNode,
17325        window: &mut Window,
17326        cx: &mut Context<Self>,
17327    ) {
17328        self.select_to_syntax_nodes(window, cx, false);
17329    }
17330
17331    pub fn select_to_end_of_larger_syntax_node(
17332        &mut self,
17333        _: &SelectToEndOfLargerSyntaxNode,
17334        window: &mut Window,
17335        cx: &mut Context<Self>,
17336    ) {
17337        self.select_to_syntax_nodes(window, cx, true);
17338    }
17339
17340    fn select_to_syntax_nodes(
17341        &mut self,
17342        window: &mut Window,
17343        cx: &mut Context<Self>,
17344        move_to_end: bool,
17345    ) {
17346        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17347
17348        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17349        let buffer = self.buffer.read(cx).snapshot(cx);
17350        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17351
17352        let new_selections = old_selections
17353            .iter()
17354            .map(|selection| {
17355                let new_pos = self.find_syntax_node_boundary(
17356                    selection.head(),
17357                    move_to_end,
17358                    &display_map,
17359                    &buffer,
17360                );
17361
17362                let mut new_selection = selection.clone();
17363                new_selection.set_head(new_pos, SelectionGoal::None);
17364                new_selection
17365            })
17366            .collect::<Vec<_>>();
17367
17368        self.change_selections(Default::default(), window, cx, |s| {
17369            s.select(new_selections);
17370        });
17371    }
17372
17373    pub fn move_to_enclosing_bracket(
17374        &mut self,
17375        _: &MoveToEnclosingBracket,
17376        window: &mut Window,
17377        cx: &mut Context<Self>,
17378    ) {
17379        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17380        self.change_selections(Default::default(), window, cx, |s| {
17381            s.move_offsets_with(&mut |snapshot, selection| {
17382                let Some(enclosing_bracket_ranges) =
17383                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17384                else {
17385                    return;
17386                };
17387
17388                let mut best_length = usize::MAX;
17389                let mut best_inside = false;
17390                let mut best_in_bracket_range = false;
17391                let mut best_destination = None;
17392                for (open, close) in enclosing_bracket_ranges {
17393                    let close = close.to_inclusive();
17394                    let length = *close.end() - open.start;
17395                    let inside = selection.start >= open.end && selection.end <= *close.start();
17396                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17397                        || close.contains(&selection.head());
17398
17399                    // If best is next to a bracket and current isn't, skip
17400                    if !in_bracket_range && best_in_bracket_range {
17401                        continue;
17402                    }
17403
17404                    // Prefer smaller lengths unless best is inside and current isn't
17405                    if length > best_length && (best_inside || !inside) {
17406                        continue;
17407                    }
17408
17409                    best_length = length;
17410                    best_inside = inside;
17411                    best_in_bracket_range = in_bracket_range;
17412                    best_destination = Some(
17413                        if close.contains(&selection.start) && close.contains(&selection.end) {
17414                            if inside { open.end } else { open.start }
17415                        } else if inside {
17416                            *close.start()
17417                        } else {
17418                            *close.end()
17419                        },
17420                    );
17421                }
17422
17423                if let Some(destination) = best_destination {
17424                    selection.collapse_to(destination, SelectionGoal::None);
17425                }
17426            })
17427        });
17428    }
17429
17430    pub fn undo_selection(
17431        &mut self,
17432        _: &UndoSelection,
17433        window: &mut Window,
17434        cx: &mut Context<Self>,
17435    ) {
17436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17437        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17438            self.selection_history.mode = SelectionHistoryMode::Undoing;
17439            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17440                this.end_selection(window, cx);
17441                this.change_selections(
17442                    SelectionEffects::scroll(Autoscroll::newest()),
17443                    window,
17444                    cx,
17445                    |s| s.select_anchors(entry.selections.to_vec()),
17446                );
17447            });
17448            self.selection_history.mode = SelectionHistoryMode::Normal;
17449
17450            self.select_next_state = entry.select_next_state;
17451            self.select_prev_state = entry.select_prev_state;
17452            self.add_selections_state = entry.add_selections_state;
17453        }
17454    }
17455
17456    pub fn redo_selection(
17457        &mut self,
17458        _: &RedoSelection,
17459        window: &mut Window,
17460        cx: &mut Context<Self>,
17461    ) {
17462        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17463        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17464            self.selection_history.mode = SelectionHistoryMode::Redoing;
17465            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17466                this.end_selection(window, cx);
17467                this.change_selections(
17468                    SelectionEffects::scroll(Autoscroll::newest()),
17469                    window,
17470                    cx,
17471                    |s| s.select_anchors(entry.selections.to_vec()),
17472                );
17473            });
17474            self.selection_history.mode = SelectionHistoryMode::Normal;
17475
17476            self.select_next_state = entry.select_next_state;
17477            self.select_prev_state = entry.select_prev_state;
17478            self.add_selections_state = entry.add_selections_state;
17479        }
17480    }
17481
17482    pub fn expand_excerpts(
17483        &mut self,
17484        action: &ExpandExcerpts,
17485        _: &mut Window,
17486        cx: &mut Context<Self>,
17487    ) {
17488        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17489    }
17490
17491    pub fn expand_excerpts_down(
17492        &mut self,
17493        action: &ExpandExcerptsDown,
17494        _: &mut Window,
17495        cx: &mut Context<Self>,
17496    ) {
17497        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17498    }
17499
17500    pub fn expand_excerpts_up(
17501        &mut self,
17502        action: &ExpandExcerptsUp,
17503        _: &mut Window,
17504        cx: &mut Context<Self>,
17505    ) {
17506        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17507    }
17508
17509    pub fn expand_excerpts_for_direction(
17510        &mut self,
17511        lines: u32,
17512        direction: ExpandExcerptDirection,
17513        cx: &mut Context<Self>,
17514    ) {
17515        let selections = self.selections.disjoint_anchors_arc();
17516
17517        let lines = if lines == 0 {
17518            EditorSettings::get_global(cx).expand_excerpt_lines
17519        } else {
17520            lines
17521        };
17522
17523        let snapshot = self.buffer.read(cx).snapshot(cx);
17524        let excerpt_anchors = selections
17525            .iter()
17526            .flat_map(|selection| {
17527                snapshot
17528                    .range_to_buffer_ranges(selection.range())
17529                    .into_iter()
17530                    .filter_map(|(buffer_snapshot, range, _)| {
17531                        snapshot.anchor_in_excerpt(buffer_snapshot.anchor_after(range.start))
17532                    })
17533            })
17534            .collect::<Vec<_>>();
17535
17536        if self.delegate_expand_excerpts {
17537            cx.emit(EditorEvent::ExpandExcerptsRequested {
17538                excerpt_anchors,
17539                lines,
17540                direction,
17541            });
17542            return;
17543        }
17544
17545        self.buffer.update(cx, |buffer, cx| {
17546            buffer.expand_excerpts(excerpt_anchors, lines, direction, cx)
17547        })
17548    }
17549
17550    pub(crate) fn expand_excerpt(
17551        &mut self,
17552        excerpt_anchor: Anchor,
17553        direction: ExpandExcerptDirection,
17554        window: &mut Window,
17555        cx: &mut Context<Self>,
17556    ) {
17557        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17558
17559        if self.delegate_expand_excerpts {
17560            cx.emit(EditorEvent::ExpandExcerptsRequested {
17561                excerpt_anchors: vec![excerpt_anchor],
17562                lines: lines_to_expand,
17563                direction,
17564            });
17565            return;
17566        }
17567
17568        let current_scroll_position = self.scroll_position(cx);
17569        let mut scroll = None;
17570
17571        if direction == ExpandExcerptDirection::Down {
17572            let multi_buffer = self.buffer.read(cx);
17573            let snapshot = multi_buffer.snapshot(cx);
17574            if let Some((buffer_snapshot, excerpt_range)) =
17575                snapshot.excerpt_containing(excerpt_anchor..excerpt_anchor)
17576            {
17577                let excerpt_end_row =
17578                    Point::from_anchor(&excerpt_range.context.end, &buffer_snapshot).row;
17579                let last_row = buffer_snapshot.max_point().row;
17580                let lines_below = last_row.saturating_sub(excerpt_end_row);
17581                if lines_below >= lines_to_expand {
17582                    scroll = Some(
17583                        current_scroll_position
17584                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17585                    );
17586                }
17587            }
17588        }
17589        if direction == ExpandExcerptDirection::Up
17590            && self
17591                .buffer
17592                .read(cx)
17593                .snapshot(cx)
17594                .excerpt_before(excerpt_anchor)
17595                .is_none()
17596        {
17597            scroll = Some(current_scroll_position);
17598        }
17599
17600        self.buffer.update(cx, |buffer, cx| {
17601            buffer.expand_excerpts([excerpt_anchor], lines_to_expand, direction, cx)
17602        });
17603
17604        if let Some(new_scroll_position) = scroll {
17605            self.set_scroll_position(new_scroll_position, window, cx);
17606        }
17607    }
17608
17609    pub fn go_to_singleton_buffer_point(
17610        &mut self,
17611        point: Point,
17612        window: &mut Window,
17613        cx: &mut Context<Self>,
17614    ) {
17615        self.go_to_singleton_buffer_range(point..point, window, cx);
17616    }
17617
17618    pub fn go_to_singleton_buffer_range(
17619        &mut self,
17620        range: Range<Point>,
17621        window: &mut Window,
17622        cx: &mut Context<Self>,
17623    ) {
17624        let multibuffer = self.buffer().read(cx);
17625        if !multibuffer.is_singleton() {
17626            return;
17627        };
17628        let anchor_range = range.to_anchors(&multibuffer.snapshot(cx));
17629        self.change_selections(
17630            SelectionEffects::default().nav_history(true),
17631            window,
17632            cx,
17633            |s| s.select_anchor_ranges([anchor_range]),
17634        );
17635    }
17636
17637    pub fn go_to_diagnostic(
17638        &mut self,
17639        action: &GoToDiagnostic,
17640        window: &mut Window,
17641        cx: &mut Context<Self>,
17642    ) {
17643        if !self.diagnostics_enabled() {
17644            return;
17645        }
17646        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17647        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17648    }
17649
17650    pub fn go_to_prev_diagnostic(
17651        &mut self,
17652        action: &GoToPreviousDiagnostic,
17653        window: &mut Window,
17654        cx: &mut Context<Self>,
17655    ) {
17656        if !self.diagnostics_enabled() {
17657            return;
17658        }
17659        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17660        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17661    }
17662
17663    pub fn go_to_diagnostic_impl(
17664        &mut self,
17665        direction: Direction,
17666        severity: GoToDiagnosticSeverityFilter,
17667        window: &mut Window,
17668        cx: &mut Context<Self>,
17669    ) {
17670        let buffer = self.buffer.read(cx).snapshot(cx);
17671        let selection = self
17672            .selections
17673            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17674
17675        let mut active_group_id = None;
17676        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17677            && active_group.active_range.start.to_offset(&buffer) == selection.start
17678        {
17679            active_group_id = Some(active_group.group_id);
17680        }
17681
17682        fn filtered<'a>(
17683            severity: GoToDiagnosticSeverityFilter,
17684            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17685        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17686            diagnostics
17687                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17688                .filter(|entry| entry.range.start != entry.range.end)
17689                .filter(|entry| !entry.diagnostic.is_unnecessary)
17690        }
17691
17692        let before = filtered(
17693            severity,
17694            buffer
17695                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17696                .filter(|entry| entry.range.start <= selection.start),
17697        );
17698        let after = filtered(
17699            severity,
17700            buffer
17701                .diagnostics_in_range(selection.start..buffer.len())
17702                .filter(|entry| entry.range.start >= selection.start),
17703        );
17704
17705        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17706        if direction == Direction::Prev {
17707            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17708            {
17709                for diagnostic in prev_diagnostics.into_iter().rev() {
17710                    if diagnostic.range.start != selection.start
17711                        || active_group_id
17712                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17713                    {
17714                        found = Some(diagnostic);
17715                        break 'outer;
17716                    }
17717                }
17718            }
17719        } else {
17720            for diagnostic in after.chain(before) {
17721                if diagnostic.range.start != selection.start
17722                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17723                {
17724                    found = Some(diagnostic);
17725                    break;
17726                }
17727            }
17728        }
17729        let Some(next_diagnostic) = found else {
17730            return;
17731        };
17732
17733        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17734        let Some((buffer_anchor, _)) = buffer.anchor_to_buffer_anchor(next_diagnostic_start) else {
17735            return;
17736        };
17737        let buffer_id = buffer_anchor.buffer_id;
17738        let snapshot = self.snapshot(window, cx);
17739        if snapshot.intersects_fold(next_diagnostic.range.start) {
17740            self.unfold_ranges(
17741                std::slice::from_ref(&next_diagnostic.range),
17742                true,
17743                false,
17744                cx,
17745            );
17746        }
17747        self.change_selections(Default::default(), window, cx, |s| {
17748            s.select_ranges(vec![
17749                next_diagnostic.range.start..next_diagnostic.range.start,
17750            ])
17751        });
17752        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17753        self.refresh_edit_prediction(false, true, window, cx);
17754    }
17755
17756    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17757        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17758        let snapshot = self.snapshot(window, cx);
17759        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17760        self.go_to_hunk_before_or_after_position(
17761            &snapshot,
17762            selection.head(),
17763            Direction::Next,
17764            true,
17765            window,
17766            cx,
17767        );
17768    }
17769
17770    pub fn go_to_hunk_before_or_after_position(
17771        &mut self,
17772        snapshot: &EditorSnapshot,
17773        position: Point,
17774        direction: Direction,
17775        wrap_around: bool,
17776        window: &mut Window,
17777        cx: &mut Context<Editor>,
17778    ) {
17779        let row = if direction == Direction::Next {
17780            self.hunk_after_position(snapshot, position, wrap_around)
17781                .map(|hunk| hunk.row_range.start)
17782        } else {
17783            self.hunk_before_position(snapshot, position, wrap_around)
17784        };
17785
17786        if let Some(row) = row {
17787            let destination = Point::new(row.0, 0);
17788            let autoscroll = Autoscroll::center();
17789
17790            self.unfold_ranges(&[destination..destination], false, false, cx);
17791            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17792                s.select_ranges([destination..destination]);
17793            });
17794        }
17795    }
17796
17797    fn hunk_after_position(
17798        &mut self,
17799        snapshot: &EditorSnapshot,
17800        position: Point,
17801        wrap_around: bool,
17802    ) -> Option<MultiBufferDiffHunk> {
17803        let result = snapshot
17804            .buffer_snapshot()
17805            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17806            .find(|hunk| hunk.row_range.start.0 > position.row);
17807
17808        if wrap_around {
17809            result.or_else(|| {
17810                snapshot
17811                    .buffer_snapshot()
17812                    .diff_hunks_in_range(Point::zero()..position)
17813                    .find(|hunk| hunk.row_range.end.0 < position.row)
17814            })
17815        } else {
17816            result
17817        }
17818    }
17819
17820    fn go_to_prev_hunk(
17821        &mut self,
17822        _: &GoToPreviousHunk,
17823        window: &mut Window,
17824        cx: &mut Context<Self>,
17825    ) {
17826        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17827        let snapshot = self.snapshot(window, cx);
17828        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17829        self.go_to_hunk_before_or_after_position(
17830            &snapshot,
17831            selection.head(),
17832            Direction::Prev,
17833            true,
17834            window,
17835            cx,
17836        );
17837    }
17838
17839    fn hunk_before_position(
17840        &mut self,
17841        snapshot: &EditorSnapshot,
17842        position: Point,
17843        wrap_around: bool,
17844    ) -> Option<MultiBufferRow> {
17845        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17846
17847        if wrap_around {
17848            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17849        } else {
17850            result
17851        }
17852    }
17853
17854    fn go_to_next_change(
17855        &mut self,
17856        _: &GoToNextChange,
17857        window: &mut Window,
17858        cx: &mut Context<Self>,
17859    ) {
17860        if let Some(selections) = self
17861            .change_list
17862            .next_change(1, Direction::Next)
17863            .map(|s| s.to_vec())
17864        {
17865            self.change_selections(Default::default(), window, cx, |s| {
17866                let map = s.display_snapshot();
17867                s.select_display_ranges(selections.iter().map(|a| {
17868                    let point = a.to_display_point(&map);
17869                    point..point
17870                }))
17871            })
17872        }
17873    }
17874
17875    fn go_to_previous_change(
17876        &mut self,
17877        _: &GoToPreviousChange,
17878        window: &mut Window,
17879        cx: &mut Context<Self>,
17880    ) {
17881        if let Some(selections) = self
17882            .change_list
17883            .next_change(1, Direction::Prev)
17884            .map(|s| s.to_vec())
17885        {
17886            self.change_selections(Default::default(), window, cx, |s| {
17887                let map = s.display_snapshot();
17888                s.select_display_ranges(selections.iter().map(|a| {
17889                    let point = a.to_display_point(&map);
17890                    point..point
17891                }))
17892            })
17893        }
17894    }
17895
17896    pub fn go_to_next_document_highlight(
17897        &mut self,
17898        _: &GoToNextDocumentHighlight,
17899        window: &mut Window,
17900        cx: &mut Context<Self>,
17901    ) {
17902        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17903    }
17904
17905    pub fn go_to_prev_document_highlight(
17906        &mut self,
17907        _: &GoToPreviousDocumentHighlight,
17908        window: &mut Window,
17909        cx: &mut Context<Self>,
17910    ) {
17911        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17912    }
17913
17914    pub fn go_to_document_highlight_before_or_after_position(
17915        &mut self,
17916        direction: Direction,
17917        window: &mut Window,
17918        cx: &mut Context<Editor>,
17919    ) {
17920        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17921        let snapshot = self.snapshot(window, cx);
17922        let buffer = &snapshot.buffer_snapshot();
17923        let position = self
17924            .selections
17925            .newest::<Point>(&snapshot.display_snapshot)
17926            .head();
17927        let anchor_position = buffer.anchor_after(position);
17928
17929        // Get all document highlights (both read and write)
17930        let mut all_highlights = Vec::new();
17931
17932        if let Some((_, read_highlights)) = self
17933            .background_highlights
17934            .get(&HighlightKey::DocumentHighlightRead)
17935        {
17936            all_highlights.extend(read_highlights.iter());
17937        }
17938
17939        if let Some((_, write_highlights)) = self
17940            .background_highlights
17941            .get(&HighlightKey::DocumentHighlightWrite)
17942        {
17943            all_highlights.extend(write_highlights.iter());
17944        }
17945
17946        if all_highlights.is_empty() {
17947            return;
17948        }
17949
17950        // Sort highlights by position
17951        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17952
17953        let target_highlight = match direction {
17954            Direction::Next => {
17955                // Find the first highlight after the current position
17956                all_highlights
17957                    .iter()
17958                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17959            }
17960            Direction::Prev => {
17961                // Find the last highlight before the current position
17962                all_highlights
17963                    .iter()
17964                    .rev()
17965                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17966            }
17967        };
17968
17969        if let Some(highlight) = target_highlight {
17970            let destination = highlight.start.to_point(buffer);
17971            let autoscroll = Autoscroll::center();
17972
17973            self.unfold_ranges(&[destination..destination], false, false, cx);
17974            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17975                s.select_ranges([destination..destination]);
17976            });
17977        }
17978    }
17979
17980    fn go_to_line<T: 'static>(
17981        &mut self,
17982        position: Anchor,
17983        highlight_color: Option<Hsla>,
17984        window: &mut Window,
17985        cx: &mut Context<Self>,
17986    ) {
17987        let snapshot = self.snapshot(window, cx).display_snapshot;
17988        let position = position.to_point(&snapshot.buffer_snapshot());
17989        let start = snapshot
17990            .buffer_snapshot()
17991            .clip_point(Point::new(position.row, 0), Bias::Left);
17992        let end = start + Point::new(1, 0);
17993        let start = snapshot.buffer_snapshot().anchor_before(start);
17994        let end = snapshot.buffer_snapshot().anchor_before(end);
17995
17996        self.highlight_rows::<T>(
17997            start..end,
17998            highlight_color
17999                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
18000            Default::default(),
18001            cx,
18002        );
18003
18004        if self.buffer.read(cx).is_singleton() {
18005            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
18006        }
18007    }
18008
18009    pub fn go_to_definition(
18010        &mut self,
18011        _: &GoToDefinition,
18012        window: &mut Window,
18013        cx: &mut Context<Self>,
18014    ) -> Task<Result<Navigated>> {
18015        let definition =
18016            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
18017        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
18018        cx.spawn_in(window, async move |editor, cx| {
18019            if definition.await? == Navigated::Yes {
18020                return Ok(Navigated::Yes);
18021            }
18022            match fallback_strategy {
18023                GoToDefinitionFallback::None => Ok(Navigated::No),
18024                GoToDefinitionFallback::FindAllReferences => {
18025                    match editor.update_in(cx, |editor, window, cx| {
18026                        editor.find_all_references(&FindAllReferences::default(), window, cx)
18027                    })? {
18028                        Some(references) => references.await,
18029                        None => Ok(Navigated::No),
18030                    }
18031                }
18032            }
18033        })
18034    }
18035
18036    pub fn go_to_declaration(
18037        &mut self,
18038        _: &GoToDeclaration,
18039        window: &mut Window,
18040        cx: &mut Context<Self>,
18041    ) -> Task<Result<Navigated>> {
18042        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
18043    }
18044
18045    pub fn go_to_declaration_split(
18046        &mut self,
18047        _: &GoToDeclaration,
18048        window: &mut Window,
18049        cx: &mut Context<Self>,
18050    ) -> Task<Result<Navigated>> {
18051        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
18052    }
18053
18054    pub fn go_to_implementation(
18055        &mut self,
18056        _: &GoToImplementation,
18057        window: &mut Window,
18058        cx: &mut Context<Self>,
18059    ) -> Task<Result<Navigated>> {
18060        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
18061    }
18062
18063    pub fn go_to_implementation_split(
18064        &mut self,
18065        _: &GoToImplementationSplit,
18066        window: &mut Window,
18067        cx: &mut Context<Self>,
18068    ) -> Task<Result<Navigated>> {
18069        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
18070    }
18071
18072    pub fn go_to_type_definition(
18073        &mut self,
18074        _: &GoToTypeDefinition,
18075        window: &mut Window,
18076        cx: &mut Context<Self>,
18077    ) -> Task<Result<Navigated>> {
18078        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
18079    }
18080
18081    pub fn go_to_definition_split(
18082        &mut self,
18083        _: &GoToDefinitionSplit,
18084        window: &mut Window,
18085        cx: &mut Context<Self>,
18086    ) -> Task<Result<Navigated>> {
18087        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18088    }
18089
18090    pub fn go_to_type_definition_split(
18091        &mut self,
18092        _: &GoToTypeDefinitionSplit,
18093        window: &mut Window,
18094        cx: &mut Context<Self>,
18095    ) -> Task<Result<Navigated>> {
18096        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18097    }
18098
18099    fn go_to_definition_of_kind(
18100        &mut self,
18101        kind: GotoDefinitionKind,
18102        split: bool,
18103        window: &mut Window,
18104        cx: &mut Context<Self>,
18105    ) -> Task<Result<Navigated>> {
18106        let Some(provider) = self.semantics_provider.clone() else {
18107            return Task::ready(Ok(Navigated::No));
18108        };
18109        let head = self
18110            .selections
18111            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18112            .head();
18113        let buffer = self.buffer.read(cx);
18114        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18115            return Task::ready(Ok(Navigated::No));
18116        };
18117        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18118            return Task::ready(Ok(Navigated::No));
18119        };
18120
18121        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18122
18123        cx.spawn_in(window, async move |editor, cx| {
18124            let Some(definitions) = definitions.await? else {
18125                return Ok(Navigated::No);
18126            };
18127            let navigated = editor
18128                .update_in(cx, |editor, window, cx| {
18129                    editor.navigate_to_hover_links(
18130                        Some(kind),
18131                        definitions
18132                            .into_iter()
18133                            .filter(|location| {
18134                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18135                            })
18136                            .map(HoverLink::Text)
18137                            .collect::<Vec<_>>(),
18138                        nav_entry,
18139                        split,
18140                        window,
18141                        cx,
18142                    )
18143                })?
18144                .await?;
18145            anyhow::Ok(navigated)
18146        })
18147    }
18148
18149    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18150        let selection = self.selections.newest_anchor();
18151        let head = selection.head();
18152        let tail = selection.tail();
18153
18154        let Some((buffer, start_position)) =
18155            self.buffer.read(cx).text_anchor_for_position(head, cx)
18156        else {
18157            return;
18158        };
18159
18160        let end_position = if head != tail {
18161            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18162                return;
18163            };
18164            Some(pos)
18165        } else {
18166            None
18167        };
18168
18169        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18170            let url = if let Some(end_pos) = end_position {
18171                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18172            } else {
18173                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18174            };
18175
18176            if let Some(url) = url {
18177                cx.update(|window, cx| {
18178                    if parse_zed_link(&url, cx).is_some() {
18179                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18180                    } else {
18181                        cx.open_url(&url);
18182                    }
18183                })?;
18184            }
18185
18186            anyhow::Ok(())
18187        });
18188
18189        url_finder.detach();
18190    }
18191
18192    pub fn open_selected_filename(
18193        &mut self,
18194        _: &OpenSelectedFilename,
18195        window: &mut Window,
18196        cx: &mut Context<Self>,
18197    ) {
18198        let Some(workspace) = self.workspace() else {
18199            return;
18200        };
18201
18202        let position = self.selections.newest_anchor().head();
18203
18204        let Some((buffer, buffer_position)) =
18205            self.buffer.read(cx).text_anchor_for_position(position, cx)
18206        else {
18207            return;
18208        };
18209
18210        let project = self.project.clone();
18211
18212        cx.spawn_in(window, async move |_, cx| {
18213            let result = find_file(&buffer, project, buffer_position, cx).await;
18214
18215            if let Some((_, path)) = result {
18216                workspace
18217                    .update_in(cx, |workspace, window, cx| {
18218                        workspace.open_resolved_path(path, window, cx)
18219                    })?
18220                    .await?;
18221            }
18222            anyhow::Ok(())
18223        })
18224        .detach();
18225    }
18226
18227    pub(crate) fn navigate_to_hover_links(
18228        &mut self,
18229        kind: Option<GotoDefinitionKind>,
18230        definitions: Vec<HoverLink>,
18231        origin: Option<NavigationEntry>,
18232        split: bool,
18233        window: &mut Window,
18234        cx: &mut Context<Editor>,
18235    ) -> Task<Result<Navigated>> {
18236        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18237        let mut first_url_or_file = None;
18238        let definitions: Vec<_> = definitions
18239            .into_iter()
18240            .filter_map(|def| match def {
18241                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18242                HoverLink::InlayHint(lsp_location, server_id) => {
18243                    let computation =
18244                        self.compute_target_location(lsp_location, server_id, window, cx);
18245                    Some(cx.background_spawn(computation))
18246                }
18247                HoverLink::Url(url) => {
18248                    first_url_or_file = Some(Either::Left(url));
18249                    None
18250                }
18251                HoverLink::File(path) => {
18252                    first_url_or_file = Some(Either::Right(path));
18253                    None
18254                }
18255            })
18256            .collect();
18257
18258        let workspace = self.workspace();
18259
18260        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18261        cx.spawn_in(window, async move |editor, cx| {
18262            let locations: Vec<Location> = future::join_all(definitions)
18263                .await
18264                .into_iter()
18265                .filter_map(|location| location.transpose())
18266                .collect::<Result<_>>()
18267                .context("location tasks")?;
18268            let mut locations = cx.update(|_, cx| {
18269                locations
18270                    .into_iter()
18271                    .map(|location| {
18272                        let buffer = location.buffer.read(cx);
18273                        (location.buffer, location.range.to_point(buffer))
18274                    })
18275                    .into_group_map()
18276            })?;
18277            let mut num_locations = 0;
18278            for ranges in locations.values_mut() {
18279                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18280                ranges.dedup();
18281                // Merge overlapping or contained ranges. After sorting by
18282                // (start, Reverse(end)), we can merge in a single pass:
18283                // if the next range starts before the current one ends,
18284                // extend the current range's end if needed.
18285                let mut i = 0;
18286                while i + 1 < ranges.len() {
18287                    if ranges[i + 1].start <= ranges[i].end {
18288                        let merged_end = ranges[i].end.max(ranges[i + 1].end);
18289                        ranges[i].end = merged_end;
18290                        ranges.remove(i + 1);
18291                    } else {
18292                        i += 1;
18293                    }
18294                }
18295                let fits_in_one_excerpt = ranges
18296                    .iter()
18297                    .tuple_windows()
18298                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18299                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18300            }
18301
18302            if num_locations > 1 {
18303                let tab_kind = match kind {
18304                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18305                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18306                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18307                    Some(GotoDefinitionKind::Type) => "Types",
18308                };
18309                let title = editor
18310                    .update_in(cx, |_, _, cx| {
18311                        let target = locations
18312                            .iter()
18313                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18314                            .map(|(buffer, location)| {
18315                                buffer
18316                                    .read(cx)
18317                                    .text_for_range(location.clone())
18318                                    .collect::<String>()
18319                            })
18320                            .filter(|text| !text.contains('\n'))
18321                            .unique()
18322                            .take(3)
18323                            .join(", ");
18324                        if target.is_empty() {
18325                            tab_kind.to_owned()
18326                        } else {
18327                            format!("{tab_kind} for {target}")
18328                        }
18329                    })
18330                    .context("buffer title")?;
18331
18332                let Some(workspace) = workspace else {
18333                    return Ok(Navigated::No);
18334                };
18335
18336                let opened = workspace
18337                    .update_in(cx, |workspace, window, cx| {
18338                        let allow_preview = PreviewTabsSettings::get_global(cx)
18339                            .enable_preview_multibuffer_from_code_navigation;
18340                        if let Some((target_editor, target_pane)) =
18341                            Self::open_locations_in_multibuffer(
18342                                workspace,
18343                                locations,
18344                                title,
18345                                split,
18346                                allow_preview,
18347                                MultibufferSelectionMode::First,
18348                                window,
18349                                cx,
18350                            )
18351                        {
18352                            // We create our own nav history instead of using
18353                            // `target_editor.nav_history` because `nav_history`
18354                            // seems to be populated asynchronously when an item
18355                            // is added to a pane
18356                            let mut nav_history = target_pane
18357                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18358                            target_editor.update(cx, |editor, cx| {
18359                                let nav_data = editor
18360                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18361                                let target =
18362                                    Some(nav_history.navigation_entry(Some(
18363                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18364                                    )));
18365                                nav_history.push_tag(origin, target);
18366                            })
18367                        }
18368                    })
18369                    .is_ok();
18370
18371                anyhow::Ok(Navigated::from_bool(opened))
18372            } else if num_locations == 0 {
18373                // If there is one url or file, open it directly
18374                match first_url_or_file {
18375                    Some(Either::Left(url)) => {
18376                        cx.update(|window, cx| {
18377                            if parse_zed_link(&url, cx).is_some() {
18378                                window
18379                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18380                            } else {
18381                                cx.open_url(&url);
18382                            }
18383                        })?;
18384                        Ok(Navigated::Yes)
18385                    }
18386                    Some(Either::Right(path)) => {
18387                        // TODO(andrew): respect preview tab settings
18388                        //               `enable_keep_preview_on_code_navigation` and
18389                        //               `enable_preview_file_from_code_navigation`
18390                        let Some(workspace) = workspace else {
18391                            return Ok(Navigated::No);
18392                        };
18393                        workspace
18394                            .update_in(cx, |workspace, window, cx| {
18395                                workspace.open_resolved_path(path, window, cx)
18396                            })?
18397                            .await?;
18398                        Ok(Navigated::Yes)
18399                    }
18400                    None => Ok(Navigated::No),
18401                }
18402            } else {
18403                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18404
18405                editor.update_in(cx, |editor, window, cx| {
18406                    let target_ranges = target_ranges
18407                        .into_iter()
18408                        .map(|r| editor.range_for_match(&r))
18409                        .map(collapse_multiline_range)
18410                        .collect::<Vec<_>>();
18411                    if !split
18412                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18413                    {
18414                        let multibuffer = editor.buffer.read(cx);
18415                        let target_ranges = target_ranges
18416                            .into_iter()
18417                            .filter_map(|r| {
18418                                let start = multibuffer.buffer_point_to_anchor(
18419                                    &target_buffer,
18420                                    r.start,
18421                                    cx,
18422                                )?;
18423                                let end = multibuffer.buffer_point_to_anchor(
18424                                    &target_buffer,
18425                                    r.end,
18426                                    cx,
18427                                )?;
18428                                Some(start..end)
18429                            })
18430                            .collect::<Vec<_>>();
18431                        if target_ranges.is_empty() {
18432                            return Navigated::No;
18433                        }
18434
18435                        editor.change_selections(
18436                            SelectionEffects::default().nav_history(true),
18437                            window,
18438                            cx,
18439                            |s| s.select_anchor_ranges(target_ranges),
18440                        );
18441
18442                        let target =
18443                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18444                        if let Some(mut nav_history) = editor.nav_history.clone() {
18445                            nav_history.push_tag(origin, target);
18446                        }
18447                    } else {
18448                        let Some(workspace) = workspace else {
18449                            return Navigated::No;
18450                        };
18451                        let pane = workspace.read(cx).active_pane().clone();
18452                        window.defer(cx, move |window, cx| {
18453                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18454                                workspace.update(cx, |workspace, cx| {
18455                                    let pane = if split {
18456                                        workspace.adjacent_pane(window, cx)
18457                                    } else {
18458                                        workspace.active_pane().clone()
18459                                    };
18460
18461                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18462                                    let keep_old_preview = preview_tabs_settings
18463                                        .enable_keep_preview_on_code_navigation;
18464                                    let allow_new_preview = preview_tabs_settings
18465                                        .enable_preview_file_from_code_navigation;
18466
18467                                    let editor = workspace.open_project_item(
18468                                        pane.clone(),
18469                                        target_buffer.clone(),
18470                                        true,
18471                                        true,
18472                                        keep_old_preview,
18473                                        allow_new_preview,
18474                                        window,
18475                                        cx,
18476                                    );
18477                                    (editor, pane)
18478                                });
18479                            // We create our own nav history instead of using
18480                            // `target_editor.nav_history` because `nav_history`
18481                            // seems to be populated asynchronously when an item
18482                            // is added to a pane
18483                            let mut nav_history = target_pane
18484                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18485                            target_editor.update(cx, |target_editor, cx| {
18486                                // When selecting a definition in a different buffer, disable the nav history
18487                                // to avoid creating a history entry at the previous cursor location.
18488                                pane.update(cx, |pane, _| pane.disable_history());
18489
18490                                let multibuffer = target_editor.buffer.read(cx);
18491                                let Some(target_buffer) = multibuffer.as_singleton() else {
18492                                    return Navigated::No;
18493                                };
18494                                let target_ranges = target_ranges
18495                                    .into_iter()
18496                                    .filter_map(|r| {
18497                                        let start = multibuffer.buffer_point_to_anchor(
18498                                            &target_buffer,
18499                                            r.start,
18500                                            cx,
18501                                        )?;
18502                                        let end = multibuffer.buffer_point_to_anchor(
18503                                            &target_buffer,
18504                                            r.end,
18505                                            cx,
18506                                        )?;
18507                                        Some(start..end)
18508                                    })
18509                                    .collect::<Vec<_>>();
18510                                if target_ranges.is_empty() {
18511                                    return Navigated::No;
18512                                }
18513
18514                                target_editor.change_selections(
18515                                    SelectionEffects::default().nav_history(true),
18516                                    window,
18517                                    cx,
18518                                    |s| s.select_anchor_ranges(target_ranges),
18519                                );
18520
18521                                let nav_data = target_editor.navigation_data(
18522                                    target_editor.selections.newest_anchor().head(),
18523                                    cx,
18524                                );
18525                                let target =
18526                                    Some(nav_history.navigation_entry(Some(
18527                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18528                                    )));
18529                                nav_history.push_tag(origin, target);
18530                                pane.update(cx, |pane, _| pane.enable_history());
18531                                Navigated::Yes
18532                            });
18533                        });
18534                    }
18535                    Navigated::Yes
18536                })
18537            }
18538        })
18539    }
18540
18541    fn compute_target_location(
18542        &self,
18543        lsp_location: lsp::Location,
18544        server_id: LanguageServerId,
18545        window: &mut Window,
18546        cx: &mut Context<Self>,
18547    ) -> Task<anyhow::Result<Option<Location>>> {
18548        let Some(project) = self.project.clone() else {
18549            return Task::ready(Ok(None));
18550        };
18551
18552        cx.spawn_in(window, async move |editor, cx| {
18553            let location_task = editor.update(cx, |_, cx| {
18554                project.update(cx, |project, cx| {
18555                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18556                })
18557            })?;
18558            let location = Some({
18559                let target_buffer_handle = location_task.await.context("open local buffer")?;
18560                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18561                    let target_start = target_buffer
18562                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18563                    let target_end = target_buffer
18564                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18565                    target_buffer.anchor_after(target_start)
18566                        ..target_buffer.anchor_before(target_end)
18567                });
18568                Location {
18569                    buffer: target_buffer_handle,
18570                    range,
18571                }
18572            });
18573            Ok(location)
18574        })
18575    }
18576
18577    fn go_to_next_reference(
18578        &mut self,
18579        _: &GoToNextReference,
18580        window: &mut Window,
18581        cx: &mut Context<Self>,
18582    ) {
18583        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18584        if let Some(task) = task {
18585            task.detach();
18586        };
18587    }
18588
18589    fn go_to_prev_reference(
18590        &mut self,
18591        _: &GoToPreviousReference,
18592        window: &mut Window,
18593        cx: &mut Context<Self>,
18594    ) {
18595        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18596        if let Some(task) = task {
18597            task.detach();
18598        };
18599    }
18600
18601    fn go_to_symbol_by_offset(
18602        &mut self,
18603        window: &mut Window,
18604        cx: &mut Context<Self>,
18605        offset: i8,
18606    ) -> Task<Result<()>> {
18607        let editor_snapshot = self.snapshot(window, cx);
18608
18609        // We don't care about multi-buffer symbols
18610        if !editor_snapshot.is_singleton() {
18611            return Task::ready(Ok(()));
18612        }
18613
18614        let cursor_offset = self
18615            .selections
18616            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18617            .head();
18618
18619        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18620            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18621                let buffer = ed.buffer.read(cx).as_singleton()?;
18622                Some(buffer.read(cx).remote_id())
18623            }) else {
18624                return Ok(());
18625            };
18626
18627            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18628            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18629
18630            let multi_snapshot = editor_snapshot.buffer();
18631            let buffer_range = |range: &Range<_>| {
18632                Some(
18633                    multi_snapshot
18634                        .buffer_anchor_range_to_anchor_range(range.clone())?
18635                        .to_offset(multi_snapshot),
18636                )
18637            };
18638
18639            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18640                let current_idx = outline_items
18641                    .iter()
18642                    .enumerate()
18643                    .filter_map(|(idx, item)| {
18644                        // Find the closest outline item by distance between outline text and cursor location
18645                        let source_range = buffer_range(&item.source_range_for_text)?;
18646                        let distance_to_closest_endpoint = cmp::min(
18647                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18648                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18649                        );
18650
18651                        let item_towards_offset =
18652                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18653                                == (offset as isize).signum();
18654
18655                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18656
18657                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18658                        // we should not already be within the outline's source range. We then pick the closest outline
18659                        // item.
18660                        (item_towards_offset && !source_range_contains_cursor)
18661                            .then_some((distance_to_closest_endpoint, idx))
18662                    })
18663                    .min()
18664                    .map(|(_, idx)| idx);
18665
18666                let Some(idx) = current_idx else {
18667                    return;
18668                };
18669
18670                let Some(range) = buffer_range(&outline_items[idx].source_range_for_text) else {
18671                    return;
18672                };
18673                let selection = [range.start..range.start];
18674
18675                let _ = editor
18676                    .update(acx, |editor, ecx| {
18677                        editor.change_selections(
18678                            SelectionEffects::scroll(Autoscroll::newest()),
18679                            window,
18680                            ecx,
18681                            |s| s.select_ranges(selection),
18682                        );
18683                    })
18684                    .ok();
18685            })?;
18686
18687            Ok(())
18688        })
18689    }
18690
18691    fn go_to_next_symbol(
18692        &mut self,
18693        _: &GoToNextSymbol,
18694        window: &mut Window,
18695        cx: &mut Context<Self>,
18696    ) {
18697        self.go_to_symbol_by_offset(window, cx, 1).detach();
18698    }
18699
18700    fn go_to_previous_symbol(
18701        &mut self,
18702        _: &GoToPreviousSymbol,
18703        window: &mut Window,
18704        cx: &mut Context<Self>,
18705    ) {
18706        self.go_to_symbol_by_offset(window, cx, -1).detach();
18707    }
18708
18709    pub fn go_to_reference_before_or_after_position(
18710        &mut self,
18711        direction: Direction,
18712        count: usize,
18713        window: &mut Window,
18714        cx: &mut Context<Self>,
18715    ) -> Option<Task<Result<()>>> {
18716        let selection = self.selections.newest_anchor();
18717        let head = selection.head();
18718
18719        let multi_buffer = self.buffer.read(cx);
18720
18721        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18722        let workspace = self.workspace()?;
18723        let project = workspace.read(cx).project().clone();
18724        let references =
18725            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18726        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18727            let Some(locations) = references.await? else {
18728                return Ok(());
18729            };
18730
18731            if locations.is_empty() {
18732                // totally normal - the cursor may be on something which is not
18733                // a symbol (e.g. a keyword)
18734                log::info!("no references found under cursor");
18735                return Ok(());
18736            }
18737
18738            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18739
18740            let (locations, current_location_index) =
18741                multi_buffer.update(cx, |multi_buffer, cx| {
18742                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18743                    let mut locations = locations
18744                        .into_iter()
18745                        .filter_map(|loc| {
18746                            let start = multi_buffer_snapshot.anchor_in_excerpt(loc.range.start)?;
18747                            let end = multi_buffer_snapshot.anchor_in_excerpt(loc.range.end)?;
18748                            Some(start..end)
18749                        })
18750                        .collect::<Vec<_>>();
18751                    // There is an O(n) implementation, but given this list will be
18752                    // small (usually <100 items), the extra O(log(n)) factor isn't
18753                    // worth the (surprisingly large amount of) extra complexity.
18754                    locations
18755                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18756
18757                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18758
18759                    let current_location_index = locations.iter().position(|loc| {
18760                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18761                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18762                    });
18763
18764                    (locations, current_location_index)
18765                });
18766
18767            let Some(current_location_index) = current_location_index else {
18768                // This indicates something has gone wrong, because we already
18769                // handle the "no references" case above
18770                log::error!(
18771                    "failed to find current reference under cursor. Total references: {}",
18772                    locations.len()
18773                );
18774                return Ok(());
18775            };
18776
18777            let destination_location_index = match direction {
18778                Direction::Next => (current_location_index + count) % locations.len(),
18779                Direction::Prev => {
18780                    (current_location_index + locations.len() - count % locations.len())
18781                        % locations.len()
18782                }
18783            };
18784
18785            // TODO(cameron): is this needed?
18786            // the thinking is to avoid "jumping to the current location" (avoid
18787            // polluting "jumplist" in vim terms)
18788            if current_location_index == destination_location_index {
18789                return Ok(());
18790            }
18791
18792            let Range { start, end } = locations[destination_location_index];
18793
18794            editor.update_in(cx, |editor, window, cx| {
18795                let effects = SelectionEffects::default();
18796
18797                editor.unfold_ranges(&[start..end], false, false, cx);
18798                editor.change_selections(effects, window, cx, |s| {
18799                    s.select_ranges([start..start]);
18800                });
18801            })?;
18802
18803            Ok(())
18804        }))
18805    }
18806
18807    pub fn find_all_references(
18808        &mut self,
18809        action: &FindAllReferences,
18810        window: &mut Window,
18811        cx: &mut Context<Self>,
18812    ) -> Option<Task<Result<Navigated>>> {
18813        let always_open_multibuffer = action.always_open_multibuffer;
18814        let selection = self.selections.newest_anchor();
18815        let multi_buffer = self.buffer.read(cx);
18816        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18817        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18818        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18819        let head = selection_offset.head();
18820
18821        let head_anchor = multi_buffer_snapshot.anchor_at(
18822            head,
18823            if head < selection_offset.tail() {
18824                Bias::Right
18825            } else {
18826                Bias::Left
18827            },
18828        );
18829
18830        match self
18831            .find_all_references_task_sources
18832            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18833        {
18834            Ok(_) => {
18835                log::info!(
18836                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18837                );
18838                return None;
18839            }
18840            Err(i) => {
18841                self.find_all_references_task_sources.insert(i, head_anchor);
18842            }
18843        }
18844
18845        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18846        let workspace = self.workspace()?;
18847        let project = workspace.read(cx).project().clone();
18848        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18849        Some(cx.spawn_in(window, async move |editor, cx| {
18850            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18851                if let Ok(i) = editor
18852                    .find_all_references_task_sources
18853                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18854                {
18855                    editor.find_all_references_task_sources.remove(i);
18856                }
18857            });
18858
18859            let Some(locations) = references.await? else {
18860                return anyhow::Ok(Navigated::No);
18861            };
18862            let mut locations = cx.update(|_, cx| {
18863                locations
18864                    .into_iter()
18865                    .map(|location| {
18866                        let buffer = location.buffer.read(cx);
18867                        (location.buffer, location.range.to_point(buffer))
18868                    })
18869                    // if special-casing the single-match case, remove ranges
18870                    // that intersect current selection
18871                    .filter(|(location_buffer, location)| {
18872                        if always_open_multibuffer || &buffer != location_buffer {
18873                            return true;
18874                        }
18875
18876                        !location.contains_inclusive(&selection_point.range())
18877                    })
18878                    .into_group_map()
18879            })?;
18880            if locations.is_empty() {
18881                return anyhow::Ok(Navigated::No);
18882            }
18883            for ranges in locations.values_mut() {
18884                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18885                ranges.dedup();
18886            }
18887            let mut num_locations = 0;
18888            for ranges in locations.values_mut() {
18889                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18890                ranges.dedup();
18891                num_locations += ranges.len();
18892            }
18893
18894            if num_locations == 1 && !always_open_multibuffer {
18895                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18896                let target_range = target_ranges.first().unwrap().clone();
18897
18898                return editor.update_in(cx, |editor, window, cx| {
18899                    let range = target_range.to_point(target_buffer.read(cx));
18900                    let range = editor.range_for_match(&range);
18901                    let range = range.start..range.start;
18902
18903                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18904                        editor.go_to_singleton_buffer_range(range, window, cx);
18905                    } else {
18906                        let pane = workspace.read(cx).active_pane().clone();
18907                        window.defer(cx, move |window, cx| {
18908                            let target_editor: Entity<Self> =
18909                                workspace.update(cx, |workspace, cx| {
18910                                    let pane = workspace.active_pane().clone();
18911
18912                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18913                                    let keep_old_preview = preview_tabs_settings
18914                                        .enable_keep_preview_on_code_navigation;
18915                                    let allow_new_preview = preview_tabs_settings
18916                                        .enable_preview_file_from_code_navigation;
18917
18918                                    workspace.open_project_item(
18919                                        pane,
18920                                        target_buffer.clone(),
18921                                        true,
18922                                        true,
18923                                        keep_old_preview,
18924                                        allow_new_preview,
18925                                        window,
18926                                        cx,
18927                                    )
18928                                });
18929                            target_editor.update(cx, |target_editor, cx| {
18930                                // When selecting a definition in a different buffer, disable the nav history
18931                                // to avoid creating a history entry at the previous cursor location.
18932                                pane.update(cx, |pane, _| pane.disable_history());
18933                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18934                                pane.update(cx, |pane, _| pane.enable_history());
18935                            });
18936                        });
18937                    }
18938                    Navigated::No
18939                });
18940            }
18941
18942            workspace.update_in(cx, |workspace, window, cx| {
18943                let target = locations
18944                    .iter()
18945                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18946                    .map(|(buffer, location)| {
18947                        buffer
18948                            .read(cx)
18949                            .text_for_range(location.clone())
18950                            .collect::<String>()
18951                    })
18952                    .filter(|text| !text.contains('\n'))
18953                    .unique()
18954                    .take(3)
18955                    .join(", ");
18956                let title = if target.is_empty() {
18957                    "References".to_owned()
18958                } else {
18959                    format!("References to {target}")
18960                };
18961                let allow_preview = PreviewTabsSettings::get_global(cx)
18962                    .enable_preview_multibuffer_from_code_navigation;
18963                Self::open_locations_in_multibuffer(
18964                    workspace,
18965                    locations,
18966                    title,
18967                    false,
18968                    allow_preview,
18969                    MultibufferSelectionMode::First,
18970                    window,
18971                    cx,
18972                );
18973                Navigated::Yes
18974            })
18975        }))
18976    }
18977
18978    /// Opens a multibuffer with the given project locations in it.
18979    pub fn open_locations_in_multibuffer(
18980        workspace: &mut Workspace,
18981        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18982        title: String,
18983        split: bool,
18984        allow_preview: bool,
18985        multibuffer_selection_mode: MultibufferSelectionMode,
18986        window: &mut Window,
18987        cx: &mut Context<Workspace>,
18988    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18989        if locations.is_empty() {
18990            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18991            return None;
18992        }
18993
18994        let capability = workspace.project().read(cx).capability();
18995        let mut ranges = <Vec<Range<Anchor>>>::new();
18996
18997        // a key to find existing multibuffer editors with the same set of locations
18998        // to prevent us from opening more and more multibuffer tabs for searches and the like
18999        let mut key = (title.clone(), vec![]);
19000        let excerpt_buffer = cx.new(|cx| {
19001            let key = &mut key.1;
19002            let mut multibuffer = MultiBuffer::new(capability);
19003            for (buffer, mut ranges_for_buffer) in locations {
19004                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
19005                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
19006                multibuffer.set_excerpts_for_path(
19007                    PathKey::for_buffer(&buffer, cx),
19008                    buffer.clone(),
19009                    ranges_for_buffer.clone(),
19010                    multibuffer_context_lines(cx),
19011                    cx,
19012                );
19013                let snapshot = multibuffer.snapshot(cx);
19014                let buffer_snapshot = buffer.read(cx).snapshot();
19015                ranges.extend(ranges_for_buffer.into_iter().filter_map(|range| {
19016                    let text_range = buffer_snapshot.anchor_range_inside(range);
19017                    let start = snapshot.anchor_in_buffer(text_range.start)?;
19018                    let end = snapshot.anchor_in_buffer(text_range.end)?;
19019                    Some(start..end)
19020                }))
19021            }
19022
19023            multibuffer.with_title(title)
19024        });
19025        let existing = workspace.active_pane().update(cx, |pane, cx| {
19026            pane.items()
19027                .filter_map(|item| item.downcast::<Editor>())
19028                .find(|editor| {
19029                    editor
19030                        .read(cx)
19031                        .lookup_key
19032                        .as_ref()
19033                        .and_then(|it| {
19034                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
19035                        })
19036                        .is_some_and(|it| *it == key)
19037                })
19038        });
19039        let was_existing = existing.is_some();
19040        let editor = existing.unwrap_or_else(|| {
19041            cx.new(|cx| {
19042                let mut editor = Editor::for_multibuffer(
19043                    excerpt_buffer,
19044                    Some(workspace.project().clone()),
19045                    window,
19046                    cx,
19047                );
19048                editor.lookup_key = Some(Box::new(key));
19049                editor
19050            })
19051        });
19052        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
19053            MultibufferSelectionMode::First => {
19054                if let Some(first_range) = ranges.first() {
19055                    editor.change_selections(
19056                        SelectionEffects::no_scroll(),
19057                        window,
19058                        cx,
19059                        |selections| {
19060                            selections.clear_disjoint();
19061                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
19062                        },
19063                    );
19064                }
19065                editor.highlight_background(
19066                    HighlightKey::Editor,
19067                    &ranges,
19068                    |_, theme| theme.colors().editor_highlighted_line_background,
19069                    cx,
19070                );
19071            }
19072            MultibufferSelectionMode::All => {
19073                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
19074                    selections.clear_disjoint();
19075                    selections.select_anchor_ranges(ranges);
19076                });
19077            }
19078        });
19079
19080        let item = Box::new(editor.clone());
19081
19082        let pane = if split {
19083            workspace.adjacent_pane(window, cx)
19084        } else {
19085            workspace.active_pane().clone()
19086        };
19087        let activate_pane = split;
19088
19089        let mut destination_index = None;
19090        pane.update(cx, |pane, cx| {
19091            if allow_preview && !was_existing {
19092                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
19093            }
19094            if was_existing && !allow_preview {
19095                pane.unpreview_item_if_preview(item.item_id());
19096            }
19097            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19098        });
19099
19100        Some((editor, pane))
19101    }
19102
19103    pub fn rename(
19104        &mut self,
19105        _: &Rename,
19106        window: &mut Window,
19107        cx: &mut Context<Self>,
19108    ) -> Option<Task<Result<()>>> {
19109        use language::ToOffset as _;
19110
19111        let provider = self.semantics_provider.clone()?;
19112        let selection = self.selections.newest_anchor().clone();
19113        let (cursor_buffer, cursor_buffer_position) = self
19114            .buffer
19115            .read(cx)
19116            .text_anchor_for_position(selection.head(), cx)?;
19117        let (tail_buffer, cursor_buffer_position_end) = self
19118            .buffer
19119            .read(cx)
19120            .text_anchor_for_position(selection.tail(), cx)?;
19121        if tail_buffer != cursor_buffer {
19122            return None;
19123        }
19124
19125        let snapshot = cursor_buffer.read(cx).snapshot();
19126        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19127        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19128        let prepare_rename = provider.range_for_rename(&cursor_buffer, cursor_buffer_position, cx);
19129        drop(snapshot);
19130
19131        Some(cx.spawn_in(window, async move |this, cx| {
19132            let rename_range = prepare_rename.await?;
19133            if let Some(rename_range) = rename_range {
19134                this.update_in(cx, |this, window, cx| {
19135                    let snapshot = cursor_buffer.read(cx).snapshot();
19136                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19137                    let cursor_offset_in_rename_range =
19138                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19139                    let cursor_offset_in_rename_range_end =
19140                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19141
19142                    this.take_rename(false, window, cx);
19143                    let buffer = this.buffer.read(cx).read(cx);
19144                    let cursor_offset = selection.head().to_offset(&buffer);
19145                    let rename_start =
19146                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19147                    let rename_end = rename_start + rename_buffer_range.len();
19148                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19149                    let mut old_highlight_id = None;
19150                    let old_name: Arc<str> = buffer
19151                        .chunks(rename_start..rename_end, true)
19152                        .map(|chunk| {
19153                            if old_highlight_id.is_none() {
19154                                old_highlight_id = chunk.syntax_highlight_id;
19155                            }
19156                            chunk.text
19157                        })
19158                        .collect::<String>()
19159                        .into();
19160
19161                    drop(buffer);
19162
19163                    // Position the selection in the rename editor so that it matches the current selection.
19164                    this.show_local_selections = false;
19165                    let rename_editor = cx.new(|cx| {
19166                        let mut editor = Editor::single_line(window, cx);
19167                        editor.buffer.update(cx, |buffer, cx| {
19168                            buffer.edit(
19169                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19170                                None,
19171                                cx,
19172                            )
19173                        });
19174                        let cursor_offset_in_rename_range =
19175                            MultiBufferOffset(cursor_offset_in_rename_range);
19176                        let cursor_offset_in_rename_range_end =
19177                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19178                        let rename_selection_range = match cursor_offset_in_rename_range
19179                            .cmp(&cursor_offset_in_rename_range_end)
19180                        {
19181                            Ordering::Equal => {
19182                                editor.select_all(&SelectAll, window, cx);
19183                                return editor;
19184                            }
19185                            Ordering::Less => {
19186                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19187                            }
19188                            Ordering::Greater => {
19189                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19190                            }
19191                        };
19192                        if rename_selection_range.end.0 > old_name.len() {
19193                            editor.select_all(&SelectAll, window, cx);
19194                        } else {
19195                            editor.change_selections(Default::default(), window, cx, |s| {
19196                                s.select_ranges([rename_selection_range]);
19197                            });
19198                        }
19199                        editor
19200                    });
19201                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19202                        if e == &EditorEvent::Focused {
19203                            cx.emit(EditorEvent::FocusedIn)
19204                        }
19205                    })
19206                    .detach();
19207
19208                    let write_highlights =
19209                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19210                    let read_highlights =
19211                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19212                    let ranges = write_highlights
19213                        .iter()
19214                        .flat_map(|(_, ranges)| ranges.iter())
19215                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19216                        .cloned()
19217                        .collect();
19218
19219                    this.highlight_text(
19220                        HighlightKey::Rename,
19221                        ranges,
19222                        HighlightStyle {
19223                            fade_out: Some(0.6),
19224                            ..Default::default()
19225                        },
19226                        cx,
19227                    );
19228                    let rename_focus_handle = rename_editor.focus_handle(cx);
19229                    window.focus(&rename_focus_handle, cx);
19230                    let block_id = this.insert_blocks(
19231                        [BlockProperties {
19232                            style: BlockStyle::Flex,
19233                            placement: BlockPlacement::Below(range.start),
19234                            height: Some(1),
19235                            render: Arc::new({
19236                                let rename_editor = rename_editor.clone();
19237                                move |cx: &mut BlockContext| {
19238                                    let mut text_style = cx.editor_style.text.clone();
19239                                    if let Some(highlight_style) = old_highlight_id
19240                                        .and_then(|h| cx.editor_style.syntax.get(h).cloned())
19241                                    {
19242                                        text_style = text_style.highlight(highlight_style);
19243                                    }
19244                                    div()
19245                                        .block_mouse_except_scroll()
19246                                        .pl(cx.anchor_x)
19247                                        .child(EditorElement::new(
19248                                            &rename_editor,
19249                                            EditorStyle {
19250                                                background: cx.theme().system().transparent,
19251                                                local_player: cx.editor_style.local_player,
19252                                                text: text_style,
19253                                                scrollbar_width: cx.editor_style.scrollbar_width,
19254                                                syntax: cx.editor_style.syntax.clone(),
19255                                                status: cx.editor_style.status.clone(),
19256                                                inlay_hints_style: HighlightStyle {
19257                                                    font_weight: Some(FontWeight::BOLD),
19258                                                    ..make_inlay_hints_style(cx.app)
19259                                                },
19260                                                edit_prediction_styles: make_suggestion_styles(
19261                                                    cx.app,
19262                                                ),
19263                                                ..EditorStyle::default()
19264                                            },
19265                                        ))
19266                                        .into_any_element()
19267                                }
19268                            }),
19269                            priority: 0,
19270                        }],
19271                        Some(Autoscroll::fit()),
19272                        cx,
19273                    )[0];
19274                    this.pending_rename = Some(RenameState {
19275                        range,
19276                        old_name,
19277                        editor: rename_editor,
19278                        block_id,
19279                    });
19280                })?;
19281            }
19282
19283            Ok(())
19284        }))
19285    }
19286
19287    pub fn confirm_rename(
19288        &mut self,
19289        _: &ConfirmRename,
19290        window: &mut Window,
19291        cx: &mut Context<Self>,
19292    ) -> Option<Task<Result<()>>> {
19293        let rename = self.take_rename(false, window, cx)?;
19294        let workspace = self.workspace()?.downgrade();
19295        let (buffer, start) = self
19296            .buffer
19297            .read(cx)
19298            .text_anchor_for_position(rename.range.start, cx)?;
19299        let (end_buffer, _) = self
19300            .buffer
19301            .read(cx)
19302            .text_anchor_for_position(rename.range.end, cx)?;
19303        if buffer != end_buffer {
19304            return None;
19305        }
19306
19307        let old_name = rename.old_name;
19308        let new_name = rename.editor.read(cx).text(cx);
19309
19310        let rename = self.semantics_provider.as_ref()?.perform_rename(
19311            &buffer,
19312            start,
19313            new_name.clone(),
19314            cx,
19315        )?;
19316
19317        Some(cx.spawn_in(window, async move |editor, cx| {
19318            let project_transaction = rename.await?;
19319            Self::open_project_transaction(
19320                &editor,
19321                workspace,
19322                project_transaction,
19323                format!("Rename: {}{}", old_name, new_name),
19324                cx,
19325            )
19326            .await?;
19327
19328            editor.update(cx, |editor, cx| {
19329                editor.refresh_document_highlights(cx);
19330            })?;
19331            Ok(())
19332        }))
19333    }
19334
19335    fn take_rename(
19336        &mut self,
19337        moving_cursor: bool,
19338        window: &mut Window,
19339        cx: &mut Context<Self>,
19340    ) -> Option<RenameState> {
19341        let rename = self.pending_rename.take()?;
19342        if rename.editor.focus_handle(cx).is_focused(window) {
19343            window.focus(&self.focus_handle, cx);
19344        }
19345
19346        self.remove_blocks(
19347            [rename.block_id].into_iter().collect(),
19348            Some(Autoscroll::fit()),
19349            cx,
19350        );
19351        self.clear_highlights(HighlightKey::Rename, cx);
19352        self.show_local_selections = true;
19353
19354        if moving_cursor {
19355            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19356                editor
19357                    .selections
19358                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19359                    .head()
19360            });
19361
19362            // Update the selection to match the position of the selection inside
19363            // the rename editor.
19364            let snapshot = self.buffer.read(cx).read(cx);
19365            let rename_range = rename.range.to_offset(&snapshot);
19366            let cursor_in_editor = snapshot
19367                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19368                .min(rename_range.end);
19369            drop(snapshot);
19370
19371            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19372                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19373            });
19374        } else {
19375            self.refresh_document_highlights(cx);
19376        }
19377
19378        Some(rename)
19379    }
19380
19381    pub fn pending_rename(&self) -> Option<&RenameState> {
19382        self.pending_rename.as_ref()
19383    }
19384
19385    fn format(
19386        &mut self,
19387        _: &Format,
19388        window: &mut Window,
19389        cx: &mut Context<Self>,
19390    ) -> Option<Task<Result<()>>> {
19391        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19392
19393        let project = match &self.project {
19394            Some(project) => project.clone(),
19395            None => return None,
19396        };
19397
19398        Some(self.perform_format(
19399            project,
19400            FormatTrigger::Manual,
19401            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19402            window,
19403            cx,
19404        ))
19405    }
19406
19407    fn format_selections(
19408        &mut self,
19409        _: &FormatSelections,
19410        window: &mut Window,
19411        cx: &mut Context<Self>,
19412    ) -> Option<Task<Result<()>>> {
19413        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19414
19415        let project = match &self.project {
19416            Some(project) => project.clone(),
19417            None => return None,
19418        };
19419
19420        let ranges = self
19421            .selections
19422            .all_adjusted(&self.display_snapshot(cx))
19423            .into_iter()
19424            .map(|selection| selection.range())
19425            .collect_vec();
19426
19427        Some(self.perform_format(
19428            project,
19429            FormatTrigger::Manual,
19430            FormatTarget::Ranges(ranges),
19431            window,
19432            cx,
19433        ))
19434    }
19435
19436    fn perform_format(
19437        &mut self,
19438        project: Entity<Project>,
19439        trigger: FormatTrigger,
19440        target: FormatTarget,
19441        window: &mut Window,
19442        cx: &mut Context<Self>,
19443    ) -> Task<Result<()>> {
19444        let buffer = self.buffer.clone();
19445        let (buffers, target) = match target {
19446            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19447            FormatTarget::Ranges(selection_ranges) => {
19448                let multi_buffer = buffer.read(cx);
19449                let snapshot = multi_buffer.read(cx);
19450                let mut buffers = HashSet::default();
19451                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19452                    BTreeMap::new();
19453                for selection_range in selection_ranges {
19454                    for (buffer_snapshot, buffer_range, _) in
19455                        snapshot.range_to_buffer_ranges(selection_range.start..selection_range.end)
19456                    {
19457                        let buffer_id = buffer_snapshot.remote_id();
19458                        let start = buffer_snapshot.anchor_before(buffer_range.start);
19459                        let end = buffer_snapshot.anchor_after(buffer_range.end);
19460                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19461                        buffer_id_to_ranges
19462                            .entry(buffer_id)
19463                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19464                            .or_insert_with(|| vec![start..end]);
19465                    }
19466                }
19467                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19468            }
19469        };
19470
19471        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19472        let selections_prev = transaction_id_prev
19473            .and_then(|transaction_id_prev| {
19474                // default to selections as they were after the last edit, if we have them,
19475                // instead of how they are now.
19476                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19477                // will take you back to where you made the last edit, instead of staying where you scrolled
19478                self.selection_history
19479                    .transaction(transaction_id_prev)
19480                    .map(|t| t.0.clone())
19481            })
19482            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19483
19484        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19485        let format = project.update(cx, |project, cx| {
19486            project.format(buffers, target, true, trigger, cx)
19487        });
19488
19489        cx.spawn_in(window, async move |editor, cx| {
19490            let transaction = futures::select_biased! {
19491                transaction = format.log_err().fuse() => transaction,
19492                () = timeout => {
19493                    log::warn!("timed out waiting for formatting");
19494                    None
19495                }
19496            };
19497
19498            buffer.update(cx, |buffer, cx| {
19499                if let Some(transaction) = transaction
19500                    && !buffer.is_singleton()
19501                {
19502                    buffer.push_transaction(&transaction.0, cx);
19503                }
19504                cx.notify();
19505            });
19506
19507            if let Some(transaction_id_now) =
19508                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19509            {
19510                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19511                if has_new_transaction {
19512                    editor
19513                        .update(cx, |editor, _| {
19514                            editor
19515                                .selection_history
19516                                .insert_transaction(transaction_id_now, selections_prev);
19517                        })
19518                        .ok();
19519                }
19520            }
19521
19522            Ok(())
19523        })
19524    }
19525
19526    fn organize_imports(
19527        &mut self,
19528        _: &OrganizeImports,
19529        window: &mut Window,
19530        cx: &mut Context<Self>,
19531    ) -> Option<Task<Result<()>>> {
19532        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19533        let project = match &self.project {
19534            Some(project) => project.clone(),
19535            None => return None,
19536        };
19537        Some(self.perform_code_action_kind(
19538            project,
19539            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19540            window,
19541            cx,
19542        ))
19543    }
19544
19545    fn perform_code_action_kind(
19546        &mut self,
19547        project: Entity<Project>,
19548        kind: CodeActionKind,
19549        window: &mut Window,
19550        cx: &mut Context<Self>,
19551    ) -> Task<Result<()>> {
19552        let buffer = self.buffer.clone();
19553        let buffers = buffer.read(cx).all_buffers();
19554        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19555        let apply_action = project.update(cx, |project, cx| {
19556            project.apply_code_action_kind(buffers, kind, true, cx)
19557        });
19558        cx.spawn_in(window, async move |_, cx| {
19559            let transaction = futures::select_biased! {
19560                () = timeout => {
19561                    log::warn!("timed out waiting for executing code action");
19562                    None
19563                }
19564                transaction = apply_action.log_err().fuse() => transaction,
19565            };
19566            buffer.update(cx, |buffer, cx| {
19567                // check if we need this
19568                if let Some(transaction) = transaction
19569                    && !buffer.is_singleton()
19570                {
19571                    buffer.push_transaction(&transaction.0, cx);
19572                }
19573                cx.notify();
19574            });
19575            Ok(())
19576        })
19577    }
19578
19579    pub fn restart_language_server(
19580        &mut self,
19581        _: &RestartLanguageServer,
19582        _: &mut Window,
19583        cx: &mut Context<Self>,
19584    ) {
19585        if let Some(project) = self.project.clone() {
19586            self.buffer.update(cx, |multi_buffer, cx| {
19587                project.update(cx, |project, cx| {
19588                    project.restart_language_servers_for_buffers(
19589                        multi_buffer.all_buffers().into_iter().collect(),
19590                        HashSet::default(),
19591                        cx,
19592                    );
19593                });
19594            })
19595        }
19596    }
19597
19598    pub fn stop_language_server(
19599        &mut self,
19600        _: &StopLanguageServer,
19601        _: &mut Window,
19602        cx: &mut Context<Self>,
19603    ) {
19604        if let Some(project) = self.project.clone() {
19605            self.buffer.update(cx, |multi_buffer, cx| {
19606                project.update(cx, |project, cx| {
19607                    project.stop_language_servers_for_buffers(
19608                        multi_buffer.all_buffers().into_iter().collect(),
19609                        HashSet::default(),
19610                        cx,
19611                    );
19612                });
19613            });
19614        }
19615    }
19616
19617    fn cancel_language_server_work(
19618        workspace: &mut Workspace,
19619        _: &actions::CancelLanguageServerWork,
19620        _: &mut Window,
19621        cx: &mut Context<Workspace>,
19622    ) {
19623        let project = workspace.project();
19624        let buffers = workspace
19625            .active_item(cx)
19626            .and_then(|item| item.act_as::<Editor>(cx))
19627            .map_or(HashSet::default(), |editor| {
19628                editor.read(cx).buffer.read(cx).all_buffers()
19629            });
19630        project.update(cx, |project, cx| {
19631            project.cancel_language_server_work_for_buffers(buffers, cx);
19632        });
19633    }
19634
19635    fn show_character_palette(
19636        &mut self,
19637        _: &ShowCharacterPalette,
19638        window: &mut Window,
19639        _: &mut Context<Self>,
19640    ) {
19641        window.show_character_palette();
19642    }
19643
19644    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19645        if !self.diagnostics_enabled() {
19646            return;
19647        }
19648
19649        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19650            let buffer = self.buffer.read(cx).snapshot(cx);
19651            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19652            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19653            let is_valid = buffer
19654                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19655                .any(|entry| {
19656                    entry.diagnostic.is_primary
19657                        && !entry.range.is_empty()
19658                        && entry.range.start == primary_range_start
19659                        && entry.diagnostic.message == active_diagnostics.active_message
19660                });
19661
19662            if !is_valid {
19663                self.dismiss_diagnostics(cx);
19664            }
19665        }
19666    }
19667
19668    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19669        match &self.active_diagnostics {
19670            ActiveDiagnostic::Group(group) => Some(group),
19671            _ => None,
19672        }
19673    }
19674
19675    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19676        if !self.diagnostics_enabled() {
19677            return;
19678        }
19679        self.dismiss_diagnostics(cx);
19680        self.active_diagnostics = ActiveDiagnostic::All;
19681    }
19682
19683    fn activate_diagnostics(
19684        &mut self,
19685        buffer_id: BufferId,
19686        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19687        window: &mut Window,
19688        cx: &mut Context<Self>,
19689    ) {
19690        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19691            return;
19692        }
19693        self.dismiss_diagnostics(cx);
19694        let snapshot = self.snapshot(window, cx);
19695        let buffer = self.buffer.read(cx).snapshot(cx);
19696        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19697            return;
19698        };
19699
19700        let diagnostic_group = buffer
19701            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19702            .collect::<Vec<_>>();
19703
19704        let language_registry = self
19705            .project()
19706            .map(|project| project.read(cx).languages().clone());
19707
19708        let blocks = renderer.render_group(
19709            diagnostic_group,
19710            buffer_id,
19711            snapshot,
19712            cx.weak_entity(),
19713            language_registry,
19714            cx,
19715        );
19716
19717        let blocks = self.display_map.update(cx, |display_map, cx| {
19718            display_map.insert_blocks(blocks, cx).into_iter().collect()
19719        });
19720        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19721            active_range: buffer.anchor_before(diagnostic.range.start)
19722                ..buffer.anchor_after(diagnostic.range.end),
19723            active_message: diagnostic.diagnostic.message.clone(),
19724            group_id: diagnostic.diagnostic.group_id,
19725            blocks,
19726        });
19727        cx.notify();
19728    }
19729
19730    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19731        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19732            return;
19733        };
19734
19735        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19736        if let ActiveDiagnostic::Group(group) = prev {
19737            self.display_map.update(cx, |display_map, cx| {
19738                display_map.remove_blocks(group.blocks, cx);
19739            });
19740            cx.notify();
19741        }
19742    }
19743
19744    /// Disable inline diagnostics rendering for this editor.
19745    pub fn disable_inline_diagnostics(&mut self) {
19746        self.inline_diagnostics_enabled = false;
19747        self.inline_diagnostics_update = Task::ready(());
19748        self.inline_diagnostics.clear();
19749    }
19750
19751    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19752        self.diagnostics_enabled = false;
19753        self.dismiss_diagnostics(cx);
19754        self.inline_diagnostics_update = Task::ready(());
19755        self.inline_diagnostics.clear();
19756    }
19757
19758    pub fn disable_word_completions(&mut self) {
19759        self.word_completions_enabled = false;
19760    }
19761
19762    pub fn diagnostics_enabled(&self) -> bool {
19763        self.diagnostics_enabled && self.lsp_data_enabled()
19764    }
19765
19766    pub fn inline_diagnostics_enabled(&self) -> bool {
19767        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19768    }
19769
19770    pub fn show_inline_diagnostics(&self) -> bool {
19771        self.show_inline_diagnostics
19772    }
19773
19774    pub fn toggle_inline_diagnostics(
19775        &mut self,
19776        _: &ToggleInlineDiagnostics,
19777        window: &mut Window,
19778        cx: &mut Context<Editor>,
19779    ) {
19780        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19781        self.refresh_inline_diagnostics(false, window, cx);
19782    }
19783
19784    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19785        self.diagnostics_max_severity = severity;
19786        self.display_map.update(cx, |display_map, _| {
19787            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19788        });
19789    }
19790
19791    pub fn toggle_diagnostics(
19792        &mut self,
19793        _: &ToggleDiagnostics,
19794        window: &mut Window,
19795        cx: &mut Context<Editor>,
19796    ) {
19797        if !self.diagnostics_enabled() {
19798            return;
19799        }
19800
19801        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19802            EditorSettings::get_global(cx)
19803                .diagnostics_max_severity
19804                .filter(|severity| severity != &DiagnosticSeverity::Off)
19805                .unwrap_or(DiagnosticSeverity::Hint)
19806        } else {
19807            DiagnosticSeverity::Off
19808        };
19809        self.set_max_diagnostics_severity(new_severity, cx);
19810        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19811            self.active_diagnostics = ActiveDiagnostic::None;
19812            self.inline_diagnostics_update = Task::ready(());
19813            self.inline_diagnostics.clear();
19814        } else {
19815            self.refresh_inline_diagnostics(false, window, cx);
19816        }
19817
19818        cx.notify();
19819    }
19820
19821    pub fn toggle_minimap(
19822        &mut self,
19823        _: &ToggleMinimap,
19824        window: &mut Window,
19825        cx: &mut Context<Editor>,
19826    ) {
19827        if self.supports_minimap(cx) {
19828            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19829        }
19830    }
19831
19832    fn refresh_inline_diagnostics(
19833        &mut self,
19834        debounce: bool,
19835        window: &mut Window,
19836        cx: &mut Context<Self>,
19837    ) {
19838        let max_severity = ProjectSettings::get_global(cx)
19839            .diagnostics
19840            .inline
19841            .max_severity
19842            .unwrap_or(self.diagnostics_max_severity);
19843
19844        if !self.inline_diagnostics_enabled()
19845            || !self.diagnostics_enabled()
19846            || !self.show_inline_diagnostics
19847            || max_severity == DiagnosticSeverity::Off
19848        {
19849            self.inline_diagnostics_update = Task::ready(());
19850            self.inline_diagnostics.clear();
19851            return;
19852        }
19853
19854        let debounce_ms = ProjectSettings::get_global(cx)
19855            .diagnostics
19856            .inline
19857            .update_debounce_ms;
19858        let debounce = if debounce && debounce_ms > 0 {
19859            Some(Duration::from_millis(debounce_ms))
19860        } else {
19861            None
19862        };
19863        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19864            if let Some(debounce) = debounce {
19865                cx.background_executor().timer(debounce).await;
19866            }
19867            let Some(snapshot) = editor.upgrade().map(|editor| {
19868                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19869            }) else {
19870                return;
19871            };
19872
19873            let new_inline_diagnostics = cx
19874                .background_spawn(async move {
19875                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19876                    for diagnostic_entry in
19877                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19878                    {
19879                        let message = diagnostic_entry
19880                            .diagnostic
19881                            .message
19882                            .split_once('\n')
19883                            .map(|(line, _)| line)
19884                            .map(SharedString::new)
19885                            .unwrap_or_else(|| {
19886                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19887                            });
19888                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19889                        let (Ok(i) | Err(i)) = inline_diagnostics
19890                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19891                        inline_diagnostics.insert(
19892                            i,
19893                            (
19894                                start_anchor,
19895                                InlineDiagnostic {
19896                                    message,
19897                                    group_id: diagnostic_entry.diagnostic.group_id,
19898                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19899                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19900                                    severity: diagnostic_entry.diagnostic.severity,
19901                                },
19902                            ),
19903                        );
19904                    }
19905                    inline_diagnostics
19906                })
19907                .await;
19908
19909            editor
19910                .update(cx, |editor, cx| {
19911                    editor.inline_diagnostics = new_inline_diagnostics;
19912                    cx.notify();
19913                })
19914                .ok();
19915        });
19916    }
19917
19918    fn pull_diagnostics(
19919        &mut self,
19920        buffer_id: BufferId,
19921        _window: &Window,
19922        cx: &mut Context<Self>,
19923    ) -> Option<()> {
19924        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19925        // skip any LSP updates for it.
19926
19927        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19928            return None;
19929        }
19930        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19931            .diagnostics
19932            .lsp_pull_diagnostics;
19933        if !pull_diagnostics_settings.enabled {
19934            return None;
19935        }
19936        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19937        let project = self.project()?.downgrade();
19938        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19939
19940        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19941            cx.background_executor().timer(debounce).await;
19942            if let Ok(task) = project.update(cx, |project, cx| {
19943                project.lsp_store().update(cx, |lsp_store, cx| {
19944                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19945                })
19946            }) {
19947                task.await.log_err();
19948            }
19949            project
19950                .update(cx, |project, cx| {
19951                    project.lsp_store().update(cx, |lsp_store, cx| {
19952                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19953                    })
19954                })
19955                .log_err();
19956        });
19957
19958        Some(())
19959    }
19960
19961    pub fn set_selections_from_remote(
19962        &mut self,
19963        selections: Vec<Selection<Anchor>>,
19964        pending_selection: Option<Selection<Anchor>>,
19965        window: &mut Window,
19966        cx: &mut Context<Self>,
19967    ) {
19968        let old_cursor_position = self.selections.newest_anchor().head();
19969        self.selections
19970            .change_with(&self.display_snapshot(cx), |s| {
19971                s.select_anchors(selections);
19972                if let Some(pending_selection) = pending_selection {
19973                    s.set_pending(pending_selection, SelectMode::Character);
19974                } else {
19975                    s.clear_pending();
19976                }
19977            });
19978        self.selections_did_change(
19979            false,
19980            &old_cursor_position,
19981            SelectionEffects::default(),
19982            window,
19983            cx,
19984        );
19985    }
19986
19987    pub fn transact(
19988        &mut self,
19989        window: &mut Window,
19990        cx: &mut Context<Self>,
19991        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19992    ) -> Option<TransactionId> {
19993        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19994            this.start_transaction_at(Instant::now(), window, cx);
19995            update(this, window, cx);
19996            this.end_transaction_at(Instant::now(), cx)
19997        })
19998    }
19999
20000    pub fn start_transaction_at(
20001        &mut self,
20002        now: Instant,
20003        window: &mut Window,
20004        cx: &mut Context<Self>,
20005    ) -> Option<TransactionId> {
20006        self.end_selection(window, cx);
20007        if let Some(tx_id) = self
20008            .buffer
20009            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
20010        {
20011            self.selection_history
20012                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
20013            cx.emit(EditorEvent::TransactionBegun {
20014                transaction_id: tx_id,
20015            });
20016            Some(tx_id)
20017        } else {
20018            None
20019        }
20020    }
20021
20022    pub fn end_transaction_at(
20023        &mut self,
20024        now: Instant,
20025        cx: &mut Context<Self>,
20026    ) -> Option<TransactionId> {
20027        if let Some(transaction_id) = self
20028            .buffer
20029            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
20030        {
20031            if let Some((_, end_selections)) =
20032                self.selection_history.transaction_mut(transaction_id)
20033            {
20034                *end_selections = Some(self.selections.disjoint_anchors_arc());
20035            } else {
20036                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
20037            }
20038
20039            cx.emit(EditorEvent::Edited { transaction_id });
20040            Some(transaction_id)
20041        } else {
20042            None
20043        }
20044    }
20045
20046    pub fn modify_transaction_selection_history(
20047        &mut self,
20048        transaction_id: TransactionId,
20049        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
20050    ) -> bool {
20051        self.selection_history
20052            .transaction_mut(transaction_id)
20053            .map(modify)
20054            .is_some()
20055    }
20056
20057    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
20058        if self.selection_mark_mode {
20059            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20060                s.move_with(&mut |_, sel| {
20061                    sel.collapse_to(sel.head(), SelectionGoal::None);
20062                });
20063            })
20064        }
20065        self.selection_mark_mode = true;
20066        cx.notify();
20067    }
20068
20069    pub fn swap_selection_ends(
20070        &mut self,
20071        _: &actions::SwapSelectionEnds,
20072        window: &mut Window,
20073        cx: &mut Context<Self>,
20074    ) {
20075        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20076            s.move_with(&mut |_, sel| {
20077                if sel.start != sel.end {
20078                    sel.reversed = !sel.reversed
20079                }
20080            });
20081        });
20082        self.request_autoscroll(Autoscroll::newest(), cx);
20083        cx.notify();
20084    }
20085
20086    pub fn toggle_focus(
20087        workspace: &mut Workspace,
20088        _: &actions::ToggleFocus,
20089        window: &mut Window,
20090        cx: &mut Context<Workspace>,
20091    ) {
20092        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20093            return;
20094        };
20095        workspace.activate_item(&item, true, true, window, cx);
20096    }
20097
20098    pub fn toggle_fold(
20099        &mut self,
20100        _: &actions::ToggleFold,
20101        window: &mut Window,
20102        cx: &mut Context<Self>,
20103    ) {
20104        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20105            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20106            let selection = self.selections.newest::<Point>(&display_map);
20107
20108            let range = if selection.is_empty() {
20109                let point = selection.head().to_display_point(&display_map);
20110                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20111                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20112                    .to_point(&display_map);
20113                start..end
20114            } else {
20115                selection.range()
20116            };
20117            if display_map.folds_in_range(range).next().is_some() {
20118                self.unfold_lines(&Default::default(), window, cx)
20119            } else {
20120                self.fold(&Default::default(), window, cx)
20121            }
20122        } else {
20123            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20124            let buffer_ids: HashSet<_> = self
20125                .selections
20126                .disjoint_anchor_ranges()
20127                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20128                .collect();
20129
20130            let should_unfold = buffer_ids
20131                .iter()
20132                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20133
20134            for buffer_id in buffer_ids {
20135                if should_unfold {
20136                    self.unfold_buffer(buffer_id, cx);
20137                } else {
20138                    self.fold_buffer(buffer_id, cx);
20139                }
20140            }
20141        }
20142    }
20143
20144    pub fn toggle_fold_recursive(
20145        &mut self,
20146        _: &actions::ToggleFoldRecursive,
20147        window: &mut Window,
20148        cx: &mut Context<Self>,
20149    ) {
20150        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20151
20152        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20153        let range = if selection.is_empty() {
20154            let point = selection.head().to_display_point(&display_map);
20155            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20156            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20157                .to_point(&display_map);
20158            start..end
20159        } else {
20160            selection.range()
20161        };
20162        if display_map.folds_in_range(range).next().is_some() {
20163            self.unfold_recursive(&Default::default(), window, cx)
20164        } else {
20165            self.fold_recursive(&Default::default(), window, cx)
20166        }
20167    }
20168
20169    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20170        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20171            let mut to_fold = Vec::new();
20172            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20173            let selections = self.selections.all_adjusted(&display_map);
20174
20175            for selection in selections {
20176                let range = selection.range().sorted();
20177                let buffer_start_row = range.start.row;
20178
20179                if range.start.row != range.end.row {
20180                    let mut found = false;
20181                    let mut row = range.start.row;
20182                    while row <= range.end.row {
20183                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20184                        {
20185                            found = true;
20186                            row = crease.range().end.row + 1;
20187                            to_fold.push(crease);
20188                        } else {
20189                            row += 1
20190                        }
20191                    }
20192                    if found {
20193                        continue;
20194                    }
20195                }
20196
20197                for row in (0..=range.start.row).rev() {
20198                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20199                        && crease.range().end.row >= buffer_start_row
20200                    {
20201                        to_fold.push(crease);
20202                        if row <= range.start.row {
20203                            break;
20204                        }
20205                    }
20206                }
20207            }
20208
20209            self.fold_creases(to_fold, true, window, cx);
20210        } else {
20211            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20212            let buffer_ids = self
20213                .selections
20214                .disjoint_anchor_ranges()
20215                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20216                .collect::<HashSet<_>>();
20217            for buffer_id in buffer_ids {
20218                self.fold_buffer(buffer_id, cx);
20219            }
20220        }
20221    }
20222
20223    pub fn toggle_fold_all(
20224        &mut self,
20225        _: &actions::ToggleFoldAll,
20226        window: &mut Window,
20227        cx: &mut Context<Self>,
20228    ) {
20229        let has_folds = if self.buffer.read(cx).is_singleton() {
20230            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20231            let has_folds = display_map
20232                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20233                .next()
20234                .is_some();
20235            has_folds
20236        } else {
20237            let snapshot = self.buffer.read(cx).snapshot(cx);
20238            let has_folds = snapshot
20239                .all_buffer_ids()
20240                .any(|buffer_id| self.is_buffer_folded(buffer_id, cx));
20241            has_folds
20242        };
20243
20244        if has_folds {
20245            self.unfold_all(&actions::UnfoldAll, window, cx);
20246        } else {
20247            self.fold_all(&actions::FoldAll, window, cx);
20248        }
20249    }
20250
20251    fn fold_at_level(
20252        &mut self,
20253        fold_at: &FoldAtLevel,
20254        window: &mut Window,
20255        cx: &mut Context<Self>,
20256    ) {
20257        if !self.buffer.read(cx).is_singleton() {
20258            return;
20259        }
20260
20261        let fold_at_level = fold_at.0;
20262        let snapshot = self.buffer.read(cx).snapshot(cx);
20263        let mut to_fold = Vec::new();
20264        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20265
20266        let row_ranges_to_keep: Vec<Range<u32>> = self
20267            .selections
20268            .all::<Point>(&self.display_snapshot(cx))
20269            .into_iter()
20270            .map(|sel| sel.start.row..sel.end.row)
20271            .collect();
20272
20273        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20274            while start_row < end_row {
20275                match self
20276                    .snapshot(window, cx)
20277                    .crease_for_buffer_row(MultiBufferRow(start_row))
20278                {
20279                    Some(crease) => {
20280                        let nested_start_row = crease.range().start.row + 1;
20281                        let nested_end_row = crease.range().end.row;
20282
20283                        if current_level < fold_at_level {
20284                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20285                        } else if current_level == fold_at_level {
20286                            // Fold iff there is no selection completely contained within the fold region
20287                            if !row_ranges_to_keep.iter().any(|selection| {
20288                                selection.end >= nested_start_row
20289                                    && selection.start <= nested_end_row
20290                            }) {
20291                                to_fold.push(crease);
20292                            }
20293                        }
20294
20295                        start_row = nested_end_row + 1;
20296                    }
20297                    None => start_row += 1,
20298                }
20299            }
20300        }
20301
20302        self.fold_creases(to_fold, true, window, cx);
20303    }
20304
20305    pub fn fold_at_level_1(
20306        &mut self,
20307        _: &actions::FoldAtLevel1,
20308        window: &mut Window,
20309        cx: &mut Context<Self>,
20310    ) {
20311        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20312    }
20313
20314    pub fn fold_at_level_2(
20315        &mut self,
20316        _: &actions::FoldAtLevel2,
20317        window: &mut Window,
20318        cx: &mut Context<Self>,
20319    ) {
20320        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20321    }
20322
20323    pub fn fold_at_level_3(
20324        &mut self,
20325        _: &actions::FoldAtLevel3,
20326        window: &mut Window,
20327        cx: &mut Context<Self>,
20328    ) {
20329        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20330    }
20331
20332    pub fn fold_at_level_4(
20333        &mut self,
20334        _: &actions::FoldAtLevel4,
20335        window: &mut Window,
20336        cx: &mut Context<Self>,
20337    ) {
20338        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20339    }
20340
20341    pub fn fold_at_level_5(
20342        &mut self,
20343        _: &actions::FoldAtLevel5,
20344        window: &mut Window,
20345        cx: &mut Context<Self>,
20346    ) {
20347        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20348    }
20349
20350    pub fn fold_at_level_6(
20351        &mut self,
20352        _: &actions::FoldAtLevel6,
20353        window: &mut Window,
20354        cx: &mut Context<Self>,
20355    ) {
20356        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20357    }
20358
20359    pub fn fold_at_level_7(
20360        &mut self,
20361        _: &actions::FoldAtLevel7,
20362        window: &mut Window,
20363        cx: &mut Context<Self>,
20364    ) {
20365        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20366    }
20367
20368    pub fn fold_at_level_8(
20369        &mut self,
20370        _: &actions::FoldAtLevel8,
20371        window: &mut Window,
20372        cx: &mut Context<Self>,
20373    ) {
20374        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20375    }
20376
20377    pub fn fold_at_level_9(
20378        &mut self,
20379        _: &actions::FoldAtLevel9,
20380        window: &mut Window,
20381        cx: &mut Context<Self>,
20382    ) {
20383        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20384    }
20385
20386    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20387        if self.buffer.read(cx).is_singleton() {
20388            let mut fold_ranges = Vec::new();
20389            let snapshot = self.buffer.read(cx).snapshot(cx);
20390
20391            for row in 0..snapshot.max_row().0 {
20392                if let Some(foldable_range) = self
20393                    .snapshot(window, cx)
20394                    .crease_for_buffer_row(MultiBufferRow(row))
20395                {
20396                    fold_ranges.push(foldable_range);
20397                }
20398            }
20399
20400            self.fold_creases(fold_ranges, true, window, cx);
20401        } else {
20402            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20403                editor
20404                    .update_in(cx, |editor, _, cx| {
20405                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20406                        for buffer_id in snapshot.all_buffer_ids() {
20407                            editor.fold_buffer(buffer_id, cx);
20408                        }
20409                    })
20410                    .ok();
20411            });
20412        }
20413    }
20414
20415    pub fn fold_function_bodies(
20416        &mut self,
20417        _: &actions::FoldFunctionBodies,
20418        window: &mut Window,
20419        cx: &mut Context<Self>,
20420    ) {
20421        let snapshot = self.buffer.read(cx).snapshot(cx);
20422
20423        let ranges = snapshot
20424            .text_object_ranges(
20425                MultiBufferOffset(0)..snapshot.len(),
20426                TreeSitterOptions::default(),
20427            )
20428            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20429            .collect::<Vec<_>>();
20430
20431        let creases = ranges
20432            .into_iter()
20433            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20434            .collect();
20435
20436        self.fold_creases(creases, true, window, cx);
20437    }
20438
20439    pub fn fold_recursive(
20440        &mut self,
20441        _: &actions::FoldRecursive,
20442        window: &mut Window,
20443        cx: &mut Context<Self>,
20444    ) {
20445        let mut to_fold = Vec::new();
20446        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20447        let selections = self.selections.all_adjusted(&display_map);
20448
20449        for selection in selections {
20450            let range = selection.range().sorted();
20451            let buffer_start_row = range.start.row;
20452
20453            if range.start.row != range.end.row {
20454                let mut found = false;
20455                for row in range.start.row..=range.end.row {
20456                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20457                        found = true;
20458                        to_fold.push(crease);
20459                    }
20460                }
20461                if found {
20462                    continue;
20463                }
20464            }
20465
20466            for row in (0..=range.start.row).rev() {
20467                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20468                    if crease.range().end.row >= buffer_start_row {
20469                        to_fold.push(crease);
20470                    } else {
20471                        break;
20472                    }
20473                }
20474            }
20475        }
20476
20477        self.fold_creases(to_fold, true, window, cx);
20478    }
20479
20480    pub fn fold_at(
20481        &mut self,
20482        buffer_row: MultiBufferRow,
20483        window: &mut Window,
20484        cx: &mut Context<Self>,
20485    ) {
20486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20487
20488        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20489            let autoscroll = self
20490                .selections
20491                .all::<Point>(&display_map)
20492                .iter()
20493                .any(|selection| crease.range().overlaps(&selection.range()));
20494
20495            self.fold_creases(vec![crease], autoscroll, window, cx);
20496        }
20497    }
20498
20499    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20500        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20501            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20502            let buffer = display_map.buffer_snapshot();
20503            let selections = self.selections.all::<Point>(&display_map);
20504            let ranges = selections
20505                .iter()
20506                .map(|s| {
20507                    let range = s.display_range(&display_map).sorted();
20508                    let mut start = range.start.to_point(&display_map);
20509                    let mut end = range.end.to_point(&display_map);
20510                    start.column = 0;
20511                    end.column = buffer.line_len(MultiBufferRow(end.row));
20512                    start..end
20513                })
20514                .collect::<Vec<_>>();
20515
20516            self.unfold_ranges(&ranges, true, true, cx);
20517        } else {
20518            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20519            let buffer_ids = self
20520                .selections
20521                .disjoint_anchor_ranges()
20522                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20523                .collect::<HashSet<_>>();
20524            for buffer_id in buffer_ids {
20525                self.unfold_buffer(buffer_id, cx);
20526            }
20527        }
20528    }
20529
20530    pub fn unfold_recursive(
20531        &mut self,
20532        _: &UnfoldRecursive,
20533        _window: &mut Window,
20534        cx: &mut Context<Self>,
20535    ) {
20536        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20537        let selections = self.selections.all::<Point>(&display_map);
20538        let ranges = selections
20539            .iter()
20540            .map(|s| {
20541                let mut range = s.display_range(&display_map).sorted();
20542                *range.start.column_mut() = 0;
20543                *range.end.column_mut() = display_map.line_len(range.end.row());
20544                let start = range.start.to_point(&display_map);
20545                let end = range.end.to_point(&display_map);
20546                start..end
20547            })
20548            .collect::<Vec<_>>();
20549
20550        self.unfold_ranges(&ranges, true, true, cx);
20551    }
20552
20553    pub fn unfold_at(
20554        &mut self,
20555        buffer_row: MultiBufferRow,
20556        _window: &mut Window,
20557        cx: &mut Context<Self>,
20558    ) {
20559        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20560
20561        let intersection_range = Point::new(buffer_row.0, 0)
20562            ..Point::new(
20563                buffer_row.0,
20564                display_map.buffer_snapshot().line_len(buffer_row),
20565            );
20566
20567        let autoscroll = self
20568            .selections
20569            .all::<Point>(&display_map)
20570            .iter()
20571            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20572
20573        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20574    }
20575
20576    pub fn unfold_all(
20577        &mut self,
20578        _: &actions::UnfoldAll,
20579        _window: &mut Window,
20580        cx: &mut Context<Self>,
20581    ) {
20582        if self.buffer.read(cx).is_singleton() {
20583            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20584            self.unfold_ranges(
20585                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20586                true,
20587                true,
20588                cx,
20589            );
20590        } else {
20591            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20592                editor
20593                    .update(cx, |editor, cx| {
20594                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20595                        for buffer_id in snapshot.all_buffer_ids() {
20596                            editor.unfold_buffer(buffer_id, cx);
20597                        }
20598                    })
20599                    .ok();
20600            });
20601        }
20602    }
20603
20604    pub fn fold_selected_ranges(
20605        &mut self,
20606        _: &FoldSelectedRanges,
20607        window: &mut Window,
20608        cx: &mut Context<Self>,
20609    ) {
20610        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20611        let selections = self.selections.all_adjusted(&display_map);
20612        let ranges = selections
20613            .into_iter()
20614            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20615            .collect::<Vec<_>>();
20616        self.fold_creases(ranges, true, window, cx);
20617    }
20618
20619    pub fn fold_ranges<T: ToOffset + Clone>(
20620        &mut self,
20621        ranges: Vec<Range<T>>,
20622        auto_scroll: bool,
20623        window: &mut Window,
20624        cx: &mut Context<Self>,
20625    ) {
20626        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20627        let ranges = ranges
20628            .into_iter()
20629            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20630            .collect::<Vec<_>>();
20631        self.fold_creases(ranges, auto_scroll, window, cx);
20632    }
20633
20634    pub fn fold_creases<T: ToOffset + Clone>(
20635        &mut self,
20636        creases: Vec<Crease<T>>,
20637        auto_scroll: bool,
20638        window: &mut Window,
20639        cx: &mut Context<Self>,
20640    ) {
20641        if creases.is_empty() {
20642            return;
20643        }
20644
20645        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20646
20647        if auto_scroll {
20648            self.request_autoscroll(Autoscroll::fit(), cx);
20649        }
20650
20651        cx.notify();
20652
20653        self.scrollbar_marker_state.dirty = true;
20654        self.update_data_on_scroll(window, cx);
20655        self.folds_did_change(cx);
20656    }
20657
20658    /// Removes any folds whose ranges intersect any of the given ranges.
20659    pub fn unfold_ranges<T: ToOffset + Clone>(
20660        &mut self,
20661        ranges: &[Range<T>],
20662        inclusive: bool,
20663        auto_scroll: bool,
20664        cx: &mut Context<Self>,
20665    ) {
20666        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20667            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20668        });
20669        self.folds_did_change(cx);
20670    }
20671
20672    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20673        self.fold_buffers([buffer_id], cx);
20674    }
20675
20676    pub fn fold_buffers(
20677        &mut self,
20678        buffer_ids: impl IntoIterator<Item = BufferId>,
20679        cx: &mut Context<Self>,
20680    ) {
20681        if self.buffer().read(cx).is_singleton() {
20682            return;
20683        }
20684
20685        let ids_to_fold: Vec<BufferId> = buffer_ids
20686            .into_iter()
20687            .filter(|id| !self.is_buffer_folded(*id, cx))
20688            .collect();
20689
20690        if ids_to_fold.is_empty() {
20691            return;
20692        }
20693
20694        self.display_map.update(cx, |display_map, cx| {
20695            display_map.fold_buffers(ids_to_fold.clone(), cx)
20696        });
20697
20698        let snapshot = self.display_snapshot(cx);
20699        self.selections.change_with(&snapshot, |selections| {
20700            for buffer_id in ids_to_fold.iter().copied() {
20701                selections.remove_selections_from_buffer(buffer_id);
20702            }
20703        });
20704
20705        cx.emit(EditorEvent::BufferFoldToggled {
20706            ids: ids_to_fold,
20707            folded: true,
20708        });
20709        cx.notify();
20710    }
20711
20712    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20713        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20714            return;
20715        }
20716        self.display_map.update(cx, |display_map, cx| {
20717            display_map.unfold_buffers([buffer_id], cx);
20718        });
20719        cx.emit(EditorEvent::BufferFoldToggled {
20720            ids: vec![buffer_id],
20721            folded: false,
20722        });
20723        cx.notify();
20724    }
20725
20726    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20727        self.display_map.read(cx).is_buffer_folded(buffer)
20728    }
20729
20730    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20731        if self.buffer().read(cx).is_singleton() {
20732            return false;
20733        }
20734        !self.folded_buffers(cx).is_empty()
20735    }
20736
20737    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20738        self.display_map.read(cx).folded_buffers()
20739    }
20740
20741    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20742        self.display_map.update(cx, |display_map, cx| {
20743            display_map.disable_header_for_buffer(buffer_id, cx);
20744        });
20745        cx.notify();
20746    }
20747
20748    /// Removes any folds with the given ranges.
20749    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20750        &mut self,
20751        ranges: &[Range<T>],
20752        type_id: TypeId,
20753        auto_scroll: bool,
20754        cx: &mut Context<Self>,
20755    ) {
20756        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20757            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20758        });
20759        self.folds_did_change(cx);
20760    }
20761
20762    fn remove_folds_with<T: ToOffset + Clone>(
20763        &mut self,
20764        ranges: &[Range<T>],
20765        auto_scroll: bool,
20766        cx: &mut Context<Self>,
20767        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20768    ) {
20769        if ranges.is_empty() {
20770            return;
20771        }
20772
20773        self.display_map.update(cx, update);
20774
20775        if auto_scroll {
20776            self.request_autoscroll(Autoscroll::fit(), cx);
20777        }
20778
20779        cx.notify();
20780        self.scrollbar_marker_state.dirty = true;
20781        self.active_indent_guides_state.dirty = true;
20782    }
20783
20784    pub fn update_renderer_widths(
20785        &mut self,
20786        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20787        cx: &mut Context<Self>,
20788    ) -> bool {
20789        self.display_map
20790            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20791    }
20792
20793    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20794        self.display_map.read(cx).fold_placeholder.clone()
20795    }
20796
20797    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20798        self.buffer.update(cx, |buffer, cx| {
20799            buffer.set_all_diff_hunks_expanded(cx);
20800        });
20801    }
20802
20803    pub fn expand_all_diff_hunks(
20804        &mut self,
20805        _: &ExpandAllDiffHunks,
20806        _window: &mut Window,
20807        cx: &mut Context<Self>,
20808    ) {
20809        self.buffer.update(cx, |buffer, cx| {
20810            buffer.expand_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20811        });
20812    }
20813
20814    pub fn collapse_all_diff_hunks(
20815        &mut self,
20816        _: &CollapseAllDiffHunks,
20817        _window: &mut Window,
20818        cx: &mut Context<Self>,
20819    ) {
20820        self.buffer.update(cx, |buffer, cx| {
20821            buffer.collapse_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20822        });
20823    }
20824
20825    pub fn toggle_selected_diff_hunks(
20826        &mut self,
20827        _: &ToggleSelectedDiffHunks,
20828        _window: &mut Window,
20829        cx: &mut Context<Self>,
20830    ) {
20831        let ranges: Vec<_> = self
20832            .selections
20833            .disjoint_anchors()
20834            .iter()
20835            .map(|s| s.range())
20836            .collect();
20837        self.toggle_diff_hunks_in_ranges(ranges, cx);
20838    }
20839
20840    pub fn diff_hunks_in_ranges<'a>(
20841        &'a self,
20842        ranges: &'a [Range<Anchor>],
20843        buffer: &'a MultiBufferSnapshot,
20844    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20845        ranges.iter().flat_map(move |range| {
20846            let end_excerpt = buffer.excerpt_containing(range.end..range.end);
20847            let range = range.to_point(buffer);
20848            let mut peek_end = range.end;
20849            if range.end.row < buffer.max_row().0 {
20850                peek_end = Point::new(range.end.row + 1, 0);
20851            }
20852            buffer
20853                .diff_hunks_in_range(range.start..peek_end)
20854                .filter(move |hunk| {
20855                    if let Some((_, excerpt_range)) = &end_excerpt
20856                        && let Some(end_anchor) =
20857                            buffer.anchor_in_excerpt(excerpt_range.context.end)
20858                        && let Some(hunk_end_anchor) =
20859                            buffer.anchor_in_excerpt(hunk.excerpt_range.context.end)
20860                        && hunk_end_anchor.cmp(&end_anchor, buffer).is_gt()
20861                    {
20862                        false
20863                    } else {
20864                        true
20865                    }
20866                })
20867        })
20868    }
20869
20870    pub fn has_stageable_diff_hunks_in_ranges(
20871        &self,
20872        ranges: &[Range<Anchor>],
20873        snapshot: &MultiBufferSnapshot,
20874    ) -> bool {
20875        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20876        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20877    }
20878
20879    pub fn toggle_staged_selected_diff_hunks(
20880        &mut self,
20881        _: &::git::ToggleStaged,
20882        _: &mut Window,
20883        cx: &mut Context<Self>,
20884    ) {
20885        let snapshot = self.buffer.read(cx).snapshot(cx);
20886        let ranges: Vec<_> = self
20887            .selections
20888            .disjoint_anchors()
20889            .iter()
20890            .map(|s| s.range())
20891            .collect();
20892        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20893        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20894    }
20895
20896    pub fn set_render_diff_hunk_controls(
20897        &mut self,
20898        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20899        cx: &mut Context<Self>,
20900    ) {
20901        self.render_diff_hunk_controls = render_diff_hunk_controls;
20902        cx.notify();
20903    }
20904
20905    pub fn stage_and_next(
20906        &mut self,
20907        _: &::git::StageAndNext,
20908        window: &mut Window,
20909        cx: &mut Context<Self>,
20910    ) {
20911        self.do_stage_or_unstage_and_next(true, window, cx);
20912    }
20913
20914    pub fn unstage_and_next(
20915        &mut self,
20916        _: &::git::UnstageAndNext,
20917        window: &mut Window,
20918        cx: &mut Context<Self>,
20919    ) {
20920        self.do_stage_or_unstage_and_next(false, window, cx);
20921    }
20922
20923    pub fn stage_or_unstage_diff_hunks(
20924        &mut self,
20925        stage: bool,
20926        ranges: Vec<Range<Anchor>>,
20927        cx: &mut Context<Self>,
20928    ) {
20929        if self.delegate_stage_and_restore {
20930            let snapshot = self.buffer.read(cx).snapshot(cx);
20931            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20932            if !hunks.is_empty() {
20933                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20934            }
20935            return;
20936        }
20937        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20938        cx.spawn(async move |this, cx| {
20939            task.await?;
20940            this.update(cx, |this, cx| {
20941                let snapshot = this.buffer.read(cx).snapshot(cx);
20942                let chunk_by = this
20943                    .diff_hunks_in_ranges(&ranges, &snapshot)
20944                    .chunk_by(|hunk| hunk.buffer_id);
20945                for (buffer_id, hunks) in &chunk_by {
20946                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20947                }
20948            })
20949        })
20950        .detach_and_log_err(cx);
20951    }
20952
20953    fn save_buffers_for_ranges_if_needed(
20954        &mut self,
20955        ranges: &[Range<Anchor>],
20956        cx: &mut Context<Editor>,
20957    ) -> Task<Result<()>> {
20958        let multibuffer = self.buffer.read(cx);
20959        let snapshot = multibuffer.read(cx);
20960        let buffer_ids: HashSet<_> = ranges
20961            .iter()
20962            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20963            .collect();
20964        drop(snapshot);
20965
20966        let mut buffers = HashSet::default();
20967        for buffer_id in buffer_ids {
20968            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20969                let buffer = buffer_entity.read(cx);
20970                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20971                {
20972                    buffers.insert(buffer_entity);
20973                }
20974            }
20975        }
20976
20977        if let Some(project) = &self.project {
20978            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20979        } else {
20980            Task::ready(Ok(()))
20981        }
20982    }
20983
20984    fn do_stage_or_unstage_and_next(
20985        &mut self,
20986        stage: bool,
20987        window: &mut Window,
20988        cx: &mut Context<Self>,
20989    ) {
20990        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20991
20992        if ranges.iter().any(|range| range.start != range.end) {
20993            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20994            return;
20995        }
20996
20997        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20998
20999        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
21000        let wrap_around = !all_diff_hunks_expanded;
21001        let snapshot = self.snapshot(window, cx);
21002        let position = self
21003            .selections
21004            .newest::<Point>(&snapshot.display_snapshot)
21005            .head();
21006
21007        self.go_to_hunk_before_or_after_position(
21008            &snapshot,
21009            position,
21010            Direction::Next,
21011            wrap_around,
21012            window,
21013            cx,
21014        );
21015    }
21016
21017    pub(crate) fn do_stage_or_unstage(
21018        &self,
21019        stage: bool,
21020        buffer_id: BufferId,
21021        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
21022        cx: &mut App,
21023    ) -> Option<()> {
21024        let project = self.project()?;
21025        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
21026        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
21027        let buffer_snapshot = buffer.read(cx).snapshot();
21028        let file_exists = buffer_snapshot
21029            .file()
21030            .is_some_and(|file| file.disk_state().exists());
21031        diff.update(cx, |diff, cx| {
21032            diff.stage_or_unstage_hunks(
21033                stage,
21034                &hunks
21035                    .map(|hunk| buffer_diff::DiffHunk {
21036                        buffer_range: hunk.buffer_range,
21037                        // We don't need to pass in word diffs here because they're only used for rendering and
21038                        // this function changes internal state
21039                        base_word_diffs: Vec::default(),
21040                        buffer_word_diffs: Vec::default(),
21041                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
21042                            ..hunk.diff_base_byte_range.end.0,
21043                        secondary_status: hunk.status.secondary,
21044                        range: Point::zero()..Point::zero(), // unused
21045                    })
21046                    .collect::<Vec<_>>(),
21047                &buffer_snapshot,
21048                file_exists,
21049                cx,
21050            )
21051        });
21052        None
21053    }
21054
21055    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
21056        let ranges: Vec<_> = self
21057            .selections
21058            .disjoint_anchors()
21059            .iter()
21060            .map(|s| s.range())
21061            .collect();
21062        self.buffer
21063            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
21064    }
21065
21066    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
21067        self.buffer.update(cx, |buffer, cx| {
21068            let ranges = vec![Anchor::Min..Anchor::Max];
21069            if !buffer.all_diff_hunks_expanded()
21070                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
21071            {
21072                buffer.collapse_diff_hunks(ranges, cx);
21073                true
21074            } else {
21075                false
21076            }
21077        })
21078    }
21079
21080    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21081        if self.buffer.read(cx).all_diff_hunks_expanded() {
21082            return true;
21083        }
21084        let ranges = vec![Anchor::Min..Anchor::Max];
21085        self.buffer
21086            .read(cx)
21087            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21088    }
21089
21090    fn toggle_diff_hunks_in_ranges(
21091        &mut self,
21092        ranges: Vec<Range<Anchor>>,
21093        cx: &mut Context<Editor>,
21094    ) {
21095        self.buffer.update(cx, |buffer, cx| {
21096            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21097            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21098        })
21099    }
21100
21101    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21102        self.buffer.update(cx, |buffer, cx| {
21103            buffer.toggle_single_diff_hunk(range, cx);
21104        })
21105    }
21106
21107    pub(crate) fn apply_all_diff_hunks(
21108        &mut self,
21109        _: &ApplyAllDiffHunks,
21110        window: &mut Window,
21111        cx: &mut Context<Self>,
21112    ) {
21113        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21114
21115        let buffers = self.buffer.read(cx).all_buffers();
21116        for branch_buffer in buffers {
21117            branch_buffer.update(cx, |branch_buffer, cx| {
21118                branch_buffer.merge_into_base(Vec::new(), cx);
21119            });
21120        }
21121
21122        if let Some(project) = self.project.clone() {
21123            self.save(
21124                SaveOptions {
21125                    format: true,
21126                    autosave: false,
21127                },
21128                project,
21129                window,
21130                cx,
21131            )
21132            .detach_and_log_err(cx);
21133        }
21134    }
21135
21136    pub(crate) fn apply_selected_diff_hunks(
21137        &mut self,
21138        _: &ApplyDiffHunk,
21139        window: &mut Window,
21140        cx: &mut Context<Self>,
21141    ) {
21142        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21143        let snapshot = self.snapshot(window, cx);
21144        let hunks = snapshot.hunks_for_ranges(
21145            self.selections
21146                .all(&snapshot.display_snapshot)
21147                .into_iter()
21148                .map(|selection| selection.range()),
21149        );
21150        let mut ranges_by_buffer = HashMap::default();
21151        self.transact(window, cx, |editor, _window, cx| {
21152            for hunk in hunks {
21153                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21154                    ranges_by_buffer
21155                        .entry(buffer.clone())
21156                        .or_insert_with(Vec::new)
21157                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21158                }
21159            }
21160
21161            for (buffer, ranges) in ranges_by_buffer {
21162                buffer.update(cx, |buffer, cx| {
21163                    buffer.merge_into_base(ranges, cx);
21164                });
21165            }
21166        });
21167
21168        if let Some(project) = self.project.clone() {
21169            self.save(
21170                SaveOptions {
21171                    format: true,
21172                    autosave: false,
21173                },
21174                project,
21175                window,
21176                cx,
21177            )
21178            .detach_and_log_err(cx);
21179        }
21180    }
21181
21182    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21183        if hovered != self.gutter_hovered {
21184            self.gutter_hovered = hovered;
21185            cx.notify();
21186        }
21187    }
21188
21189    pub fn insert_blocks(
21190        &mut self,
21191        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21192        autoscroll: Option<Autoscroll>,
21193        cx: &mut Context<Self>,
21194    ) -> Vec<CustomBlockId> {
21195        let blocks = self
21196            .display_map
21197            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21198        if let Some(autoscroll) = autoscroll {
21199            self.request_autoscroll(autoscroll, cx);
21200        }
21201        cx.notify();
21202        blocks
21203    }
21204
21205    pub fn resize_blocks(
21206        &mut self,
21207        heights: HashMap<CustomBlockId, u32>,
21208        autoscroll: Option<Autoscroll>,
21209        cx: &mut Context<Self>,
21210    ) {
21211        self.display_map
21212            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21213        if let Some(autoscroll) = autoscroll {
21214            self.request_autoscroll(autoscroll, cx);
21215        }
21216        cx.notify();
21217    }
21218
21219    pub fn replace_blocks(
21220        &mut self,
21221        renderers: HashMap<CustomBlockId, RenderBlock>,
21222        autoscroll: Option<Autoscroll>,
21223        cx: &mut Context<Self>,
21224    ) {
21225        self.display_map
21226            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21227        if let Some(autoscroll) = autoscroll {
21228            self.request_autoscroll(autoscroll, cx);
21229        }
21230        cx.notify();
21231    }
21232
21233    pub fn remove_blocks(
21234        &mut self,
21235        block_ids: HashSet<CustomBlockId>,
21236        autoscroll: Option<Autoscroll>,
21237        cx: &mut Context<Self>,
21238    ) {
21239        self.display_map.update(cx, |display_map, cx| {
21240            display_map.remove_blocks(block_ids, cx)
21241        });
21242        if let Some(autoscroll) = autoscroll {
21243            self.request_autoscroll(autoscroll, cx);
21244        }
21245        cx.notify();
21246    }
21247
21248    pub fn row_for_block(
21249        &self,
21250        block_id: CustomBlockId,
21251        cx: &mut Context<Self>,
21252    ) -> Option<DisplayRow> {
21253        self.display_map
21254            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21255    }
21256
21257    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21258        self.focused_block = Some(focused_block);
21259    }
21260
21261    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21262        self.focused_block.take()
21263    }
21264
21265    pub fn insert_creases(
21266        &mut self,
21267        creases: impl IntoIterator<Item = Crease<Anchor>>,
21268        cx: &mut Context<Self>,
21269    ) -> Vec<CreaseId> {
21270        self.display_map
21271            .update(cx, |map, cx| map.insert_creases(creases, cx))
21272    }
21273
21274    pub fn remove_creases(
21275        &mut self,
21276        ids: impl IntoIterator<Item = CreaseId>,
21277        cx: &mut Context<Self>,
21278    ) -> Vec<(CreaseId, Range<Anchor>)> {
21279        self.display_map
21280            .update(cx, |map, cx| map.remove_creases(ids, cx))
21281    }
21282
21283    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21284        self.display_map
21285            .update(cx, |map, cx| map.snapshot(cx))
21286            .longest_row()
21287    }
21288
21289    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21290        self.display_map
21291            .update(cx, |map, cx| map.snapshot(cx))
21292            .max_point()
21293    }
21294
21295    pub fn text(&self, cx: &App) -> String {
21296        self.buffer.read(cx).read(cx).text()
21297    }
21298
21299    pub fn is_empty(&self, cx: &App) -> bool {
21300        self.buffer.read(cx).read(cx).is_empty()
21301    }
21302
21303    pub fn text_option(&self, cx: &App) -> Option<String> {
21304        let text = self.text(cx);
21305        let text = text.trim();
21306
21307        if text.is_empty() {
21308            return None;
21309        }
21310
21311        Some(text.to_string())
21312    }
21313
21314    pub fn set_text(
21315        &mut self,
21316        text: impl Into<Arc<str>>,
21317        window: &mut Window,
21318        cx: &mut Context<Self>,
21319    ) {
21320        self.transact(window, cx, |this, _, cx| {
21321            this.buffer
21322                .read(cx)
21323                .as_singleton()
21324                .expect("you can only call set_text on editors for singleton buffers")
21325                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21326        });
21327    }
21328
21329    pub fn display_text(&self, cx: &mut App) -> String {
21330        self.display_map
21331            .update(cx, |map, cx| map.snapshot(cx))
21332            .text()
21333    }
21334
21335    fn create_minimap(
21336        &self,
21337        minimap_settings: MinimapSettings,
21338        window: &mut Window,
21339        cx: &mut Context<Self>,
21340    ) -> Option<Entity<Self>> {
21341        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21342            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21343    }
21344
21345    fn initialize_new_minimap(
21346        &self,
21347        minimap_settings: MinimapSettings,
21348        window: &mut Window,
21349        cx: &mut Context<Self>,
21350    ) -> Entity<Self> {
21351        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21352        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21353
21354        let mut minimap = Editor::new_internal(
21355            EditorMode::Minimap {
21356                parent: cx.weak_entity(),
21357            },
21358            self.buffer.clone(),
21359            None,
21360            Some(self.display_map.clone()),
21361            window,
21362            cx,
21363        );
21364        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21365        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21366        minimap.scroll_manager.clone_state(
21367            &self.scroll_manager,
21368            &my_snapshot,
21369            &minimap_snapshot,
21370            cx,
21371        );
21372        minimap.set_text_style_refinement(TextStyleRefinement {
21373            font_size: Some(MINIMAP_FONT_SIZE),
21374            font_weight: Some(MINIMAP_FONT_WEIGHT),
21375            font_family: Some(MINIMAP_FONT_FAMILY),
21376            ..Default::default()
21377        });
21378        minimap.update_minimap_configuration(minimap_settings, cx);
21379        cx.new(|_| minimap)
21380    }
21381
21382    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21383        let current_line_highlight = minimap_settings
21384            .current_line_highlight
21385            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21386        self.set_current_line_highlight(Some(current_line_highlight));
21387    }
21388
21389    pub fn minimap(&self) -> Option<&Entity<Self>> {
21390        self.minimap
21391            .as_ref()
21392            .filter(|_| self.minimap_visibility.visible())
21393    }
21394
21395    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21396        let mut wrap_guides = smallvec![];
21397
21398        if self.show_wrap_guides == Some(false) {
21399            return wrap_guides;
21400        }
21401
21402        let settings = self.buffer.read(cx).language_settings(cx);
21403        if settings.show_wrap_guides {
21404            match self.soft_wrap_mode(cx) {
21405                SoftWrap::Column(soft_wrap) => {
21406                    wrap_guides.push((soft_wrap as usize, true));
21407                }
21408                SoftWrap::Bounded(soft_wrap) => {
21409                    wrap_guides.push((soft_wrap as usize, true));
21410                }
21411                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21412            }
21413            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21414        }
21415
21416        wrap_guides
21417    }
21418
21419    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21420        let settings = self.buffer.read(cx).language_settings(cx);
21421        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21422        match mode {
21423            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21424                SoftWrap::None
21425            }
21426            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21427            language_settings::SoftWrap::PreferredLineLength => {
21428                SoftWrap::Column(settings.preferred_line_length)
21429            }
21430            language_settings::SoftWrap::Bounded => {
21431                SoftWrap::Bounded(settings.preferred_line_length)
21432            }
21433        }
21434    }
21435
21436    pub fn set_soft_wrap_mode(
21437        &mut self,
21438        mode: language_settings::SoftWrap,
21439        cx: &mut Context<Self>,
21440    ) {
21441        self.soft_wrap_mode_override = Some(mode);
21442        cx.notify();
21443    }
21444
21445    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21446        self.hard_wrap = hard_wrap;
21447        cx.notify();
21448    }
21449
21450    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21451        self.text_style_refinement = Some(style);
21452    }
21453
21454    /// called by the Element so we know what style we were most recently rendered with.
21455    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21456        // We intentionally do not inform the display map about the minimap style
21457        // so that wrapping is not recalculated and stays consistent for the editor
21458        // and its linked minimap.
21459        if !self.mode.is_minimap() {
21460            let font = style.text.font();
21461            let font_size = style.text.font_size.to_pixels(window.rem_size());
21462            let display_map = self
21463                .placeholder_display_map
21464                .as_ref()
21465                .filter(|_| self.is_empty(cx))
21466                .unwrap_or(&self.display_map);
21467
21468            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21469        }
21470        self.style = Some(style);
21471    }
21472
21473    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21474        if self.style.is_none() {
21475            self.style = Some(self.create_style(cx));
21476        }
21477        self.style.as_ref().unwrap()
21478    }
21479
21480    // Called by the element. This method is not designed to be called outside of the editor
21481    // element's layout code because it does not notify when rewrapping is computed synchronously.
21482    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21483        if self.is_empty(cx) {
21484            self.placeholder_display_map
21485                .as_ref()
21486                .map_or(false, |display_map| {
21487                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21488                })
21489        } else {
21490            self.display_map
21491                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21492        }
21493    }
21494
21495    pub fn set_soft_wrap(&mut self) {
21496        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21497    }
21498
21499    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21500        if self.soft_wrap_mode_override.is_some() {
21501            self.soft_wrap_mode_override.take();
21502        } else {
21503            let soft_wrap = match self.soft_wrap_mode(cx) {
21504                SoftWrap::GitDiff => return,
21505                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21506                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21507                    language_settings::SoftWrap::None
21508                }
21509            };
21510            self.soft_wrap_mode_override = Some(soft_wrap);
21511        }
21512        cx.notify();
21513    }
21514
21515    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21516        let Some(workspace) = self.workspace() else {
21517            return;
21518        };
21519        let fs = workspace.read(cx).app_state().fs.clone();
21520        let current_show = TabBarSettings::get_global(cx).show;
21521        update_settings_file(fs, cx, move |setting, _| {
21522            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21523        });
21524    }
21525
21526    pub fn toggle_indent_guides(
21527        &mut self,
21528        _: &ToggleIndentGuides,
21529        _: &mut Window,
21530        cx: &mut Context<Self>,
21531    ) {
21532        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21533            self.buffer
21534                .read(cx)
21535                .language_settings(cx)
21536                .indent_guides
21537                .enabled
21538        });
21539        self.show_indent_guides = Some(!currently_enabled);
21540        cx.notify();
21541    }
21542
21543    fn should_show_indent_guides(&self) -> Option<bool> {
21544        self.show_indent_guides
21545    }
21546
21547    pub fn disable_indent_guides_for_buffer(
21548        &mut self,
21549        buffer_id: BufferId,
21550        cx: &mut Context<Self>,
21551    ) {
21552        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21553        cx.notify();
21554    }
21555
21556    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21557        self.buffers_with_disabled_indent_guides
21558            .contains(&buffer_id)
21559    }
21560
21561    pub fn toggle_line_numbers(
21562        &mut self,
21563        _: &ToggleLineNumbers,
21564        _: &mut Window,
21565        cx: &mut Context<Self>,
21566    ) {
21567        let mut editor_settings = EditorSettings::get_global(cx).clone();
21568        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21569        EditorSettings::override_global(editor_settings, cx);
21570    }
21571
21572    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21573        if let Some(show_line_numbers) = self.show_line_numbers {
21574            return show_line_numbers;
21575        }
21576        EditorSettings::get_global(cx).gutter.line_numbers
21577    }
21578
21579    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21580        match (
21581            self.use_relative_line_numbers,
21582            EditorSettings::get_global(cx).relative_line_numbers,
21583        ) {
21584            (None, setting) => setting,
21585            (Some(false), _) => RelativeLineNumbers::Disabled,
21586            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21587            (Some(true), _) => RelativeLineNumbers::Enabled,
21588        }
21589    }
21590
21591    pub fn toggle_relative_line_numbers(
21592        &mut self,
21593        _: &ToggleRelativeLineNumbers,
21594        _: &mut Window,
21595        cx: &mut Context<Self>,
21596    ) {
21597        let is_relative = self.relative_line_numbers(cx);
21598        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21599    }
21600
21601    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21602        self.use_relative_line_numbers = is_relative;
21603        cx.notify();
21604    }
21605
21606    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21607        self.show_gutter = show_gutter;
21608        cx.notify();
21609    }
21610
21611    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21612        self.show_scrollbars = ScrollbarAxes {
21613            horizontal: show,
21614            vertical: show,
21615        };
21616        cx.notify();
21617    }
21618
21619    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21620        self.show_scrollbars.vertical = show;
21621        cx.notify();
21622    }
21623
21624    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21625        self.show_scrollbars.horizontal = show;
21626        cx.notify();
21627    }
21628
21629    pub fn set_minimap_visibility(
21630        &mut self,
21631        minimap_visibility: MinimapVisibility,
21632        window: &mut Window,
21633        cx: &mut Context<Self>,
21634    ) {
21635        if self.minimap_visibility != minimap_visibility {
21636            if minimap_visibility.visible() && self.minimap.is_none() {
21637                let minimap_settings = EditorSettings::get_global(cx).minimap;
21638                self.minimap =
21639                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21640            }
21641            self.minimap_visibility = minimap_visibility;
21642            cx.notify();
21643        }
21644    }
21645
21646    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21647        self.set_show_scrollbars(false, cx);
21648        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21649    }
21650
21651    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21652        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21653    }
21654
21655    /// Normally the text in full mode and auto height editors is padded on the
21656    /// left side by roughly half a character width for improved hit testing.
21657    ///
21658    /// Use this method to disable this for cases where this is not wanted (e.g.
21659    /// if you want to align the editor text with some other text above or below)
21660    /// or if you want to add this padding to single-line editors.
21661    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21662        self.offset_content = offset_content;
21663        cx.notify();
21664    }
21665
21666    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21667        self.show_line_numbers = Some(show_line_numbers);
21668        cx.notify();
21669    }
21670
21671    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21672        self.disable_expand_excerpt_buttons = true;
21673        cx.notify();
21674    }
21675
21676    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21677        self.number_deleted_lines = number;
21678        cx.notify();
21679    }
21680
21681    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21682        self.delegate_expand_excerpts = delegate;
21683    }
21684
21685    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21686        self.delegate_stage_and_restore = delegate;
21687    }
21688
21689    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21690        self.delegate_open_excerpts = delegate;
21691    }
21692
21693    pub fn set_on_local_selections_changed(
21694        &mut self,
21695        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21696    ) {
21697        self.on_local_selections_changed = callback;
21698    }
21699
21700    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21701        self.suppress_selection_callback = suppress;
21702    }
21703
21704    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21705        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21706        cx.notify();
21707    }
21708
21709    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21710        self.show_code_actions = Some(show_code_actions);
21711        cx.notify();
21712    }
21713
21714    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21715        self.show_runnables = Some(show_runnables);
21716        cx.notify();
21717    }
21718
21719    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21720        self.show_breakpoints = Some(show_breakpoints);
21721        cx.notify();
21722    }
21723
21724    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21725        self.show_diff_review_button = show;
21726        cx.notify();
21727    }
21728
21729    pub fn show_diff_review_button(&self) -> bool {
21730        self.show_diff_review_button
21731    }
21732
21733    pub fn render_diff_review_button(
21734        &self,
21735        display_row: DisplayRow,
21736        width: Pixels,
21737        cx: &mut Context<Self>,
21738    ) -> impl IntoElement {
21739        let text_color = cx.theme().colors().text;
21740        let icon_color = cx.theme().colors().icon_accent;
21741
21742        h_flex()
21743            .id("diff_review_button")
21744            .cursor_pointer()
21745            .w(width - px(1.))
21746            .h(relative(0.9))
21747            .justify_center()
21748            .rounded_sm()
21749            .border_1()
21750            .border_color(text_color.opacity(0.1))
21751            .bg(text_color.opacity(0.15))
21752            .hover(|s| {
21753                s.bg(icon_color.opacity(0.4))
21754                    .border_color(icon_color.opacity(0.5))
21755            })
21756            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21757            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21758            .on_mouse_down(
21759                gpui::MouseButton::Left,
21760                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21761                    editor.start_diff_review_drag(display_row, window, cx);
21762                }),
21763            )
21764    }
21765
21766    pub fn start_diff_review_drag(
21767        &mut self,
21768        display_row: DisplayRow,
21769        window: &mut Window,
21770        cx: &mut Context<Self>,
21771    ) {
21772        let snapshot = self.snapshot(window, cx);
21773        let point = snapshot
21774            .display_snapshot
21775            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21776        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21777        self.diff_review_drag_state = Some(DiffReviewDragState {
21778            start_anchor: anchor,
21779            current_anchor: anchor,
21780        });
21781        cx.notify();
21782    }
21783
21784    pub fn update_diff_review_drag(
21785        &mut self,
21786        display_row: DisplayRow,
21787        window: &mut Window,
21788        cx: &mut Context<Self>,
21789    ) {
21790        if self.diff_review_drag_state.is_none() {
21791            return;
21792        }
21793        let snapshot = self.snapshot(window, cx);
21794        let point = snapshot
21795            .display_snapshot
21796            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21797        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21798        if let Some(drag_state) = &mut self.diff_review_drag_state {
21799            drag_state.current_anchor = anchor;
21800            cx.notify();
21801        }
21802    }
21803
21804    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21805        if let Some(drag_state) = self.diff_review_drag_state.take() {
21806            let snapshot = self.snapshot(window, cx);
21807            let range = drag_state.row_range(&snapshot.display_snapshot);
21808            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21809        }
21810        cx.notify();
21811    }
21812
21813    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21814        self.diff_review_drag_state = None;
21815        cx.notify();
21816    }
21817
21818    /// Calculates the appropriate block height for the diff review overlay.
21819    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21820    /// and 2 lines per comment when expanded.
21821    fn calculate_overlay_height(
21822        &self,
21823        hunk_key: &DiffHunkKey,
21824        comments_expanded: bool,
21825        snapshot: &MultiBufferSnapshot,
21826    ) -> u32 {
21827        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21828        let base_height: u32 = 2; // Input row with avatar and buttons
21829
21830        if comment_count == 0 {
21831            base_height
21832        } else if comments_expanded {
21833            // Header (1 line) + 2 lines per comment
21834            base_height + 1 + (comment_count as u32 * 2)
21835        } else {
21836            // Just header when collapsed
21837            base_height + 1
21838        }
21839    }
21840
21841    pub fn show_diff_review_overlay(
21842        &mut self,
21843        display_range: Range<DisplayRow>,
21844        window: &mut Window,
21845        cx: &mut Context<Self>,
21846    ) {
21847        let Range { start, end } = display_range.sorted();
21848
21849        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21850        let editor_snapshot = self.snapshot(window, cx);
21851
21852        // Convert display rows to multibuffer points
21853        let start_point = editor_snapshot
21854            .display_snapshot
21855            .display_point_to_point(start.as_display_point(), Bias::Left);
21856        let end_point = editor_snapshot
21857            .display_snapshot
21858            .display_point_to_point(end.as_display_point(), Bias::Left);
21859        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21860
21861        // Create anchor range for the selected lines (start of first line to end of last line)
21862        let line_end = Point::new(
21863            end_point.row,
21864            buffer_snapshot.line_len(end_multi_buffer_row),
21865        );
21866        let anchor_range =
21867            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21868
21869        // Compute the hunk key for this display row
21870        let file_path = buffer_snapshot
21871            .file_at(start_point)
21872            .map(|file: &Arc<dyn language::File>| file.path().clone())
21873            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21874        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21875        let new_hunk_key = DiffHunkKey {
21876            file_path,
21877            hunk_start_anchor,
21878        };
21879
21880        // Check if we already have an overlay for this hunk
21881        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21882            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21883        }) {
21884            // Just focus the existing overlay's prompt editor
21885            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21886            window.focus(&focus_handle, cx);
21887            return;
21888        }
21889
21890        // Dismiss overlays that have no comments for their hunks
21891        self.dismiss_overlays_without_comments(cx);
21892
21893        // Get the current user's avatar URI from the project's user_store
21894        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21895            let user_store = project.read(cx).user_store();
21896            user_store
21897                .read(cx)
21898                .current_user()
21899                .map(|user| user.avatar_uri.clone())
21900        });
21901
21902        // Create anchor at the end of the last row so the block appears immediately below it
21903        // Use multibuffer coordinates for anchor creation
21904        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21905        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21906
21907        // Use the hunk key we already computed
21908        let hunk_key = new_hunk_key;
21909
21910        // Create the prompt editor for the review input
21911        let prompt_editor = cx.new(|cx| {
21912            let mut editor = Editor::single_line(window, cx);
21913            editor.set_placeholder_text("Add a review comment...", window, cx);
21914            editor
21915        });
21916
21917        // Register the Newline action on the prompt editor to submit the review
21918        let parent_editor = cx.entity().downgrade();
21919        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21920            prompt_editor.register_action({
21921                let parent_editor = parent_editor.clone();
21922                move |_: &crate::actions::Newline, window, cx| {
21923                    if let Some(editor) = parent_editor.upgrade() {
21924                        editor.update(cx, |editor, cx| {
21925                            editor.submit_diff_review_comment(window, cx);
21926                        });
21927                    }
21928                }
21929            })
21930        });
21931
21932        // Calculate initial height based on existing comments for this hunk
21933        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21934
21935        // Create the overlay block
21936        let prompt_editor_for_render = prompt_editor.clone();
21937        let hunk_key_for_render = hunk_key.clone();
21938        let editor_handle = cx.entity().downgrade();
21939        let block = BlockProperties {
21940            style: BlockStyle::Sticky,
21941            placement: BlockPlacement::Below(anchor),
21942            height: Some(initial_height),
21943            render: Arc::new(move |cx| {
21944                Self::render_diff_review_overlay(
21945                    &prompt_editor_for_render,
21946                    &hunk_key_for_render,
21947                    &editor_handle,
21948                    cx,
21949                )
21950            }),
21951            priority: 0,
21952        };
21953
21954        let block_ids = self.insert_blocks([block], None, cx);
21955        let Some(block_id) = block_ids.into_iter().next() else {
21956            log::error!("Failed to insert diff review overlay block");
21957            return;
21958        };
21959
21960        self.diff_review_overlays.push(DiffReviewOverlay {
21961            anchor_range,
21962            block_id,
21963            prompt_editor: prompt_editor.clone(),
21964            hunk_key,
21965            comments_expanded: true,
21966            inline_edit_editors: HashMap::default(),
21967            inline_edit_subscriptions: HashMap::default(),
21968            user_avatar_uri,
21969            _subscription: subscription,
21970        });
21971
21972        // Focus the prompt editor
21973        let focus_handle = prompt_editor.focus_handle(cx);
21974        window.focus(&focus_handle, cx);
21975
21976        cx.notify();
21977    }
21978
21979    /// Dismisses all diff review overlays.
21980    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21981        if self.diff_review_overlays.is_empty() {
21982            return;
21983        }
21984        let block_ids: HashSet<_> = self
21985            .diff_review_overlays
21986            .drain(..)
21987            .map(|overlay| overlay.block_id)
21988            .collect();
21989        self.remove_blocks(block_ids, None, cx);
21990        cx.notify();
21991    }
21992
21993    /// Dismisses overlays that have no comments stored for their hunks.
21994    /// Keeps overlays that have at least one comment.
21995    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21996        let snapshot = self.buffer.read(cx).snapshot(cx);
21997
21998        // First, compute which overlays have comments (to avoid borrow issues with retain)
21999        let overlays_with_comments: Vec<bool> = self
22000            .diff_review_overlays
22001            .iter()
22002            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
22003            .collect();
22004
22005        // Now collect block IDs to remove and retain overlays
22006        let mut block_ids_to_remove = HashSet::default();
22007        let mut index = 0;
22008        self.diff_review_overlays.retain(|overlay| {
22009            let has_comments = overlays_with_comments[index];
22010            index += 1;
22011            if !has_comments {
22012                block_ids_to_remove.insert(overlay.block_id);
22013            }
22014            has_comments
22015        });
22016
22017        if !block_ids_to_remove.is_empty() {
22018            self.remove_blocks(block_ids_to_remove, None, cx);
22019            cx.notify();
22020        }
22021    }
22022
22023    /// Refreshes the diff review overlay block to update its height and render function.
22024    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
22025    fn refresh_diff_review_overlay_height(
22026        &mut self,
22027        hunk_key: &DiffHunkKey,
22028        _window: &mut Window,
22029        cx: &mut Context<Self>,
22030    ) {
22031        // Extract all needed data from overlay first to avoid borrow conflicts
22032        let snapshot = self.buffer.read(cx).snapshot(cx);
22033        let (comments_expanded, block_id, prompt_editor) = {
22034            let Some(overlay) = self
22035                .diff_review_overlays
22036                .iter()
22037                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22038            else {
22039                return;
22040            };
22041
22042            (
22043                overlay.comments_expanded,
22044                overlay.block_id,
22045                overlay.prompt_editor.clone(),
22046            )
22047        };
22048
22049        // Calculate new height
22050        let snapshot = self.buffer.read(cx).snapshot(cx);
22051        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
22052
22053        // Update the block height using resize_blocks (avoids flicker)
22054        let mut heights = HashMap::default();
22055        heights.insert(block_id, new_height);
22056        self.resize_blocks(heights, None, cx);
22057
22058        // Update the render function using replace_blocks (avoids flicker)
22059        let hunk_key_for_render = hunk_key.clone();
22060        let editor_handle = cx.entity().downgrade();
22061        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
22062            Arc::new(move |cx| {
22063                Self::render_diff_review_overlay(
22064                    &prompt_editor,
22065                    &hunk_key_for_render,
22066                    &editor_handle,
22067                    cx,
22068                )
22069            });
22070
22071        let mut renderers = HashMap::default();
22072        renderers.insert(block_id, render);
22073        self.replace_blocks(renderers, None, cx);
22074    }
22075
22076    /// Action handler for SubmitDiffReviewComment.
22077    pub fn submit_diff_review_comment_action(
22078        &mut self,
22079        _: &SubmitDiffReviewComment,
22080        window: &mut Window,
22081        cx: &mut Context<Self>,
22082    ) {
22083        self.submit_diff_review_comment(window, cx);
22084    }
22085
22086    /// Stores the diff review comment locally.
22087    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22088    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22089        // Find the overlay that currently has focus
22090        let overlay_index = self
22091            .diff_review_overlays
22092            .iter()
22093            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22094        let Some(overlay_index) = overlay_index else {
22095            return;
22096        };
22097        let overlay = &self.diff_review_overlays[overlay_index];
22098
22099        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22100        if comment_text.is_empty() {
22101            return;
22102        }
22103
22104        let anchor_range = overlay.anchor_range.clone();
22105        let hunk_key = overlay.hunk_key.clone();
22106
22107        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22108
22109        // Clear the prompt editor but keep the overlay open
22110        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22111            overlay.prompt_editor.update(cx, |editor, cx| {
22112                editor.clear(window, cx);
22113            });
22114        }
22115
22116        // Refresh the overlay to update the block height for the new comment
22117        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22118
22119        cx.notify();
22120    }
22121
22122    /// Returns the prompt editor for the diff review overlay, if one is active.
22123    /// This is primarily used for testing.
22124    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22125        self.diff_review_overlays
22126            .first()
22127            .map(|overlay| &overlay.prompt_editor)
22128    }
22129
22130    /// Returns the line range for the first diff review overlay, if one is active.
22131    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22132    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22133        let overlay = self.diff_review_overlays.first()?;
22134        let snapshot = self.buffer.read(cx).snapshot(cx);
22135        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22136        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22137        let start_row = snapshot
22138            .point_to_buffer_point(start_point)
22139            .map(|(_, p)| p.row)
22140            .unwrap_or(start_point.row);
22141        let end_row = snapshot
22142            .point_to_buffer_point(end_point)
22143            .map(|(_, p)| p.row)
22144            .unwrap_or(end_point.row);
22145        Some((start_row, end_row))
22146    }
22147
22148    /// Sets whether the comments section is expanded in the diff review overlay.
22149    /// This is primarily used for testing.
22150    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22151        for overlay in &mut self.diff_review_overlays {
22152            overlay.comments_expanded = expanded;
22153        }
22154        cx.notify();
22155    }
22156
22157    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22158    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22159        a.file_path == b.file_path
22160            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22161    }
22162
22163    /// Returns comments for a specific hunk, ordered by creation time.
22164    pub fn comments_for_hunk<'a>(
22165        &'a self,
22166        key: &DiffHunkKey,
22167        snapshot: &MultiBufferSnapshot,
22168    ) -> &'a [StoredReviewComment] {
22169        let key_point = key.hunk_start_anchor.to_point(snapshot);
22170        self.stored_review_comments
22171            .iter()
22172            .find(|(k, _)| {
22173                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22174            })
22175            .map(|(_, comments)| comments.as_slice())
22176            .unwrap_or(&[])
22177    }
22178
22179    /// Returns the total count of stored review comments across all hunks.
22180    pub fn total_review_comment_count(&self) -> usize {
22181        self.stored_review_comments
22182            .iter()
22183            .map(|(_, v)| v.len())
22184            .sum()
22185    }
22186
22187    /// Returns the count of comments for a specific hunk.
22188    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22189        let key_point = key.hunk_start_anchor.to_point(snapshot);
22190        self.stored_review_comments
22191            .iter()
22192            .find(|(k, _)| {
22193                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22194            })
22195            .map(|(_, v)| v.len())
22196            .unwrap_or(0)
22197    }
22198
22199    /// Adds a new review comment to a specific hunk.
22200    pub fn add_review_comment(
22201        &mut self,
22202        hunk_key: DiffHunkKey,
22203        comment: String,
22204        anchor_range: Range<Anchor>,
22205        cx: &mut Context<Self>,
22206    ) -> usize {
22207        let id = self.next_review_comment_id;
22208        self.next_review_comment_id += 1;
22209
22210        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22211
22212        let snapshot = self.buffer.read(cx).snapshot(cx);
22213        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22214
22215        // Find existing entry for this hunk or add a new one
22216        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22217            k.file_path == hunk_key.file_path
22218                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22219        }) {
22220            comments.push(stored_comment);
22221        } else {
22222            self.stored_review_comments
22223                .push((hunk_key, vec![stored_comment]));
22224        }
22225
22226        cx.emit(EditorEvent::ReviewCommentsChanged {
22227            total_count: self.total_review_comment_count(),
22228        });
22229        cx.notify();
22230        id
22231    }
22232
22233    /// Removes a review comment by ID from any hunk.
22234    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22235        for (_, comments) in self.stored_review_comments.iter_mut() {
22236            if let Some(index) = comments.iter().position(|c| c.id == id) {
22237                comments.remove(index);
22238                cx.emit(EditorEvent::ReviewCommentsChanged {
22239                    total_count: self.total_review_comment_count(),
22240                });
22241                cx.notify();
22242                return true;
22243            }
22244        }
22245        false
22246    }
22247
22248    /// Updates a review comment's text by ID.
22249    pub fn update_review_comment(
22250        &mut self,
22251        id: usize,
22252        new_comment: String,
22253        cx: &mut Context<Self>,
22254    ) -> bool {
22255        for (_, comments) in self.stored_review_comments.iter_mut() {
22256            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22257                comment.comment = new_comment;
22258                comment.is_editing = false;
22259                cx.emit(EditorEvent::ReviewCommentsChanged {
22260                    total_count: self.total_review_comment_count(),
22261                });
22262                cx.notify();
22263                return true;
22264            }
22265        }
22266        false
22267    }
22268
22269    /// Sets a comment's editing state.
22270    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22271        for (_, comments) in self.stored_review_comments.iter_mut() {
22272            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22273                comment.is_editing = is_editing;
22274                cx.notify();
22275                return;
22276            }
22277        }
22278    }
22279
22280    /// Takes all stored comments from all hunks, clearing the storage.
22281    /// Returns a Vec of (hunk_key, comments) pairs.
22282    pub fn take_all_review_comments(
22283        &mut self,
22284        cx: &mut Context<Self>,
22285    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22286        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22287        self.dismiss_all_diff_review_overlays(cx);
22288        let comments = std::mem::take(&mut self.stored_review_comments);
22289        // Reset the ID counter since all comments have been taken
22290        self.next_review_comment_id = 0;
22291        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22292        cx.notify();
22293        comments
22294    }
22295
22296    /// Removes review comments whose anchors are no longer valid or whose
22297    /// associated diff hunks no longer exist.
22298    ///
22299    /// This should be called when the buffer changes to prevent orphaned comments
22300    /// from accumulating.
22301    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22302        let snapshot = self.buffer.read(cx).snapshot(cx);
22303        let original_count = self.total_review_comment_count();
22304
22305        // Remove comments with invalid hunk anchors
22306        self.stored_review_comments
22307            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22308
22309        // Also clean up individual comments with invalid anchor ranges
22310        for (_, comments) in &mut self.stored_review_comments {
22311            comments.retain(|comment| {
22312                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22313            });
22314        }
22315
22316        // Remove empty hunk entries
22317        self.stored_review_comments
22318            .retain(|(_, comments)| !comments.is_empty());
22319
22320        let new_count = self.total_review_comment_count();
22321        if new_count != original_count {
22322            cx.emit(EditorEvent::ReviewCommentsChanged {
22323                total_count: new_count,
22324            });
22325            cx.notify();
22326        }
22327    }
22328
22329    /// Toggles the expanded state of the comments section in the overlay.
22330    pub fn toggle_review_comments_expanded(
22331        &mut self,
22332        _: &ToggleReviewCommentsExpanded,
22333        window: &mut Window,
22334        cx: &mut Context<Self>,
22335    ) {
22336        // Find the overlay that currently has focus, or use the first one
22337        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22338            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22339                overlay.comments_expanded = !overlay.comments_expanded;
22340                Some(overlay.hunk_key.clone())
22341            } else {
22342                None
22343            }
22344        });
22345
22346        // If no focused overlay found, toggle the first one
22347        let hunk_key = overlay_info.or_else(|| {
22348            self.diff_review_overlays.first_mut().map(|overlay| {
22349                overlay.comments_expanded = !overlay.comments_expanded;
22350                overlay.hunk_key.clone()
22351            })
22352        });
22353
22354        if let Some(hunk_key) = hunk_key {
22355            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22356            cx.notify();
22357        }
22358    }
22359
22360    /// Handles the EditReviewComment action - sets a comment into editing mode.
22361    pub fn edit_review_comment(
22362        &mut self,
22363        action: &EditReviewComment,
22364        window: &mut Window,
22365        cx: &mut Context<Self>,
22366    ) {
22367        let comment_id = action.id;
22368
22369        // Set the comment to editing mode
22370        self.set_comment_editing(comment_id, true, cx);
22371
22372        // Find the overlay that contains this comment and create an inline editor if needed
22373        // First, find which hunk this comment belongs to
22374        let hunk_key = self
22375            .stored_review_comments
22376            .iter()
22377            .find_map(|(key, comments)| {
22378                if comments.iter().any(|c| c.id == comment_id) {
22379                    Some(key.clone())
22380                } else {
22381                    None
22382                }
22383            });
22384
22385        let snapshot = self.buffer.read(cx).snapshot(cx);
22386        if let Some(hunk_key) = hunk_key {
22387            if let Some(overlay) = self
22388                .diff_review_overlays
22389                .iter_mut()
22390                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22391            {
22392                if let std::collections::hash_map::Entry::Vacant(entry) =
22393                    overlay.inline_edit_editors.entry(comment_id)
22394                {
22395                    // Find the comment text
22396                    let comment_text = self
22397                        .stored_review_comments
22398                        .iter()
22399                        .flat_map(|(_, comments)| comments)
22400                        .find(|c| c.id == comment_id)
22401                        .map(|c| c.comment.clone())
22402                        .unwrap_or_default();
22403
22404                    // Create inline editor
22405                    let parent_editor = cx.entity().downgrade();
22406                    let inline_editor = cx.new(|cx| {
22407                        let mut editor = Editor::single_line(window, cx);
22408                        editor.set_text(&*comment_text, window, cx);
22409                        // Select all text for easy replacement
22410                        editor.select_all(&crate::actions::SelectAll, window, cx);
22411                        editor
22412                    });
22413
22414                    // Register the Newline action to confirm the edit
22415                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22416                        inline_editor.register_action({
22417                            let parent_editor = parent_editor.clone();
22418                            move |_: &crate::actions::Newline, window, cx| {
22419                                if let Some(editor) = parent_editor.upgrade() {
22420                                    editor.update(cx, |editor, cx| {
22421                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22422                                    });
22423                                }
22424                            }
22425                        })
22426                    });
22427
22428                    // Store the subscription to keep the action handler alive
22429                    overlay
22430                        .inline_edit_subscriptions
22431                        .insert(comment_id, subscription);
22432
22433                    // Focus the inline editor
22434                    let focus_handle = inline_editor.focus_handle(cx);
22435                    window.focus(&focus_handle, cx);
22436
22437                    entry.insert(inline_editor);
22438                }
22439            }
22440        }
22441
22442        cx.notify();
22443    }
22444
22445    /// Confirms an inline edit of a review comment.
22446    pub fn confirm_edit_review_comment(
22447        &mut self,
22448        comment_id: usize,
22449        _window: &mut Window,
22450        cx: &mut Context<Self>,
22451    ) {
22452        // Get the new text from the inline editor
22453        // Find the overlay containing this comment's inline editor
22454        let snapshot = self.buffer.read(cx).snapshot(cx);
22455        let hunk_key = self
22456            .stored_review_comments
22457            .iter()
22458            .find_map(|(key, comments)| {
22459                if comments.iter().any(|c| c.id == comment_id) {
22460                    Some(key.clone())
22461                } else {
22462                    None
22463                }
22464            });
22465
22466        let new_text = hunk_key
22467            .as_ref()
22468            .and_then(|hunk_key| {
22469                self.diff_review_overlays
22470                    .iter()
22471                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22472            })
22473            .as_ref()
22474            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22475            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22476
22477        if let Some(new_text) = new_text {
22478            if !new_text.is_empty() {
22479                self.update_review_comment(comment_id, new_text, cx);
22480            }
22481        }
22482
22483        // Remove the inline editor and its subscription
22484        if let Some(hunk_key) = hunk_key {
22485            if let Some(overlay) = self
22486                .diff_review_overlays
22487                .iter_mut()
22488                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22489            {
22490                overlay.inline_edit_editors.remove(&comment_id);
22491                overlay.inline_edit_subscriptions.remove(&comment_id);
22492            }
22493        }
22494
22495        // Clear editing state
22496        self.set_comment_editing(comment_id, false, cx);
22497    }
22498
22499    /// Cancels an inline edit of a review comment.
22500    pub fn cancel_edit_review_comment(
22501        &mut self,
22502        comment_id: usize,
22503        _window: &mut Window,
22504        cx: &mut Context<Self>,
22505    ) {
22506        // Find which hunk this comment belongs to
22507        let hunk_key = self
22508            .stored_review_comments
22509            .iter()
22510            .find_map(|(key, comments)| {
22511                if comments.iter().any(|c| c.id == comment_id) {
22512                    Some(key.clone())
22513                } else {
22514                    None
22515                }
22516            });
22517
22518        // Remove the inline editor and its subscription
22519        if let Some(hunk_key) = hunk_key {
22520            let snapshot = self.buffer.read(cx).snapshot(cx);
22521            if let Some(overlay) = self
22522                .diff_review_overlays
22523                .iter_mut()
22524                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22525            {
22526                overlay.inline_edit_editors.remove(&comment_id);
22527                overlay.inline_edit_subscriptions.remove(&comment_id);
22528            }
22529        }
22530
22531        // Clear editing state
22532        self.set_comment_editing(comment_id, false, cx);
22533    }
22534
22535    /// Action handler for ConfirmEditReviewComment.
22536    pub fn confirm_edit_review_comment_action(
22537        &mut self,
22538        action: &ConfirmEditReviewComment,
22539        window: &mut Window,
22540        cx: &mut Context<Self>,
22541    ) {
22542        self.confirm_edit_review_comment(action.id, window, cx);
22543    }
22544
22545    /// Action handler for CancelEditReviewComment.
22546    pub fn cancel_edit_review_comment_action(
22547        &mut self,
22548        action: &CancelEditReviewComment,
22549        window: &mut Window,
22550        cx: &mut Context<Self>,
22551    ) {
22552        self.cancel_edit_review_comment(action.id, window, cx);
22553    }
22554
22555    /// Handles the DeleteReviewComment action - removes a comment.
22556    pub fn delete_review_comment(
22557        &mut self,
22558        action: &DeleteReviewComment,
22559        window: &mut Window,
22560        cx: &mut Context<Self>,
22561    ) {
22562        // Get the hunk key before removing the comment
22563        // Find the hunk key from the comment itself
22564        let comment_id = action.id;
22565        let hunk_key = self
22566            .stored_review_comments
22567            .iter()
22568            .find_map(|(key, comments)| {
22569                if comments.iter().any(|c| c.id == comment_id) {
22570                    Some(key.clone())
22571                } else {
22572                    None
22573                }
22574            });
22575
22576        // Also get it from the overlay for refresh purposes
22577        let overlay_hunk_key = self
22578            .diff_review_overlays
22579            .first()
22580            .map(|o| o.hunk_key.clone());
22581
22582        self.remove_review_comment(action.id, cx);
22583
22584        // Refresh the overlay height after removing a comment
22585        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22586            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22587        }
22588    }
22589
22590    fn render_diff_review_overlay(
22591        prompt_editor: &Entity<Editor>,
22592        hunk_key: &DiffHunkKey,
22593        editor_handle: &WeakEntity<Editor>,
22594        cx: &mut BlockContext,
22595    ) -> AnyElement {
22596        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22597            if ranges.is_empty() {
22598                return None;
22599            }
22600            let formatted: Vec<String> = ranges
22601                .iter()
22602                .map(|(start, end)| {
22603                    let start_line = start + 1;
22604                    let end_line = end + 1;
22605                    if start_line == end_line {
22606                        format!("Line {start_line}")
22607                    } else {
22608                        format!("Lines {start_line}-{end_line}")
22609                    }
22610                })
22611                .collect();
22612            // Don't show label for single line in single excerpt
22613            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22614                return None;
22615            }
22616            Some(formatted.join(""))
22617        }
22618
22619        let theme = cx.theme();
22620        let colors = theme.colors();
22621
22622        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22623            editor_handle
22624                .upgrade()
22625                .map(|editor| {
22626                    let editor = editor.read(cx);
22627                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22628                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22629                    let (expanded, editors, avatar_uri, line_ranges) = editor
22630                        .diff_review_overlays
22631                        .iter()
22632                        .find(|overlay| {
22633                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22634                        })
22635                        .map(|o| {
22636                            let start_point = o.anchor_range.start.to_point(&snapshot);
22637                            let end_point = o.anchor_range.end.to_point(&snapshot);
22638                            // Get line ranges per excerpt to detect discontinuities
22639                            let buffer_ranges =
22640                                snapshot.range_to_buffer_ranges(start_point..end_point);
22641                            let ranges: Vec<(u32, u32)> = buffer_ranges
22642                                .iter()
22643                                .map(|(buffer_snapshot, range, _)| {
22644                                    let start = buffer_snapshot.offset_to_point(range.start.0).row;
22645                                    let end = buffer_snapshot.offset_to_point(range.end.0).row;
22646                                    (start, end)
22647                                })
22648                                .collect();
22649                            (
22650                                o.comments_expanded,
22651                                o.inline_edit_editors.clone(),
22652                                o.user_avatar_uri.clone(),
22653                                if ranges.is_empty() {
22654                                    None
22655                                } else {
22656                                    Some(ranges)
22657                                },
22658                            )
22659                        })
22660                        .unwrap_or((true, HashMap::default(), None, None));
22661                    (comments, expanded, editors, avatar_uri, line_ranges)
22662                })
22663                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22664
22665        let comment_count = comments.len();
22666        let avatar_size = px(20.);
22667        let action_icon_size = IconSize::XSmall;
22668
22669        v_flex()
22670            .w_full()
22671            .bg(colors.editor_background)
22672            .border_b_1()
22673            .border_color(colors.border)
22674            .px_2()
22675            .pb_2()
22676            .gap_2()
22677            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22678            .when_some(line_ranges, |el, ranges| {
22679                let label = format_line_ranges(&ranges);
22680                if let Some(label) = label {
22681                    el.child(
22682                        h_flex()
22683                            .w_full()
22684                            .px_2()
22685                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22686                    )
22687                } else {
22688                    el
22689                }
22690            })
22691            // Top row: editable input with user's avatar
22692            .child(
22693                h_flex()
22694                    .w_full()
22695                    .items_center()
22696                    .gap_2()
22697                    .px_2()
22698                    .py_1p5()
22699                    .rounded_md()
22700                    .bg(colors.surface_background)
22701                    .child(
22702                        div()
22703                            .size(avatar_size)
22704                            .flex_shrink_0()
22705                            .rounded_full()
22706                            .overflow_hidden()
22707                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22708                                Avatar::new(avatar_uri.clone())
22709                                    .size(avatar_size)
22710                                    .into_any_element()
22711                            } else {
22712                                Icon::new(IconName::Person)
22713                                    .size(IconSize::Small)
22714                                    .color(ui::Color::Muted)
22715                                    .into_any_element()
22716                            }),
22717                    )
22718                    .child(
22719                        div()
22720                            .flex_1()
22721                            .border_1()
22722                            .border_color(colors.border)
22723                            .rounded_md()
22724                            .bg(colors.editor_background)
22725                            .px_2()
22726                            .py_1()
22727                            .child(prompt_editor.clone()),
22728                    )
22729                    .child(
22730                        h_flex()
22731                            .flex_shrink_0()
22732                            .gap_1()
22733                            .child(
22734                                IconButton::new("diff-review-close", IconName::Close)
22735                                    .icon_color(ui::Color::Muted)
22736                                    .icon_size(action_icon_size)
22737                                    .tooltip(Tooltip::text("Close"))
22738                                    .on_click(|_, window, cx| {
22739                                        window
22740                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22741                                    }),
22742                            )
22743                            .child(
22744                                IconButton::new("diff-review-add", IconName::Return)
22745                                    .icon_color(ui::Color::Muted)
22746                                    .icon_size(action_icon_size)
22747                                    .tooltip(Tooltip::text("Add comment"))
22748                                    .on_click(|_, window, cx| {
22749                                        window.dispatch_action(
22750                                            Box::new(crate::actions::SubmitDiffReviewComment),
22751                                            cx,
22752                                        );
22753                                    }),
22754                            ),
22755                    ),
22756            )
22757            // Expandable comments section (only shown when there are comments)
22758            .when(comment_count > 0, |el| {
22759                el.child(Self::render_comments_section(
22760                    comments,
22761                    comments_expanded,
22762                    inline_editors,
22763                    user_avatar_uri,
22764                    avatar_size,
22765                    action_icon_size,
22766                    colors,
22767                ))
22768            })
22769            .into_any_element()
22770    }
22771
22772    fn render_comments_section(
22773        comments: Vec<StoredReviewComment>,
22774        expanded: bool,
22775        inline_editors: HashMap<usize, Entity<Editor>>,
22776        user_avatar_uri: Option<SharedUri>,
22777        avatar_size: Pixels,
22778        action_icon_size: IconSize,
22779        colors: &theme::ThemeColors,
22780    ) -> impl IntoElement {
22781        let comment_count = comments.len();
22782
22783        v_flex()
22784            .w_full()
22785            .gap_1()
22786            // Header with expand/collapse toggle
22787            .child(
22788                h_flex()
22789                    .id("review-comments-header")
22790                    .w_full()
22791                    .items_center()
22792                    .gap_1()
22793                    .px_2()
22794                    .py_1()
22795                    .cursor_pointer()
22796                    .rounded_md()
22797                    .hover(|style| style.bg(colors.ghost_element_hover))
22798                    .on_click(|_, window: &mut Window, cx| {
22799                        window.dispatch_action(
22800                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22801                            cx,
22802                        );
22803                    })
22804                    .child(
22805                        Icon::new(if expanded {
22806                            IconName::ChevronDown
22807                        } else {
22808                            IconName::ChevronRight
22809                        })
22810                        .size(IconSize::Small)
22811                        .color(ui::Color::Muted),
22812                    )
22813                    .child(
22814                        Label::new(format!(
22815                            "{} Comment{}",
22816                            comment_count,
22817                            if comment_count == 1 { "" } else { "s" }
22818                        ))
22819                        .size(LabelSize::Small)
22820                        .color(Color::Muted),
22821                    ),
22822            )
22823            // Comments list (when expanded)
22824            .when(expanded, |el| {
22825                el.children(comments.into_iter().map(|comment| {
22826                    let inline_editor = inline_editors.get(&comment.id).cloned();
22827                    Self::render_comment_row(
22828                        comment,
22829                        inline_editor,
22830                        user_avatar_uri.clone(),
22831                        avatar_size,
22832                        action_icon_size,
22833                        colors,
22834                    )
22835                }))
22836            })
22837    }
22838
22839    fn render_comment_row(
22840        comment: StoredReviewComment,
22841        inline_editor: Option<Entity<Editor>>,
22842        user_avatar_uri: Option<SharedUri>,
22843        avatar_size: Pixels,
22844        action_icon_size: IconSize,
22845        colors: &theme::ThemeColors,
22846    ) -> impl IntoElement {
22847        let comment_id = comment.id;
22848        let is_editing = inline_editor.is_some();
22849
22850        h_flex()
22851            .w_full()
22852            .items_center()
22853            .gap_2()
22854            .px_2()
22855            .py_1p5()
22856            .rounded_md()
22857            .bg(colors.surface_background)
22858            .child(
22859                div()
22860                    .size(avatar_size)
22861                    .flex_shrink_0()
22862                    .rounded_full()
22863                    .overflow_hidden()
22864                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22865                        Avatar::new(avatar_uri.clone())
22866                            .size(avatar_size)
22867                            .into_any_element()
22868                    } else {
22869                        Icon::new(IconName::Person)
22870                            .size(IconSize::Small)
22871                            .color(ui::Color::Muted)
22872                            .into_any_element()
22873                    }),
22874            )
22875            .child(if let Some(editor) = inline_editor {
22876                // Inline edit mode: show an editable text field
22877                div()
22878                    .flex_1()
22879                    .border_1()
22880                    .border_color(colors.border)
22881                    .rounded_md()
22882                    .bg(colors.editor_background)
22883                    .px_2()
22884                    .py_1()
22885                    .child(editor)
22886                    .into_any_element()
22887            } else {
22888                // Display mode: show the comment text
22889                div()
22890                    .flex_1()
22891                    .text_sm()
22892                    .text_color(colors.text)
22893                    .child(comment.comment)
22894                    .into_any_element()
22895            })
22896            .child(if is_editing {
22897                // Editing mode: show close and confirm buttons
22898                h_flex()
22899                    .gap_1()
22900                    .child(
22901                        IconButton::new(
22902                            format!("diff-review-cancel-edit-{comment_id}"),
22903                            IconName::Close,
22904                        )
22905                        .icon_color(ui::Color::Muted)
22906                        .icon_size(action_icon_size)
22907                        .tooltip(Tooltip::text("Cancel"))
22908                        .on_click(move |_, window, cx| {
22909                            window.dispatch_action(
22910                                Box::new(crate::actions::CancelEditReviewComment {
22911                                    id: comment_id,
22912                                }),
22913                                cx,
22914                            );
22915                        }),
22916                    )
22917                    .child(
22918                        IconButton::new(
22919                            format!("diff-review-confirm-edit-{comment_id}"),
22920                            IconName::Return,
22921                        )
22922                        .icon_color(ui::Color::Muted)
22923                        .icon_size(action_icon_size)
22924                        .tooltip(Tooltip::text("Confirm"))
22925                        .on_click(move |_, window, cx| {
22926                            window.dispatch_action(
22927                                Box::new(crate::actions::ConfirmEditReviewComment {
22928                                    id: comment_id,
22929                                }),
22930                                cx,
22931                            );
22932                        }),
22933                    )
22934                    .into_any_element()
22935            } else {
22936                // Display mode: no action buttons for now (edit/delete not yet implemented)
22937                gpui::Empty.into_any_element()
22938            })
22939    }
22940
22941    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22942        if self.display_map.read(cx).masked != masked {
22943            self.display_map.update(cx, |map, _| map.masked = masked);
22944        }
22945        cx.notify()
22946    }
22947
22948    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22949        self.show_wrap_guides = Some(show_wrap_guides);
22950        cx.notify();
22951    }
22952
22953    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22954        self.show_indent_guides = Some(show_indent_guides);
22955        cx.notify();
22956    }
22957
22958    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22959        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22960            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22961                && let Some(dir) = file.abs_path(cx).parent()
22962            {
22963                return Some(dir.to_owned());
22964            }
22965        }
22966
22967        None
22968    }
22969
22970    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22971        self.active_buffer(cx)?
22972            .read(cx)
22973            .file()
22974            .and_then(|f| f.as_local())
22975    }
22976
22977    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22978        self.active_buffer(cx).and_then(|buffer| {
22979            let buffer = buffer.read(cx);
22980            if let Some(project_path) = buffer.project_path(cx) {
22981                let project = self.project()?.read(cx);
22982                project.absolute_path(&project_path, cx)
22983            } else {
22984                buffer
22985                    .file()
22986                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22987            }
22988        })
22989    }
22990
22991    pub fn reveal_in_finder(
22992        &mut self,
22993        _: &RevealInFileManager,
22994        _window: &mut Window,
22995        cx: &mut Context<Self>,
22996    ) {
22997        if let Some(path) = self.target_file_abs_path(cx) {
22998            if let Some(project) = self.project() {
22999                project.update(cx, |project, cx| project.reveal_path(&path, cx));
23000            } else {
23001                cx.reveal_path(&path);
23002            }
23003        }
23004    }
23005
23006    pub fn copy_path(
23007        &mut self,
23008        _: &zed_actions::workspace::CopyPath,
23009        _window: &mut Window,
23010        cx: &mut Context<Self>,
23011    ) {
23012        if let Some(path) = self.target_file_abs_path(cx)
23013            && let Some(path) = path.to_str()
23014        {
23015            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23016        } else {
23017            cx.propagate();
23018        }
23019    }
23020
23021    pub fn copy_relative_path(
23022        &mut self,
23023        _: &zed_actions::workspace::CopyRelativePath,
23024        _window: &mut Window,
23025        cx: &mut Context<Self>,
23026    ) {
23027        if let Some(path) = self.active_buffer(cx).and_then(|buffer| {
23028            let project = self.project()?.read(cx);
23029            let path = buffer.read(cx).file()?.path();
23030            let path = path.display(project.path_style(cx));
23031            Some(path)
23032        }) {
23033            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23034        } else {
23035            cx.propagate();
23036        }
23037    }
23038
23039    /// Returns the project path for the editor's buffer, if any buffer is
23040    /// opened in the editor.
23041    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
23042        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
23043            buffer.read(cx).project_path(cx)
23044        } else {
23045            None
23046        }
23047    }
23048
23049    // Returns true if the editor handled a go-to-line request
23050    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
23051        maybe!({
23052            let breakpoint_store = self.breakpoint_store.as_ref()?;
23053
23054            let (active_stack_frame, debug_line_pane_id) = {
23055                let store = breakpoint_store.read(cx);
23056                let active_stack_frame = store.active_position().cloned();
23057                let debug_line_pane_id = store.active_debug_line_pane_id();
23058                (active_stack_frame, debug_line_pane_id)
23059            };
23060
23061            let Some(active_stack_frame) = active_stack_frame else {
23062                self.clear_row_highlights::<ActiveDebugLine>();
23063                return None;
23064            };
23065
23066            if let Some(debug_line_pane_id) = debug_line_pane_id {
23067                if let Some(workspace) = self
23068                    .workspace
23069                    .as_ref()
23070                    .and_then(|(workspace, _)| workspace.upgrade())
23071                {
23072                    let editor_pane_id = workspace
23073                        .read(cx)
23074                        .pane_for_item_id(cx.entity_id())
23075                        .map(|pane| pane.entity_id());
23076
23077                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
23078                        self.clear_row_highlights::<ActiveDebugLine>();
23079                        return None;
23080                    }
23081                }
23082            }
23083
23084            let position = active_stack_frame.position;
23085
23086            let snapshot = self.buffer.read(cx).snapshot(cx);
23087            let multibuffer_anchor = snapshot.anchor_in_excerpt(position)?;
23088
23089            self.clear_row_highlights::<ActiveDebugLine>();
23090
23091            self.go_to_line::<ActiveDebugLine>(
23092                multibuffer_anchor,
23093                Some(cx.theme().colors().editor_debugger_active_line_background),
23094                window,
23095                cx,
23096            );
23097
23098            cx.notify();
23099
23100            Some(())
23101        })
23102        .is_some()
23103    }
23104
23105    pub fn copy_file_name_without_extension(
23106        &mut self,
23107        _: &CopyFileNameWithoutExtension,
23108        _: &mut Window,
23109        cx: &mut Context<Self>,
23110    ) {
23111        if let Some(file_stem) = self.active_buffer(cx).and_then(|buffer| {
23112            let file = buffer.read(cx).file()?;
23113            file.path().file_stem()
23114        }) {
23115            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23116        }
23117    }
23118
23119    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23120        if let Some(file_name) = self.active_buffer(cx).and_then(|buffer| {
23121            let file = buffer.read(cx).file()?;
23122            Some(file.file_name(cx))
23123        }) {
23124            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23125        }
23126    }
23127
23128    pub fn toggle_git_blame(
23129        &mut self,
23130        _: &::git::Blame,
23131        window: &mut Window,
23132        cx: &mut Context<Self>,
23133    ) {
23134        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23135
23136        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23137            self.start_git_blame(true, window, cx);
23138        }
23139
23140        cx.notify();
23141    }
23142
23143    pub fn toggle_git_blame_inline(
23144        &mut self,
23145        _: &ToggleGitBlameInline,
23146        window: &mut Window,
23147        cx: &mut Context<Self>,
23148    ) {
23149        self.toggle_git_blame_inline_internal(true, window, cx);
23150        cx.notify();
23151    }
23152
23153    pub fn open_git_blame_commit(
23154        &mut self,
23155        _: &OpenGitBlameCommit,
23156        window: &mut Window,
23157        cx: &mut Context<Self>,
23158    ) {
23159        self.open_git_blame_commit_internal(window, cx);
23160    }
23161
23162    fn open_git_blame_commit_internal(
23163        &mut self,
23164        window: &mut Window,
23165        cx: &mut Context<Self>,
23166    ) -> Option<()> {
23167        let blame = self.blame.as_ref()?;
23168        let snapshot = self.snapshot(window, cx);
23169        let cursor = self
23170            .selections
23171            .newest::<Point>(&snapshot.display_snapshot)
23172            .head();
23173        let (buffer, point) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23174        let (_, blame_entry) = blame
23175            .update(cx, |blame, cx| {
23176                blame
23177                    .blame_for_rows(
23178                        &[RowInfo {
23179                            buffer_id: Some(buffer.remote_id()),
23180                            buffer_row: Some(point.row),
23181                            ..Default::default()
23182                        }],
23183                        cx,
23184                    )
23185                    .next()
23186            })
23187            .flatten()?;
23188        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23189        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23190        let workspace = self.workspace()?.downgrade();
23191        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23192        None
23193    }
23194
23195    pub fn git_blame_inline_enabled(&self) -> bool {
23196        self.git_blame_inline_enabled
23197    }
23198
23199    pub fn toggle_selection_menu(
23200        &mut self,
23201        _: &ToggleSelectionMenu,
23202        _: &mut Window,
23203        cx: &mut Context<Self>,
23204    ) {
23205        self.show_selection_menu = self
23206            .show_selection_menu
23207            .map(|show_selections_menu| !show_selections_menu)
23208            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23209
23210        cx.notify();
23211    }
23212
23213    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23214        self.show_selection_menu
23215            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23216    }
23217
23218    fn start_git_blame(
23219        &mut self,
23220        user_triggered: bool,
23221        window: &mut Window,
23222        cx: &mut Context<Self>,
23223    ) {
23224        if let Some(project) = self.project() {
23225            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23226                && buffer.read(cx).file().is_none()
23227            {
23228                return;
23229            }
23230
23231            let focused = self.focus_handle(cx).contains_focused(window, cx);
23232
23233            let project = project.clone();
23234            let blame = cx
23235                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23236            self.blame_subscription =
23237                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23238            self.blame = Some(blame);
23239        }
23240    }
23241
23242    fn toggle_git_blame_inline_internal(
23243        &mut self,
23244        user_triggered: bool,
23245        window: &mut Window,
23246        cx: &mut Context<Self>,
23247    ) {
23248        if self.git_blame_inline_enabled {
23249            self.git_blame_inline_enabled = false;
23250            self.show_git_blame_inline = false;
23251            self.show_git_blame_inline_delay_task.take();
23252        } else {
23253            self.git_blame_inline_enabled = true;
23254            self.start_git_blame_inline(user_triggered, window, cx);
23255        }
23256
23257        cx.notify();
23258    }
23259
23260    fn start_git_blame_inline(
23261        &mut self,
23262        user_triggered: bool,
23263        window: &mut Window,
23264        cx: &mut Context<Self>,
23265    ) {
23266        self.start_git_blame(user_triggered, window, cx);
23267
23268        if ProjectSettings::get_global(cx)
23269            .git
23270            .inline_blame_delay()
23271            .is_some()
23272        {
23273            self.start_inline_blame_timer(window, cx);
23274        } else {
23275            self.show_git_blame_inline = true
23276        }
23277    }
23278
23279    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23280        self.blame.as_ref()
23281    }
23282
23283    pub fn show_git_blame_gutter(&self) -> bool {
23284        self.show_git_blame_gutter
23285    }
23286
23287    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23288        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23289    }
23290
23291    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23292        self.show_git_blame_inline
23293            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23294            && !self.newest_selection_head_on_empty_line(cx)
23295            && self.has_blame_entries(cx)
23296    }
23297
23298    fn has_blame_entries(&self, cx: &App) -> bool {
23299        self.blame()
23300            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23301    }
23302
23303    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23304        let cursor_anchor = self.selections.newest_anchor().head();
23305
23306        let snapshot = self.buffer.read(cx).snapshot(cx);
23307        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23308
23309        snapshot.line_len(buffer_row) == 0
23310    }
23311
23312    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23313        let buffer_and_selection = maybe!({
23314            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23315            let selection_range = selection.range();
23316
23317            let multi_buffer = self.buffer().read(cx);
23318            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23319            let buffer_ranges = multi_buffer_snapshot
23320                .range_to_buffer_ranges(selection_range.start..selection_range.end);
23321
23322            let (buffer_snapshot, range, _) = if selection.reversed {
23323                buffer_ranges.first()
23324            } else {
23325                buffer_ranges.last()
23326            }?;
23327
23328            let buffer_range = range.to_point(buffer_snapshot);
23329            let buffer = multi_buffer.buffer(buffer_snapshot.remote_id()).unwrap();
23330
23331            let Some(buffer_diff) = multi_buffer.diff_for(buffer_snapshot.remote_id()) else {
23332                return Some((buffer, buffer_range.start.row..buffer_range.end.row));
23333            };
23334
23335            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23336            let start = buffer_diff_snapshot
23337                .buffer_point_to_base_text_point(buffer_range.start, &buffer_snapshot);
23338            let end = buffer_diff_snapshot
23339                .buffer_point_to_base_text_point(buffer_range.end, &buffer_snapshot);
23340
23341            Some((buffer, start.row..end.row))
23342        });
23343
23344        let Some((buffer, selection)) = buffer_and_selection else {
23345            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23346        };
23347
23348        let Some(project) = self.project() else {
23349            return Task::ready(Err(anyhow!("editor does not have project")));
23350        };
23351
23352        project.update(cx, |project, cx| {
23353            project.get_permalink_to_line(&buffer, selection, cx)
23354        })
23355    }
23356
23357    pub fn copy_permalink_to_line(
23358        &mut self,
23359        _: &CopyPermalinkToLine,
23360        window: &mut Window,
23361        cx: &mut Context<Self>,
23362    ) {
23363        let permalink_task = self.get_permalink_to_line(cx);
23364        let workspace = self.workspace();
23365
23366        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23367            Ok(permalink) => {
23368                cx.update(|_, cx| {
23369                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23370                })
23371                .ok();
23372            }
23373            Err(err) => {
23374                let message = format!("Failed to copy permalink: {err}");
23375
23376                anyhow::Result::<()>::Err(err).log_err();
23377
23378                if let Some(workspace) = workspace {
23379                    workspace
23380                        .update_in(cx, |workspace, _, cx| {
23381                            struct CopyPermalinkToLine;
23382
23383                            workspace.show_toast(
23384                                Toast::new(
23385                                    NotificationId::unique::<CopyPermalinkToLine>(),
23386                                    message,
23387                                ),
23388                                cx,
23389                            )
23390                        })
23391                        .ok();
23392                }
23393            }
23394        })
23395        .detach();
23396    }
23397
23398    pub fn copy_file_location(
23399        &mut self,
23400        _: &CopyFileLocation,
23401        _: &mut Window,
23402        cx: &mut Context<Self>,
23403    ) {
23404        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23405
23406        let start_line = selection.start.row + 1;
23407        let end_line = selection.end.row + 1;
23408
23409        let end_line = if selection.end.column == 0 && end_line > start_line {
23410            end_line - 1
23411        } else {
23412            end_line
23413        };
23414
23415        if let Some(file_location) = self.active_buffer(cx).and_then(|buffer| {
23416            let project = self.project()?.read(cx);
23417            let file = buffer.read(cx).file()?;
23418            let path = file.path().display(project.path_style(cx));
23419
23420            let location = if start_line == end_line {
23421                format!("{path}:{start_line}")
23422            } else {
23423                format!("{path}:{start_line}-{end_line}")
23424            };
23425            Some(location)
23426        }) {
23427            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23428        }
23429    }
23430
23431    pub fn open_permalink_to_line(
23432        &mut self,
23433        _: &OpenPermalinkToLine,
23434        window: &mut Window,
23435        cx: &mut Context<Self>,
23436    ) {
23437        let permalink_task = self.get_permalink_to_line(cx);
23438        let workspace = self.workspace();
23439
23440        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23441            Ok(permalink) => {
23442                cx.update(|_, cx| {
23443                    cx.open_url(permalink.as_ref());
23444                })
23445                .ok();
23446            }
23447            Err(err) => {
23448                let message = format!("Failed to open permalink: {err}");
23449
23450                anyhow::Result::<()>::Err(err).log_err();
23451
23452                if let Some(workspace) = workspace {
23453                    workspace.update(cx, |workspace, cx| {
23454                        struct OpenPermalinkToLine;
23455
23456                        workspace.show_toast(
23457                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23458                            cx,
23459                        )
23460                    });
23461                }
23462            }
23463        })
23464        .detach();
23465    }
23466
23467    pub fn insert_uuid_v4(
23468        &mut self,
23469        _: &InsertUuidV4,
23470        window: &mut Window,
23471        cx: &mut Context<Self>,
23472    ) {
23473        self.insert_uuid(UuidVersion::V4, window, cx);
23474    }
23475
23476    pub fn insert_uuid_v7(
23477        &mut self,
23478        _: &InsertUuidV7,
23479        window: &mut Window,
23480        cx: &mut Context<Self>,
23481    ) {
23482        self.insert_uuid(UuidVersion::V7, window, cx);
23483    }
23484
23485    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23487        self.transact(window, cx, |this, window, cx| {
23488            let edits = this
23489                .selections
23490                .all::<Point>(&this.display_snapshot(cx))
23491                .into_iter()
23492                .map(|selection| {
23493                    let uuid = match version {
23494                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23495                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23496                    };
23497
23498                    (selection.range(), uuid.to_string())
23499                });
23500            this.edit(edits, cx);
23501            this.refresh_edit_prediction(true, false, window, cx);
23502        });
23503    }
23504
23505    pub fn open_selections_in_multibuffer(
23506        &mut self,
23507        _: &OpenSelectionsInMultibuffer,
23508        window: &mut Window,
23509        cx: &mut Context<Self>,
23510    ) {
23511        let multibuffer = self.buffer.read(cx);
23512
23513        let Some(buffer) = multibuffer.as_singleton() else {
23514            return;
23515        };
23516        let buffer_snapshot = buffer.read(cx).snapshot();
23517
23518        let Some(workspace) = self.workspace() else {
23519            return;
23520        };
23521
23522        let title = multibuffer.title(cx).to_string();
23523
23524        let locations = self
23525            .selections
23526            .all_anchors(&self.display_snapshot(cx))
23527            .iter()
23528            .map(|selection| {
23529                (
23530                    buffer.clone(),
23531                    (selection.start.text_anchor_in(&buffer_snapshot)
23532                        ..selection.end.text_anchor_in(&buffer_snapshot))
23533                        .to_point(buffer.read(cx)),
23534                )
23535            })
23536            .into_group_map();
23537
23538        cx.spawn_in(window, async move |_, cx| {
23539            workspace.update_in(cx, |workspace, window, cx| {
23540                Self::open_locations_in_multibuffer(
23541                    workspace,
23542                    locations,
23543                    format!("Selections for '{title}'"),
23544                    false,
23545                    false,
23546                    MultibufferSelectionMode::All,
23547                    window,
23548                    cx,
23549                );
23550            })
23551        })
23552        .detach();
23553    }
23554
23555    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23556    /// last highlight added will be used.
23557    ///
23558    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23559    pub fn highlight_rows<T: 'static>(
23560        &mut self,
23561        range: Range<Anchor>,
23562        color: Hsla,
23563        options: RowHighlightOptions,
23564        cx: &mut Context<Self>,
23565    ) {
23566        let snapshot = self.buffer().read(cx).snapshot(cx);
23567        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23568        let ix = row_highlights.binary_search_by(|highlight| {
23569            Ordering::Equal
23570                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23571                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23572        });
23573
23574        if let Err(mut ix) = ix {
23575            let index = post_inc(&mut self.highlight_order);
23576
23577            // If this range intersects with the preceding highlight, then merge it with
23578            // the preceding highlight. Otherwise insert a new highlight.
23579            let mut merged = false;
23580            if ix > 0 {
23581                let prev_highlight = &mut row_highlights[ix - 1];
23582                if prev_highlight
23583                    .range
23584                    .end
23585                    .cmp(&range.start, &snapshot)
23586                    .is_ge()
23587                {
23588                    ix -= 1;
23589                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23590                        prev_highlight.range.end = range.end;
23591                    }
23592                    merged = true;
23593                    prev_highlight.index = index;
23594                    prev_highlight.color = color;
23595                    prev_highlight.options = options;
23596                }
23597            }
23598
23599            if !merged {
23600                row_highlights.insert(
23601                    ix,
23602                    RowHighlight {
23603                        range,
23604                        index,
23605                        color,
23606                        options,
23607                        type_id: TypeId::of::<T>(),
23608                    },
23609                );
23610            }
23611
23612            // If any of the following highlights intersect with this one, merge them.
23613            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23614                let highlight = &row_highlights[ix];
23615                if next_highlight
23616                    .range
23617                    .start
23618                    .cmp(&highlight.range.end, &snapshot)
23619                    .is_le()
23620                {
23621                    if next_highlight
23622                        .range
23623                        .end
23624                        .cmp(&highlight.range.end, &snapshot)
23625                        .is_gt()
23626                    {
23627                        row_highlights[ix].range.end = next_highlight.range.end;
23628                    }
23629                    row_highlights.remove(ix + 1);
23630                } else {
23631                    break;
23632                }
23633            }
23634        }
23635    }
23636
23637    /// Remove any highlighted row ranges of the given type that intersect the
23638    /// given ranges.
23639    pub fn remove_highlighted_rows<T: 'static>(
23640        &mut self,
23641        ranges_to_remove: Vec<Range<Anchor>>,
23642        cx: &mut Context<Self>,
23643    ) {
23644        let snapshot = self.buffer().read(cx).snapshot(cx);
23645        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23646        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23647        row_highlights.retain(|highlight| {
23648            while let Some(range_to_remove) = ranges_to_remove.peek() {
23649                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23650                    Ordering::Less | Ordering::Equal => {
23651                        ranges_to_remove.next();
23652                    }
23653                    Ordering::Greater => {
23654                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23655                            Ordering::Less | Ordering::Equal => {
23656                                return false;
23657                            }
23658                            Ordering::Greater => break,
23659                        }
23660                    }
23661                }
23662            }
23663
23664            true
23665        })
23666    }
23667
23668    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23669    pub fn clear_row_highlights<T: 'static>(&mut self) {
23670        self.highlighted_rows.remove(&TypeId::of::<T>());
23671    }
23672
23673    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23674    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23675        self.highlighted_rows
23676            .get(&TypeId::of::<T>())
23677            .map_or(&[] as &[_], |vec| vec.as_slice())
23678            .iter()
23679            .map(|highlight| (highlight.range.clone(), highlight.color))
23680    }
23681
23682    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23683    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23684    /// Allows to ignore certain kinds of highlights.
23685    pub fn highlighted_display_rows(
23686        &self,
23687        window: &mut Window,
23688        cx: &mut App,
23689    ) -> BTreeMap<DisplayRow, LineHighlight> {
23690        let snapshot = self.snapshot(window, cx);
23691        let mut used_highlight_orders = HashMap::default();
23692        self.highlighted_rows
23693            .iter()
23694            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23695            .fold(
23696                BTreeMap::<DisplayRow, LineHighlight>::new(),
23697                |mut unique_rows, highlight| {
23698                    let start = highlight.range.start.to_display_point(&snapshot);
23699                    let end = highlight.range.end.to_display_point(&snapshot);
23700                    let start_row = start.row().0;
23701                    let end_row = if !highlight.range.end.is_max() && end.column() == 0 {
23702                        end.row().0.saturating_sub(1)
23703                    } else {
23704                        end.row().0
23705                    };
23706                    for row in start_row..=end_row {
23707                        let used_index =
23708                            used_highlight_orders.entry(row).or_insert(highlight.index);
23709                        if highlight.index >= *used_index {
23710                            *used_index = highlight.index;
23711                            unique_rows.insert(
23712                                DisplayRow(row),
23713                                LineHighlight {
23714                                    include_gutter: highlight.options.include_gutter,
23715                                    border: None,
23716                                    background: highlight.color.into(),
23717                                    type_id: Some(highlight.type_id),
23718                                },
23719                            );
23720                        }
23721                    }
23722                    unique_rows
23723                },
23724            )
23725    }
23726
23727    pub fn highlighted_display_row_for_autoscroll(
23728        &self,
23729        snapshot: &DisplaySnapshot,
23730    ) -> Option<DisplayRow> {
23731        self.highlighted_rows
23732            .values()
23733            .flat_map(|highlighted_rows| highlighted_rows.iter())
23734            .filter_map(|highlight| {
23735                if highlight.options.autoscroll {
23736                    Some(highlight.range.start.to_display_point(snapshot).row())
23737                } else {
23738                    None
23739                }
23740            })
23741            .min()
23742    }
23743
23744    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23745        self.highlight_background(
23746            HighlightKey::SearchWithinRange,
23747            ranges,
23748            |_, colors| colors.colors().editor_document_highlight_read_background,
23749            cx,
23750        )
23751    }
23752
23753    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23754        self.breadcrumb_header = Some(new_header);
23755    }
23756
23757    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23758        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23759    }
23760
23761    pub fn highlight_background(
23762        &mut self,
23763        key: HighlightKey,
23764        ranges: &[Range<Anchor>],
23765        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23766        cx: &mut Context<Self>,
23767    ) {
23768        self.background_highlights
23769            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23770        self.scrollbar_marker_state.dirty = true;
23771        cx.notify();
23772    }
23773
23774    pub fn clear_background_highlights(
23775        &mut self,
23776        key: HighlightKey,
23777        cx: &mut Context<Self>,
23778    ) -> Option<BackgroundHighlight> {
23779        let text_highlights = self.background_highlights.remove(&key)?;
23780        if !text_highlights.1.is_empty() {
23781            self.scrollbar_marker_state.dirty = true;
23782            cx.notify();
23783        }
23784        Some(text_highlights)
23785    }
23786
23787    pub fn highlight_gutter<T: 'static>(
23788        &mut self,
23789        ranges: impl Into<Vec<Range<Anchor>>>,
23790        color_fetcher: fn(&App) -> Hsla,
23791        cx: &mut Context<Self>,
23792    ) {
23793        self.gutter_highlights
23794            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23795        cx.notify();
23796    }
23797
23798    pub fn clear_gutter_highlights<T: 'static>(
23799        &mut self,
23800        cx: &mut Context<Self>,
23801    ) -> Option<GutterHighlight> {
23802        cx.notify();
23803        self.gutter_highlights.remove(&TypeId::of::<T>())
23804    }
23805
23806    pub fn insert_gutter_highlight<T: 'static>(
23807        &mut self,
23808        range: Range<Anchor>,
23809        color_fetcher: fn(&App) -> Hsla,
23810        cx: &mut Context<Self>,
23811    ) {
23812        let snapshot = self.buffer().read(cx).snapshot(cx);
23813        let mut highlights = self
23814            .gutter_highlights
23815            .remove(&TypeId::of::<T>())
23816            .map(|(_, highlights)| highlights)
23817            .unwrap_or_default();
23818        let ix = highlights.binary_search_by(|highlight| {
23819            Ordering::Equal
23820                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23821                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23822        });
23823        if let Err(ix) = ix {
23824            highlights.insert(ix, range);
23825        }
23826        self.gutter_highlights
23827            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23828    }
23829
23830    pub fn remove_gutter_highlights<T: 'static>(
23831        &mut self,
23832        ranges_to_remove: Vec<Range<Anchor>>,
23833        cx: &mut Context<Self>,
23834    ) {
23835        let snapshot = self.buffer().read(cx).snapshot(cx);
23836        let Some((color_fetcher, mut gutter_highlights)) =
23837            self.gutter_highlights.remove(&TypeId::of::<T>())
23838        else {
23839            return;
23840        };
23841        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23842        gutter_highlights.retain(|highlight| {
23843            while let Some(range_to_remove) = ranges_to_remove.peek() {
23844                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23845                    Ordering::Less | Ordering::Equal => {
23846                        ranges_to_remove.next();
23847                    }
23848                    Ordering::Greater => {
23849                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23850                            Ordering::Less | Ordering::Equal => {
23851                                return false;
23852                            }
23853                            Ordering::Greater => break,
23854                        }
23855                    }
23856                }
23857            }
23858
23859            true
23860        });
23861        self.gutter_highlights
23862            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23863    }
23864
23865    #[cfg(any(test, feature = "test-support"))]
23866    pub fn all_text_highlights(
23867        &self,
23868        window: &mut Window,
23869        cx: &mut Context<Self>,
23870    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23871        let snapshot = self.snapshot(window, cx);
23872        self.display_map.update(cx, |display_map, _| {
23873            display_map
23874                .all_text_highlights()
23875                .map(|(_, highlight)| {
23876                    let (style, ranges) = highlight.as_ref();
23877                    (
23878                        *style,
23879                        ranges
23880                            .iter()
23881                            .map(|range| range.clone().to_display_points(&snapshot))
23882                            .collect(),
23883                    )
23884                })
23885                .collect()
23886        })
23887    }
23888
23889    #[cfg(any(test, feature = "test-support"))]
23890    pub fn all_text_background_highlights(
23891        &self,
23892        window: &mut Window,
23893        cx: &mut Context<Self>,
23894    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23895        let snapshot = self.snapshot(window, cx);
23896        let buffer = &snapshot.buffer_snapshot();
23897        let start = buffer.anchor_before(MultiBufferOffset(0));
23898        let end = buffer.anchor_after(buffer.len());
23899        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23900    }
23901
23902    #[cfg(any(test, feature = "test-support"))]
23903    pub fn sorted_background_highlights_in_range(
23904        &self,
23905        search_range: Range<Anchor>,
23906        display_snapshot: &DisplaySnapshot,
23907        theme: &Theme,
23908    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23909        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23910        res.sort_by(|a, b| {
23911            a.0.start
23912                .cmp(&b.0.start)
23913                .then_with(|| a.0.end.cmp(&b.0.end))
23914                .then_with(|| a.1.cmp(&b.1))
23915        });
23916        res
23917    }
23918
23919    #[cfg(any(test, feature = "test-support"))]
23920    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23921        let snapshot = self.buffer().read(cx).snapshot(cx);
23922
23923        let highlights = self
23924            .background_highlights
23925            .get(&HighlightKey::BufferSearchHighlights);
23926
23927        if let Some((_color, ranges)) = highlights {
23928            ranges
23929                .iter()
23930                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23931                .collect_vec()
23932        } else {
23933            vec![]
23934        }
23935    }
23936
23937    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23938        self.background_highlights
23939            .get(&key)
23940            .is_some_and(|(_, highlights)| !highlights.is_empty())
23941    }
23942
23943    /// Returns all background highlights for a given range.
23944    ///
23945    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23946    pub fn background_highlights_in_range(
23947        &self,
23948        search_range: Range<Anchor>,
23949        display_snapshot: &DisplaySnapshot,
23950        theme: &Theme,
23951    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23952        let mut results = Vec::new();
23953        for (color_fetcher, ranges) in self.background_highlights.values() {
23954            let start_ix = match ranges.binary_search_by(|probe| {
23955                let cmp = probe
23956                    .end
23957                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23958                if cmp.is_gt() {
23959                    Ordering::Greater
23960                } else {
23961                    Ordering::Less
23962                }
23963            }) {
23964                Ok(i) | Err(i) => i,
23965            };
23966            for (index, range) in ranges[start_ix..].iter().enumerate() {
23967                if range
23968                    .start
23969                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23970                    .is_ge()
23971                {
23972                    break;
23973                }
23974
23975                let color = color_fetcher(&(start_ix + index), theme);
23976                let start = range.start.to_display_point(display_snapshot);
23977                let end = range.end.to_display_point(display_snapshot);
23978                results.push((start..end, color))
23979            }
23980        }
23981        results
23982    }
23983
23984    pub fn gutter_highlights_in_range(
23985        &self,
23986        search_range: Range<Anchor>,
23987        display_snapshot: &DisplaySnapshot,
23988        cx: &App,
23989    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23990        let mut results = Vec::new();
23991        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23992            let color = color_fetcher(cx);
23993            let start_ix = match ranges.binary_search_by(|probe| {
23994                let cmp = probe
23995                    .end
23996                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23997                if cmp.is_gt() {
23998                    Ordering::Greater
23999                } else {
24000                    Ordering::Less
24001                }
24002            }) {
24003                Ok(i) | Err(i) => i,
24004            };
24005            for range in &ranges[start_ix..] {
24006                if range
24007                    .start
24008                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24009                    .is_ge()
24010                {
24011                    break;
24012                }
24013
24014                let start = range.start.to_display_point(display_snapshot);
24015                let end = range.end.to_display_point(display_snapshot);
24016                results.push((start..end, color))
24017            }
24018        }
24019        results
24020    }
24021
24022    /// Get the text ranges corresponding to the redaction query
24023    pub fn redacted_ranges(
24024        &self,
24025        search_range: Range<Anchor>,
24026        display_snapshot: &DisplaySnapshot,
24027        cx: &App,
24028    ) -> Vec<Range<DisplayPoint>> {
24029        display_snapshot
24030            .buffer_snapshot()
24031            .redacted_ranges(search_range, |file| {
24032                if let Some(file) = file {
24033                    file.is_private()
24034                        && EditorSettings::get(
24035                            Some(SettingsLocation {
24036                                worktree_id: file.worktree_id(cx),
24037                                path: file.path().as_ref(),
24038                            }),
24039                            cx,
24040                        )
24041                        .redact_private_values
24042                } else {
24043                    false
24044                }
24045            })
24046            .map(|range| {
24047                range.start.to_display_point(display_snapshot)
24048                    ..range.end.to_display_point(display_snapshot)
24049            })
24050            .collect()
24051    }
24052
24053    pub fn highlight_text_key(
24054        &mut self,
24055        key: HighlightKey,
24056        ranges: Vec<Range<Anchor>>,
24057        style: HighlightStyle,
24058        merge: bool,
24059        cx: &mut Context<Self>,
24060    ) {
24061        self.display_map.update(cx, |map, cx| {
24062            map.highlight_text(key, ranges, style, merge, cx);
24063        });
24064        cx.notify();
24065    }
24066
24067    pub fn highlight_text(
24068        &mut self,
24069        key: HighlightKey,
24070        ranges: Vec<Range<Anchor>>,
24071        style: HighlightStyle,
24072        cx: &mut Context<Self>,
24073    ) {
24074        self.display_map.update(cx, |map, cx| {
24075            map.highlight_text(key, ranges, style, false, cx)
24076        });
24077        cx.notify();
24078    }
24079
24080    pub fn text_highlights<'a>(
24081        &'a self,
24082        key: HighlightKey,
24083        cx: &'a App,
24084    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24085        self.display_map.read(cx).text_highlights(key)
24086    }
24087
24088    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24089        let cleared = self
24090            .display_map
24091            .update(cx, |map, _| map.clear_highlights(key));
24092        if cleared {
24093            cx.notify();
24094        }
24095    }
24096
24097    pub fn clear_highlights_with(
24098        &mut self,
24099        f: &mut dyn FnMut(&HighlightKey) -> bool,
24100        cx: &mut Context<Self>,
24101    ) {
24102        let cleared = self
24103            .display_map
24104            .update(cx, |map, _| map.clear_highlights_with(f));
24105        if cleared {
24106            cx.notify();
24107        }
24108    }
24109
24110    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24111        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24112            && self.focus_handle.is_focused(window)
24113    }
24114
24115    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24116        self.show_cursor_when_unfocused = is_enabled;
24117        cx.notify();
24118    }
24119
24120    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24121        cx.notify();
24122    }
24123
24124    fn on_debug_session_event(
24125        &mut self,
24126        _session: Entity<Session>,
24127        event: &SessionEvent,
24128        cx: &mut Context<Self>,
24129    ) {
24130        if let SessionEvent::InvalidateInlineValue = event {
24131            self.refresh_inline_values(cx);
24132        }
24133    }
24134
24135    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24136        let Some(semantics) = self.semantics_provider.clone() else {
24137            return;
24138        };
24139
24140        if !self.inline_value_cache.enabled {
24141            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24142            self.splice_inlays(&inlays, Vec::new(), cx);
24143            return;
24144        }
24145
24146        let current_execution_position = self
24147            .highlighted_rows
24148            .get(&TypeId::of::<ActiveDebugLine>())
24149            .and_then(|lines| lines.last().map(|line| line.range.end));
24150
24151        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24152            let inline_values = editor
24153                .update(cx, |editor, cx| {
24154                    let Some(current_execution_position) = current_execution_position else {
24155                        return Some(Task::ready(Ok(Vec::new())));
24156                    };
24157
24158                    let (buffer, buffer_anchor) =
24159                        editor.buffer.read_with(cx, |multibuffer, cx| {
24160                            let multibuffer_snapshot = multibuffer.snapshot(cx);
24161                            let (buffer_anchor, _) = multibuffer_snapshot
24162                                .anchor_to_buffer_anchor(current_execution_position)?;
24163                            let buffer = multibuffer.buffer(buffer_anchor.buffer_id)?;
24164                            Some((buffer, buffer_anchor))
24165                        })?;
24166
24167                    let range = buffer.read(cx).anchor_before(0)..buffer_anchor;
24168
24169                    semantics.inline_values(buffer, range, cx)
24170                })
24171                .ok()
24172                .flatten()?
24173                .await
24174                .context("refreshing debugger inlays")
24175                .log_err()?;
24176
24177            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24178
24179            for (buffer_id, inline_value) in inline_values
24180                .into_iter()
24181                .map(|hint| (hint.position.buffer_id, hint))
24182            {
24183                buffer_inline_values
24184                    .entry(buffer_id)
24185                    .or_default()
24186                    .push(inline_value);
24187            }
24188
24189            editor
24190                .update(cx, |editor, cx| {
24191                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24192                    let mut new_inlays = Vec::default();
24193
24194                    for (_buffer_id, inline_values) in buffer_inline_values {
24195                        for hint in inline_values {
24196                            let Some(anchor) = snapshot.anchor_in_excerpt(hint.position) else {
24197                                continue;
24198                            };
24199                            let inlay = Inlay::debugger(
24200                                post_inc(&mut editor.next_inlay_id),
24201                                anchor,
24202                                hint.text(),
24203                            );
24204                            if !inlay.text().chars().contains(&'\n') {
24205                                new_inlays.push(inlay);
24206                            }
24207                        }
24208                    }
24209
24210                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24211                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24212
24213                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24214                })
24215                .ok()?;
24216            Some(())
24217        });
24218    }
24219
24220    fn on_buffer_event(
24221        &mut self,
24222        multibuffer: &Entity<MultiBuffer>,
24223        event: &multi_buffer::Event,
24224        window: &mut Window,
24225        cx: &mut Context<Self>,
24226    ) {
24227        match event {
24228            multi_buffer::Event::Edited {
24229                edited_buffer,
24230                is_local,
24231            } => {
24232                self.scrollbar_marker_state.dirty = true;
24233                self.active_indent_guides_state.dirty = true;
24234                self.refresh_active_diagnostics(cx);
24235                self.refresh_code_actions(window, cx);
24236                self.refresh_single_line_folds(window, cx);
24237                let snapshot = self.snapshot(window, cx);
24238                self.refresh_matching_bracket_highlights(&snapshot, cx);
24239                self.refresh_outline_symbols_at_cursor(cx);
24240                self.refresh_sticky_headers(&snapshot, cx);
24241                if *is_local && self.has_active_edit_prediction() {
24242                    self.update_visible_edit_prediction(window, cx);
24243                }
24244
24245                // Clean up orphaned review comments after edits
24246                self.cleanup_orphaned_review_comments(cx);
24247
24248                if let Some(buffer) = edited_buffer {
24249                    if buffer.read(cx).file().is_none() {
24250                        cx.emit(EditorEvent::TitleChanged);
24251                    }
24252
24253                    if self.project.is_some() {
24254                        let buffer_id = buffer.read(cx).remote_id();
24255                        self.register_buffer(buffer_id, cx);
24256                        self.update_lsp_data(Some(buffer_id), window, cx);
24257                        self.refresh_inlay_hints(
24258                            InlayHintRefreshReason::BufferEdited(buffer_id),
24259                            cx,
24260                        );
24261                    }
24262                }
24263
24264                cx.emit(EditorEvent::BufferEdited);
24265                cx.emit(SearchEvent::MatchesInvalidated);
24266
24267                let Some(project) = &self.project else { return };
24268                let (telemetry, is_via_ssh) = {
24269                    let project = project.read(cx);
24270                    let telemetry = project.client().telemetry().clone();
24271                    let is_via_ssh = project.is_via_remote_server();
24272                    (telemetry, is_via_ssh)
24273                };
24274                telemetry.log_edit_event("editor", is_via_ssh);
24275            }
24276            multi_buffer::Event::BufferRangesUpdated {
24277                buffer,
24278                ranges,
24279                path_key,
24280            } => {
24281                self.refresh_document_highlights(cx);
24282                let buffer_id = buffer.read(cx).remote_id();
24283                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24284                    && let Some(project) = &self.project
24285                {
24286                    update_uncommitted_diff_for_buffer(
24287                        cx.entity(),
24288                        project,
24289                        [buffer.clone()],
24290                        self.buffer.clone(),
24291                        cx,
24292                    )
24293                    .detach();
24294                }
24295                self.register_visible_buffers(cx);
24296                self.update_lsp_data(Some(buffer_id), window, cx);
24297                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24298                self.refresh_runnables(None, window, cx);
24299                self.bracket_fetched_tree_sitter_chunks
24300                    .retain(|range, _| range.start.buffer_id != buffer_id);
24301                self.colorize_brackets(false, cx);
24302                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24303                self.semantic_token_state.invalidate_buffer(&buffer_id);
24304                cx.emit(EditorEvent::BufferRangesUpdated {
24305                    buffer: buffer.clone(),
24306                    ranges: ranges.clone(),
24307                    path_key: path_key.clone(),
24308                });
24309            }
24310            multi_buffer::Event::BuffersRemoved { removed_buffer_ids } => {
24311                if let Some(inlay_hints) = &mut self.inlay_hints {
24312                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24313                }
24314                self.refresh_inlay_hints(
24315                    InlayHintRefreshReason::BuffersRemoved(removed_buffer_ids.clone()),
24316                    cx,
24317                );
24318                for buffer_id in removed_buffer_ids {
24319                    self.registered_buffers.remove(buffer_id);
24320                    self.clear_runnables(Some(*buffer_id));
24321                    self.semantic_token_state.invalidate_buffer(buffer_id);
24322                    self.display_map.update(cx, |display_map, cx| {
24323                        display_map.invalidate_semantic_highlights(*buffer_id);
24324                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24325                    });
24326                }
24327
24328                self.display_map.update(cx, |display_map, cx| {
24329                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24330                });
24331
24332                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24333                cx.emit(EditorEvent::BuffersRemoved {
24334                    removed_buffer_ids: removed_buffer_ids.clone(),
24335                });
24336            }
24337            multi_buffer::Event::BuffersEdited { buffer_ids } => {
24338                self.display_map.update(cx, |map, cx| {
24339                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24340                });
24341                cx.emit(EditorEvent::BuffersEdited {
24342                    buffer_ids: buffer_ids.clone(),
24343                });
24344            }
24345            multi_buffer::Event::Reparsed(buffer_id) => {
24346                self.refresh_runnables(Some(*buffer_id), window, cx);
24347                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24348                self.colorize_brackets(true, cx);
24349                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24350
24351                cx.emit(EditorEvent::Reparsed(*buffer_id));
24352            }
24353            multi_buffer::Event::DiffHunksToggled => {
24354                self.refresh_runnables(None, window, cx);
24355            }
24356            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24357                if !is_fresh_language {
24358                    self.registered_buffers.remove(&buffer_id);
24359                }
24360                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24361                cx.emit(EditorEvent::Reparsed(*buffer_id));
24362                self.update_edit_prediction_settings(cx);
24363                cx.notify();
24364            }
24365            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24366            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24367            multi_buffer::Event::FileHandleChanged
24368            | multi_buffer::Event::Reloaded
24369            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24370            multi_buffer::Event::DiagnosticsUpdated => {
24371                self.update_diagnostics_state(window, cx);
24372            }
24373            _ => {}
24374        };
24375    }
24376
24377    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24378        if !self.diagnostics_enabled() {
24379            return;
24380        }
24381        self.refresh_active_diagnostics(cx);
24382        self.refresh_inline_diagnostics(true, window, cx);
24383        self.scrollbar_marker_state.dirty = true;
24384        cx.notify();
24385    }
24386
24387    pub fn start_temporary_diff_override(&mut self) {
24388        self.load_diff_task.take();
24389        self.temporary_diff_override = true;
24390    }
24391
24392    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24393        self.temporary_diff_override = false;
24394        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24395        self.buffer.update(cx, |buffer, cx| {
24396            buffer.set_all_diff_hunks_collapsed(cx);
24397        });
24398
24399        if let Some(project) = self.project.clone() {
24400            self.load_diff_task = Some(
24401                update_uncommitted_diff_for_buffer(
24402                    cx.entity(),
24403                    &project,
24404                    self.buffer.read(cx).all_buffers(),
24405                    self.buffer.clone(),
24406                    cx,
24407                )
24408                .shared(),
24409            );
24410        }
24411    }
24412
24413    fn on_display_map_changed(
24414        &mut self,
24415        _: Entity<DisplayMap>,
24416        _: &mut Window,
24417        cx: &mut Context<Self>,
24418    ) {
24419        cx.notify();
24420    }
24421
24422    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24423        if !self.mode.is_full() {
24424            return None;
24425        }
24426
24427        let theme_settings = theme_settings::ThemeSettings::get_global(cx);
24428        let theme = cx.theme();
24429        let accent_colors = theme.accents().clone();
24430
24431        let accent_overrides = theme_settings
24432            .theme_overrides
24433            .get(theme.name.as_ref())
24434            .map(|theme_style| &theme_style.accents)
24435            .into_iter()
24436            .flatten()
24437            .chain(
24438                theme_settings
24439                    .experimental_theme_overrides
24440                    .as_ref()
24441                    .map(|overrides| &overrides.accents)
24442                    .into_iter()
24443                    .flatten(),
24444            )
24445            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24446            .collect();
24447
24448        Some(AccentData {
24449            colors: accent_colors,
24450            overrides: accent_overrides,
24451        })
24452    }
24453
24454    fn fetch_applicable_language_settings(
24455        &self,
24456        cx: &App,
24457    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24458        if !self.mode.is_full() {
24459            return HashMap::default();
24460        }
24461
24462        self.buffer().read(cx).all_buffers().into_iter().fold(
24463            HashMap::default(),
24464            |mut acc, buffer| {
24465                let buffer = buffer.read(cx);
24466                let language = buffer.language().map(|language| language.name());
24467                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24468                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24469                }
24470                acc
24471            },
24472        )
24473    }
24474
24475    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24476        let new_language_settings = self.fetch_applicable_language_settings(cx);
24477        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24478        self.applicable_language_settings = new_language_settings;
24479
24480        let new_accents = self.fetch_accent_data(cx);
24481        let accents_changed = new_accents != self.accent_data;
24482        self.accent_data = new_accents;
24483
24484        if self.diagnostics_enabled() {
24485            let new_severity = EditorSettings::get_global(cx)
24486                .diagnostics_max_severity
24487                .unwrap_or(DiagnosticSeverity::Hint);
24488            self.set_max_diagnostics_severity(new_severity, cx);
24489        }
24490        self.refresh_runnables(None, window, cx);
24491        self.update_edit_prediction_settings(cx);
24492        self.refresh_edit_prediction(true, false, window, cx);
24493        self.refresh_inline_values(cx);
24494
24495        let old_cursor_shape = self.cursor_shape;
24496        let old_show_breadcrumbs = self.show_breadcrumbs;
24497
24498        {
24499            let editor_settings = EditorSettings::get_global(cx);
24500            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24501            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24502            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24503            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24504        }
24505
24506        if old_cursor_shape != self.cursor_shape {
24507            cx.emit(EditorEvent::CursorShapeChanged);
24508        }
24509
24510        if old_show_breadcrumbs != self.show_breadcrumbs {
24511            cx.emit(EditorEvent::BreadcrumbsChanged);
24512        }
24513
24514        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24515            let project_settings = ProjectSettings::get_global(cx);
24516            (
24517                project_settings.session.restore_unsaved_buffers,
24518                project_settings.diagnostics.inline.enabled,
24519                project_settings.git.inline_blame.enabled,
24520            )
24521        };
24522        self.buffer_serialization = self
24523            .should_serialize_buffer()
24524            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24525
24526        if self.mode.is_full() {
24527            if self.show_inline_diagnostics != show_inline_diagnostics {
24528                self.show_inline_diagnostics = show_inline_diagnostics;
24529                self.refresh_inline_diagnostics(false, window, cx);
24530            }
24531
24532            if self.git_blame_inline_enabled != inline_blame_enabled {
24533                self.toggle_git_blame_inline_internal(false, window, cx);
24534            }
24535
24536            let minimap_settings = EditorSettings::get_global(cx).minimap;
24537            if self.minimap_visibility != MinimapVisibility::Disabled {
24538                if self.minimap_visibility.settings_visibility()
24539                    != minimap_settings.minimap_enabled()
24540                {
24541                    self.set_minimap_visibility(
24542                        MinimapVisibility::for_mode(self.mode(), cx),
24543                        window,
24544                        cx,
24545                    );
24546                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24547                    minimap_entity.update(cx, |minimap_editor, cx| {
24548                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24549                    })
24550                }
24551            }
24552
24553            if language_settings_changed || accents_changed {
24554                self.colorize_brackets(true, cx);
24555            }
24556
24557            if language_settings_changed {
24558                self.clear_disabled_lsp_folding_ranges(window, cx);
24559                self.refresh_document_symbols(None, cx);
24560            }
24561
24562            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24563                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24564            }) {
24565                if !inlay_splice.is_empty() {
24566                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24567                }
24568                self.refresh_document_colors(None, window, cx);
24569            }
24570
24571            self.refresh_inlay_hints(
24572                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24573                    self.selections.newest_anchor().head(),
24574                    &self.buffer.read(cx).snapshot(cx),
24575                    cx,
24576                )),
24577                cx,
24578            );
24579
24580            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24581                .global_lsp_settings
24582                .semantic_token_rules
24583                .clone();
24584            let semantic_token_rules_changed = self
24585                .semantic_token_state
24586                .update_rules(new_semantic_token_rules);
24587            if language_settings_changed || semantic_token_rules_changed {
24588                self.invalidate_semantic_tokens(None);
24589                self.refresh_semantic_tokens(None, None, cx);
24590            }
24591        }
24592
24593        cx.notify();
24594    }
24595
24596    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24597        if !self.mode.is_full() {
24598            return;
24599        }
24600
24601        let new_accents = self.fetch_accent_data(cx);
24602        if new_accents != self.accent_data {
24603            self.accent_data = new_accents;
24604            self.colorize_brackets(true, cx);
24605        }
24606
24607        self.invalidate_semantic_tokens(None);
24608        self.refresh_semantic_tokens(None, None, cx);
24609    }
24610
24611    pub fn set_searchable(&mut self, searchable: bool) {
24612        self.searchable = searchable;
24613    }
24614
24615    pub fn searchable(&self) -> bool {
24616        self.searchable
24617    }
24618
24619    pub fn open_excerpts_in_split(
24620        &mut self,
24621        _: &OpenExcerptsSplit,
24622        window: &mut Window,
24623        cx: &mut Context<Self>,
24624    ) {
24625        self.open_excerpts_common(None, true, window, cx)
24626    }
24627
24628    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24629        self.open_excerpts_common(None, false, window, cx)
24630    }
24631
24632    pub(crate) fn open_excerpts_common(
24633        &mut self,
24634        jump_data: Option<JumpData>,
24635        split: bool,
24636        window: &mut Window,
24637        cx: &mut Context<Self>,
24638    ) {
24639        if self.buffer.read(cx).is_singleton() {
24640            cx.propagate();
24641            return;
24642        }
24643
24644        let mut new_selections_by_buffer = HashMap::default();
24645        match &jump_data {
24646            Some(JumpData::MultiBufferPoint {
24647                anchor,
24648                position,
24649                line_offset_from_top,
24650            }) => {
24651                if let Some(buffer) = self.buffer.read(cx).buffer(anchor.buffer_id) {
24652                    let buffer_snapshot = buffer.read(cx).snapshot();
24653                    let jump_to_point = if buffer_snapshot.can_resolve(&anchor) {
24654                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24655                    } else {
24656                        buffer_snapshot.clip_point(*position, Bias::Left)
24657                    };
24658                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24659                    new_selections_by_buffer.insert(
24660                        buffer,
24661                        (
24662                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24663                            Some(*line_offset_from_top),
24664                        ),
24665                    );
24666                }
24667            }
24668            Some(JumpData::MultiBufferRow {
24669                row,
24670                line_offset_from_top,
24671            }) => {
24672                let point = MultiBufferPoint::new(row.0, 0);
24673                if let Some((buffer, buffer_point)) =
24674                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24675                {
24676                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24677                    new_selections_by_buffer
24678                        .entry(buffer)
24679                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24680                        .0
24681                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24682                }
24683            }
24684            None => {
24685                let selections = self
24686                    .selections
24687                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24688                let multi_buffer = self.buffer.read(cx);
24689                let multi_buffer_snapshot = multi_buffer.snapshot(cx);
24690                for selection in selections {
24691                    for (snapshot, range, anchor) in multi_buffer_snapshot
24692                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24693                    {
24694                        if let Some((text_anchor, _)) = anchor.and_then(|anchor| {
24695                            multi_buffer_snapshot.anchor_to_buffer_anchor(anchor)
24696                        }) {
24697                            let Some(buffer_handle) = multi_buffer.buffer(text_anchor.buffer_id)
24698                            else {
24699                                continue;
24700                            };
24701                            let offset = text::ToOffset::to_offset(
24702                                &text_anchor,
24703                                &buffer_handle.read(cx).snapshot(),
24704                            );
24705                            let range = BufferOffset(offset)..BufferOffset(offset);
24706                            new_selections_by_buffer
24707                                .entry(buffer_handle)
24708                                .or_insert((Vec::new(), None))
24709                                .0
24710                                .push(range)
24711                        } else {
24712                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24713                            else {
24714                                continue;
24715                            };
24716                            new_selections_by_buffer
24717                                .entry(buffer_handle)
24718                                .or_insert((Vec::new(), None))
24719                                .0
24720                                .push(range)
24721                        }
24722                    }
24723                }
24724            }
24725        }
24726
24727        if self.delegate_open_excerpts {
24728            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24729                .into_iter()
24730                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24731                .collect();
24732            if !selections_by_buffer.is_empty() {
24733                cx.emit(EditorEvent::OpenExcerptsRequested {
24734                    selections_by_buffer,
24735                    split,
24736                });
24737            }
24738            return;
24739        }
24740
24741        let Some(workspace) = self.workspace() else {
24742            cx.propagate();
24743            return;
24744        };
24745
24746        new_selections_by_buffer
24747            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24748
24749        if new_selections_by_buffer.is_empty() {
24750            return;
24751        }
24752
24753        Self::open_buffers_in_workspace(
24754            workspace.downgrade(),
24755            new_selections_by_buffer,
24756            split,
24757            window,
24758            cx,
24759        );
24760    }
24761
24762    pub(crate) fn open_buffers_in_workspace(
24763        workspace: WeakEntity<Workspace>,
24764        new_selections_by_buffer: HashMap<
24765            Entity<language::Buffer>,
24766            (Vec<Range<BufferOffset>>, Option<u32>),
24767        >,
24768        split: bool,
24769        window: &mut Window,
24770        cx: &mut App,
24771    ) {
24772        // We defer the pane interaction because we ourselves are a workspace item
24773        // and activating a new item causes the pane to call a method on us reentrantly,
24774        // which panics if we're on the stack.
24775        window.defer(cx, move |window, cx| {
24776            workspace
24777                .update(cx, |workspace, cx| {
24778                    let pane = if split {
24779                        workspace.adjacent_pane(window, cx)
24780                    } else {
24781                        workspace.active_pane().clone()
24782                    };
24783
24784                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24785                        let buffer_read = buffer.read(cx);
24786                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24787                            (true, project::File::from_dyn(Some(file)).is_some())
24788                        } else {
24789                            (false, false)
24790                        };
24791
24792                        // If project file is none workspace.open_project_item will fail to open the excerpt
24793                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24794                        // so we check if there's a tab match in that case first
24795                        let editor = (!has_file || !is_project_file)
24796                            .then(|| {
24797                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24798                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24799                                // Instead, we try to activate the existing editor in the pane first.
24800                                let (editor, pane_item_index, pane_item_id) =
24801                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24802                                        let editor = item.downcast::<Editor>()?;
24803                                        let singleton_buffer =
24804                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24805                                        if singleton_buffer == buffer {
24806                                            Some((editor, i, item.item_id()))
24807                                        } else {
24808                                            None
24809                                        }
24810                                    })?;
24811                                pane.update(cx, |pane, cx| {
24812                                    pane.activate_item(pane_item_index, true, true, window, cx);
24813                                    if !PreviewTabsSettings::get_global(cx)
24814                                        .enable_preview_from_multibuffer
24815                                    {
24816                                        pane.unpreview_item_if_preview(pane_item_id);
24817                                    }
24818                                });
24819                                Some(editor)
24820                            })
24821                            .flatten()
24822                            .unwrap_or_else(|| {
24823                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24824                                    .enable_keep_preview_on_code_navigation;
24825                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24826                                    .enable_preview_from_multibuffer;
24827                                workspace.open_project_item::<Self>(
24828                                    pane.clone(),
24829                                    buffer,
24830                                    true,
24831                                    true,
24832                                    keep_old_preview,
24833                                    allow_new_preview,
24834                                    window,
24835                                    cx,
24836                                )
24837                            });
24838
24839                        editor.update(cx, |editor, cx| {
24840                            if has_file && !is_project_file {
24841                                editor.set_read_only(true);
24842                            }
24843                            let autoscroll = match scroll_offset {
24844                                Some(scroll_offset) => {
24845                                    Autoscroll::top_relative(scroll_offset as usize)
24846                                }
24847                                None => Autoscroll::newest(),
24848                            };
24849                            let nav_history = editor.nav_history.take();
24850                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24851                            let Some(buffer_snapshot) = multibuffer_snapshot.as_singleton() else {
24852                                return;
24853                            };
24854                            editor.change_selections(
24855                                SelectionEffects::scroll(autoscroll),
24856                                window,
24857                                cx,
24858                                |s| {
24859                                    s.select_ranges(ranges.into_iter().map(|range| {
24860                                        let range = buffer_snapshot.anchor_before(range.start)
24861                                            ..buffer_snapshot.anchor_after(range.end);
24862                                        multibuffer_snapshot
24863                                            .buffer_anchor_range_to_anchor_range(range)
24864                                            .unwrap()
24865                                    }));
24866                                },
24867                            );
24868                            editor.nav_history = nav_history;
24869                        });
24870                    }
24871                })
24872                .ok();
24873        });
24874    }
24875
24876    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24877        let snapshot = self.buffer.read(cx).read(cx);
24878        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24879        Some(
24880            ranges
24881                .iter()
24882                .map(move |range| {
24883                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24884                })
24885                .collect(),
24886        )
24887    }
24888
24889    fn selection_replacement_ranges(
24890        &self,
24891        range: Range<MultiBufferOffsetUtf16>,
24892        cx: &mut App,
24893    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24894        let selections = self
24895            .selections
24896            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24897        let newest_selection = selections
24898            .iter()
24899            .max_by_key(|selection| selection.id)
24900            .unwrap();
24901        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24902        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24903        let snapshot = self.buffer.read(cx).read(cx);
24904        selections
24905            .into_iter()
24906            .map(|mut selection| {
24907                selection.start.0.0 =
24908                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24909                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24910                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24911                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24912            })
24913            .collect()
24914    }
24915
24916    fn report_editor_event(
24917        &self,
24918        reported_event: ReportEditorEvent,
24919        file_extension: Option<String>,
24920        cx: &App,
24921    ) {
24922        if cfg!(any(test, feature = "test-support")) {
24923            return;
24924        }
24925
24926        let Some(project) = &self.project else { return };
24927
24928        // If None, we are in a file without an extension
24929        let file = self
24930            .buffer
24931            .read(cx)
24932            .as_singleton()
24933            .and_then(|b| b.read(cx).file());
24934        let file_extension = file_extension.or(file
24935            .as_ref()
24936            .and_then(|file| Path::new(file.file_name(cx)).extension())
24937            .and_then(|e| e.to_str())
24938            .map(|a| a.to_string()));
24939
24940        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24941            .map(|vim_mode| vim_mode.0)
24942            .unwrap_or(false);
24943
24944        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24945        let copilot_enabled = edit_predictions_provider
24946            == language::language_settings::EditPredictionProvider::Copilot;
24947        let copilot_enabled_for_language = self
24948            .buffer
24949            .read(cx)
24950            .language_settings(cx)
24951            .show_edit_predictions;
24952
24953        let project = project.read(cx);
24954        let event_type = reported_event.event_type();
24955
24956        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24957            telemetry::event!(
24958                event_type,
24959                type = if auto_saved {"autosave"} else {"manual"},
24960                file_extension,
24961                vim_mode,
24962                copilot_enabled,
24963                copilot_enabled_for_language,
24964                edit_predictions_provider,
24965                is_via_ssh = project.is_via_remote_server(),
24966            );
24967        } else {
24968            telemetry::event!(
24969                event_type,
24970                file_extension,
24971                vim_mode,
24972                copilot_enabled,
24973                copilot_enabled_for_language,
24974                edit_predictions_provider,
24975                is_via_ssh = project.is_via_remote_server(),
24976            );
24977        };
24978    }
24979
24980    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24981    /// with each line being an array of {text, highlight} objects.
24982    fn copy_highlight_json(
24983        &mut self,
24984        _: &CopyHighlightJson,
24985        _: &mut Window,
24986        cx: &mut Context<Self>,
24987    ) {
24988        #[derive(Serialize)]
24989        struct Chunk<'a> {
24990            text: String,
24991            highlight: Option<&'a str>,
24992        }
24993
24994        let snapshot = self.buffer.read(cx).snapshot(cx);
24995        let mut selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
24996        let max_point = snapshot.max_point();
24997
24998        let range = if self.selections.line_mode() {
24999            selection.start = Point::new(selection.start.row, 0);
25000            selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
25001            selection.goal = SelectionGoal::None;
25002            selection.range()
25003        } else if selection.is_empty() {
25004            Point::new(0, 0)..max_point
25005        } else {
25006            selection.range()
25007        };
25008
25009        let chunks = snapshot.chunks(range, true);
25010        let mut lines = Vec::new();
25011        let mut line: VecDeque<Chunk> = VecDeque::new();
25012
25013        let Some(style) = self.style.as_ref() else {
25014            return;
25015        };
25016
25017        for chunk in chunks {
25018            let highlight = chunk
25019                .syntax_highlight_id
25020                .and_then(|id| style.syntax.get_capture_name(id));
25021
25022            let mut chunk_lines = chunk.text.split('\n').peekable();
25023            while let Some(text) = chunk_lines.next() {
25024                let mut merged_with_last_token = false;
25025                if let Some(last_token) = line.back_mut()
25026                    && last_token.highlight == highlight
25027                {
25028                    last_token.text.push_str(text);
25029                    merged_with_last_token = true;
25030                }
25031
25032                if !merged_with_last_token {
25033                    line.push_back(Chunk {
25034                        text: text.into(),
25035                        highlight,
25036                    });
25037                }
25038
25039                if chunk_lines.peek().is_some() {
25040                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25041                        line.pop_front();
25042                    }
25043                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25044                        line.pop_back();
25045                    }
25046
25047                    lines.push(mem::take(&mut line));
25048                }
25049            }
25050        }
25051
25052        if line.iter().any(|chunk| !chunk.text.is_empty()) {
25053            lines.push(line);
25054        }
25055
25056        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25057            return;
25058        };
25059        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25060    }
25061
25062    pub fn open_context_menu(
25063        &mut self,
25064        _: &OpenContextMenu,
25065        window: &mut Window,
25066        cx: &mut Context<Self>,
25067    ) {
25068        self.request_autoscroll(Autoscroll::newest(), cx);
25069        let position = self
25070            .selections
25071            .newest_display(&self.display_snapshot(cx))
25072            .start;
25073        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25074    }
25075
25076    pub fn replay_insert_event(
25077        &mut self,
25078        text: &str,
25079        relative_utf16_range: Option<Range<isize>>,
25080        window: &mut Window,
25081        cx: &mut Context<Self>,
25082    ) {
25083        if !self.input_enabled {
25084            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25085            return;
25086        }
25087        if let Some(relative_utf16_range) = relative_utf16_range {
25088            let selections = self
25089                .selections
25090                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25091            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25092                let new_ranges = selections.into_iter().map(|range| {
25093                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25094                        range
25095                            .head()
25096                            .0
25097                            .0
25098                            .saturating_add_signed(relative_utf16_range.start),
25099                    ));
25100                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25101                        range
25102                            .head()
25103                            .0
25104                            .0
25105                            .saturating_add_signed(relative_utf16_range.end),
25106                    ));
25107                    start..end
25108                });
25109                s.select_ranges(new_ranges);
25110            });
25111        }
25112
25113        self.handle_input(text, window, cx);
25114    }
25115
25116    pub fn is_focused(&self, window: &Window) -> bool {
25117        self.focus_handle.is_focused(window)
25118    }
25119
25120    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25121        cx.emit(EditorEvent::Focused);
25122
25123        if let Some(descendant) = self
25124            .last_focused_descendant
25125            .take()
25126            .and_then(|descendant| descendant.upgrade())
25127        {
25128            window.focus(&descendant, cx);
25129        } else {
25130            if let Some(blame) = self.blame.as_ref() {
25131                blame.update(cx, GitBlame::focus)
25132            }
25133
25134            self.blink_manager.update(cx, BlinkManager::enable);
25135            self.show_cursor_names(window, cx);
25136            self.buffer.update(cx, |buffer, cx| {
25137                buffer.finalize_last_transaction(cx);
25138                if self.leader_id.is_none() {
25139                    buffer.set_active_selections(
25140                        &self.selections.disjoint_anchors_arc(),
25141                        self.selections.line_mode(),
25142                        self.cursor_shape,
25143                        cx,
25144                    );
25145                }
25146            });
25147
25148            if let Some(position_map) = self.last_position_map.clone()
25149                && !self.mouse_cursor_hidden
25150            {
25151                EditorElement::mouse_moved(
25152                    self,
25153                    &MouseMoveEvent {
25154                        position: window.mouse_position(),
25155                        pressed_button: None,
25156                        modifiers: window.modifiers(),
25157                    },
25158                    &position_map,
25159                    None,
25160                    window,
25161                    cx,
25162                );
25163            }
25164        }
25165    }
25166
25167    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25168        cx.emit(EditorEvent::FocusedIn)
25169    }
25170
25171    fn handle_focus_out(
25172        &mut self,
25173        event: FocusOutEvent,
25174        _window: &mut Window,
25175        cx: &mut Context<Self>,
25176    ) {
25177        if event.blurred != self.focus_handle {
25178            self.last_focused_descendant = Some(event.blurred);
25179        }
25180        self.selection_drag_state = SelectionDragState::None;
25181        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25182    }
25183
25184    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25185        self.blink_manager.update(cx, BlinkManager::disable);
25186        self.buffer
25187            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25188
25189        if let Some(blame) = self.blame.as_ref() {
25190            blame.update(cx, GitBlame::blur)
25191        }
25192        if !self.hover_state.focused(window, cx) {
25193            hide_hover(self, cx);
25194        }
25195        if !self
25196            .context_menu
25197            .borrow()
25198            .as_ref()
25199            .is_some_and(|context_menu| context_menu.focused(window, cx))
25200        {
25201            self.hide_context_menu(window, cx);
25202        }
25203        self.take_active_edit_prediction(true, cx);
25204        cx.emit(EditorEvent::Blurred);
25205        cx.notify();
25206    }
25207
25208    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25209        let mut pending: String = window
25210            .pending_input_keystrokes()
25211            .into_iter()
25212            .flatten()
25213            .filter_map(|keystroke| keystroke.key_char.clone())
25214            .collect();
25215
25216        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25217            pending = "".to_string();
25218        }
25219
25220        let existing_pending = self
25221            .text_highlights(HighlightKey::PendingInput, cx)
25222            .map(|(_, ranges)| ranges.to_vec());
25223        if existing_pending.is_none() && pending.is_empty() {
25224            return;
25225        }
25226        let transaction =
25227            self.transact(window, cx, |this, window, cx| {
25228                let selections = this
25229                    .selections
25230                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25231                let edits = selections
25232                    .iter()
25233                    .map(|selection| (selection.end..selection.end, pending.clone()));
25234                this.edit(edits, cx);
25235                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25236                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25237                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25238                    }));
25239                });
25240                if let Some(existing_ranges) = existing_pending {
25241                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25242                    this.edit(edits, cx);
25243                }
25244            });
25245
25246        let snapshot = self.snapshot(window, cx);
25247        let ranges = self
25248            .selections
25249            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25250            .into_iter()
25251            .map(|selection| {
25252                snapshot.buffer_snapshot().anchor_after(selection.end)
25253                    ..snapshot
25254                        .buffer_snapshot()
25255                        .anchor_before(selection.end + pending.len())
25256            })
25257            .collect();
25258
25259        if pending.is_empty() {
25260            self.clear_highlights(HighlightKey::PendingInput, cx);
25261        } else {
25262            self.highlight_text(
25263                HighlightKey::PendingInput,
25264                ranges,
25265                HighlightStyle {
25266                    underline: Some(UnderlineStyle {
25267                        thickness: px(1.),
25268                        color: None,
25269                        wavy: false,
25270                    }),
25271                    ..Default::default()
25272                },
25273                cx,
25274            );
25275        }
25276
25277        self.ime_transaction = self.ime_transaction.or(transaction);
25278        if let Some(transaction) = self.ime_transaction {
25279            self.buffer.update(cx, |buffer, cx| {
25280                buffer.group_until_transaction(transaction, cx);
25281            });
25282        }
25283
25284        if self
25285            .text_highlights(HighlightKey::PendingInput, cx)
25286            .is_none()
25287        {
25288            self.ime_transaction.take();
25289        }
25290    }
25291
25292    pub fn register_action_renderer(
25293        &mut self,
25294        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25295    ) -> Subscription {
25296        let id = self.next_editor_action_id.post_inc();
25297        self.editor_actions
25298            .borrow_mut()
25299            .insert(id, Box::new(listener));
25300
25301        let editor_actions = self.editor_actions.clone();
25302        Subscription::new(move || {
25303            editor_actions.borrow_mut().remove(&id);
25304        })
25305    }
25306
25307    pub fn register_action<A: Action>(
25308        &mut self,
25309        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25310    ) -> Subscription {
25311        let id = self.next_editor_action_id.post_inc();
25312        let listener = Arc::new(listener);
25313        self.editor_actions.borrow_mut().insert(
25314            id,
25315            Box::new(move |_, window, _| {
25316                let listener = listener.clone();
25317                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25318                    let action = action.downcast_ref().unwrap();
25319                    if phase == DispatchPhase::Bubble {
25320                        listener(action, window, cx)
25321                    }
25322                })
25323            }),
25324        );
25325
25326        let editor_actions = self.editor_actions.clone();
25327        Subscription::new(move || {
25328            editor_actions.borrow_mut().remove(&id);
25329        })
25330    }
25331
25332    pub fn file_header_size(&self) -> u32 {
25333        FILE_HEADER_HEIGHT
25334    }
25335
25336    pub fn restore(
25337        &mut self,
25338        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25339        window: &mut Window,
25340        cx: &mut Context<Self>,
25341    ) {
25342        self.buffer().update(cx, |multi_buffer, cx| {
25343            for (buffer_id, changes) in revert_changes {
25344                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25345                    buffer.update(cx, |buffer, cx| {
25346                        buffer.edit(
25347                            changes
25348                                .into_iter()
25349                                .map(|(range, text)| (range, text.to_string())),
25350                            None,
25351                            cx,
25352                        );
25353                    });
25354                }
25355            }
25356        });
25357        let selections = self
25358            .selections
25359            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
25360        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25361            s.select(selections);
25362        });
25363    }
25364
25365    pub fn to_pixel_point(
25366        &mut self,
25367        source: Anchor,
25368        editor_snapshot: &EditorSnapshot,
25369        window: &mut Window,
25370        cx: &mut App,
25371    ) -> Option<gpui::Point<Pixels>> {
25372        let source_point = source.to_display_point(editor_snapshot);
25373        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25374    }
25375
25376    pub fn display_to_pixel_point(
25377        &mut self,
25378        source: DisplayPoint,
25379        editor_snapshot: &EditorSnapshot,
25380        window: &mut Window,
25381        cx: &mut App,
25382    ) -> Option<gpui::Point<Pixels>> {
25383        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25384        let text_layout_details = self.text_layout_details(window, cx);
25385        let scroll_top = text_layout_details
25386            .scroll_anchor
25387            .scroll_position(editor_snapshot)
25388            .y;
25389
25390        if source.row().as_f64() < scroll_top.floor() {
25391            return None;
25392        }
25393        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25394        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25395        Some(gpui::Point::new(source_x, source_y))
25396    }
25397
25398    pub fn has_visible_completions_menu(&self) -> bool {
25399        !self.edit_prediction_preview_is_active()
25400            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25401                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25402            })
25403    }
25404
25405    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25406        if self.mode.is_minimap() {
25407            return;
25408        }
25409        self.addons
25410            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25411    }
25412
25413    pub fn unregister_addon<T: Addon>(&mut self) {
25414        self.addons.remove(&std::any::TypeId::of::<T>());
25415    }
25416
25417    pub fn addon<T: Addon>(&self) -> Option<&T> {
25418        let type_id = std::any::TypeId::of::<T>();
25419        self.addons
25420            .get(&type_id)
25421            .and_then(|item| item.to_any().downcast_ref::<T>())
25422    }
25423
25424    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25425        let type_id = std::any::TypeId::of::<T>();
25426        self.addons
25427            .get_mut(&type_id)
25428            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25429    }
25430
25431    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25432        let text_layout_details = self.text_layout_details(window, cx);
25433        let style = &text_layout_details.editor_style;
25434        let font_id = window.text_system().resolve_font(&style.text.font());
25435        let font_size = style.text.font_size.to_pixels(window.rem_size());
25436        let line_height = style.text.line_height_in_pixels(window.rem_size());
25437        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25438        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25439
25440        CharacterDimensions {
25441            em_width,
25442            em_advance,
25443            line_height,
25444        }
25445    }
25446
25447    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25448        self.load_diff_task.clone()
25449    }
25450
25451    fn read_metadata_from_db(
25452        &mut self,
25453        item_id: u64,
25454        workspace_id: WorkspaceId,
25455        window: &mut Window,
25456        cx: &mut Context<Editor>,
25457    ) {
25458        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25459            && !self.mode.is_minimap()
25460            && WorkspaceSettings::get(None, cx).restore_on_startup
25461                != RestoreOnStartupBehavior::EmptyTab
25462        {
25463            let buffer_snapshot = OnceCell::new();
25464
25465            // Get file path for path-based fold lookup
25466            let file_path: Option<Arc<Path>> =
25467                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25468                    project::File::from_dyn(buffer.read(cx).file())
25469                        .map(|file| Arc::from(file.abs_path(cx)))
25470                });
25471
25472            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25473            let db = EditorDb::global(cx);
25474            let (folds, needs_migration) = if let Some(ref path) = file_path {
25475                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25476                    && !folds.is_empty()
25477                {
25478                    (Some(folds), false)
25479                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25480                    && !folds.is_empty()
25481                {
25482                    // Found old editor_folds data, will migrate to file_folds
25483                    (Some(folds), true)
25484                } else {
25485                    (None, false)
25486                }
25487            } else {
25488                // No file path, try editor_folds as fallback
25489                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25490                (folds.filter(|f| !f.is_empty()), false)
25491            };
25492
25493            if let Some(folds) = folds {
25494                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25495                let snapshot_len = snapshot.len().0;
25496
25497                // Helper: search for fingerprint in buffer, return offset if found
25498                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25499                    // Ensure we start at a character boundary (defensive)
25500                    let search_start = snapshot
25501                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25502                        .0;
25503                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25504
25505                    let mut byte_offset = search_start;
25506                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25507                        if byte_offset > search_end {
25508                            break;
25509                        }
25510                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25511                            return Some(byte_offset);
25512                        }
25513                        byte_offset += ch.len_utf8();
25514                    }
25515                    None
25516                };
25517
25518                // Track search position to handle duplicate fingerprints correctly.
25519                // Folds are stored in document order, so we advance after each match.
25520                let mut search_start = 0usize;
25521
25522                // Collect db_folds for migration (only folds with valid fingerprints)
25523                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25524
25525                let valid_folds: Vec<_> = folds
25526                    .into_iter()
25527                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25528                        // Skip folds without fingerprints (old data before migration)
25529                        let sfp = start_fp?;
25530                        let efp = end_fp?;
25531                        let efp_len = efp.len();
25532
25533                        // Fast path: check if fingerprints match at stored offsets
25534                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25535                        let start_matches = stored_start < snapshot_len
25536                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25537                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25538                        let end_matches = efp_check_pos >= stored_start
25539                            && stored_end <= snapshot_len
25540                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25541
25542                        let (new_start, new_end) = if start_matches && end_matches {
25543                            // Offsets unchanged, use stored values
25544                            (stored_start, stored_end)
25545                        } else if sfp == efp {
25546                            // Short fold: identical fingerprints can only match once per search
25547                            // Use stored fold length to compute new_end
25548                            let new_start = find_fingerprint(&sfp, search_start)?;
25549                            let fold_len = stored_end - stored_start;
25550                            let new_end = new_start + fold_len;
25551                            (new_start, new_end)
25552                        } else {
25553                            // Slow path: search for fingerprints in buffer
25554                            let new_start = find_fingerprint(&sfp, search_start)?;
25555                            // Search for end_fp after start, then add efp_len to get actual fold end
25556                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25557                            let new_end = efp_pos + efp_len;
25558                            (new_start, new_end)
25559                        };
25560
25561                        // Advance search position for next fold
25562                        search_start = new_end;
25563
25564                        // Validate fold makes sense (end must be after start)
25565                        if new_end <= new_start {
25566                            return None;
25567                        }
25568
25569                        // Collect for migration if needed
25570                        if needs_migration {
25571                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25572                        }
25573
25574                        Some(
25575                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25576                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25577                        )
25578                    })
25579                    .collect();
25580
25581                if !valid_folds.is_empty() {
25582                    self.fold_ranges(valid_folds, false, window, cx);
25583
25584                    // Migrate from editor_folds to file_folds if we loaded from old table
25585                    if needs_migration {
25586                        if let Some(ref path) = file_path {
25587                            let path = path.clone();
25588                            let db = EditorDb::global(cx);
25589                            cx.spawn(async move |_, _| {
25590                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25591                                    .await
25592                                    .log_err();
25593                            })
25594                            .detach();
25595                        }
25596                    }
25597                }
25598            }
25599
25600            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25601                && !selections.is_empty()
25602            {
25603                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25604                // skip adding the initial selection to selection history
25605                self.selection_history.mode = SelectionHistoryMode::Skipping;
25606                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25607                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25608                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25609                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25610                    }));
25611                });
25612                self.selection_history.mode = SelectionHistoryMode::Normal;
25613            };
25614        }
25615
25616        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25617    }
25618
25619    /// Load folds from the file_folds database table by file path.
25620    /// Used when manually opening a file that was previously closed.
25621    fn load_folds_from_db(
25622        &mut self,
25623        workspace_id: WorkspaceId,
25624        file_path: PathBuf,
25625        window: &mut Window,
25626        cx: &mut Context<Editor>,
25627    ) {
25628        if self.mode.is_minimap()
25629            || WorkspaceSettings::get(None, cx).restore_on_startup
25630                == RestoreOnStartupBehavior::EmptyTab
25631        {
25632            return;
25633        }
25634
25635        let Some(folds) = EditorDb::global(cx)
25636            .get_file_folds(workspace_id, &file_path)
25637            .log_err()
25638        else {
25639            return;
25640        };
25641        if folds.is_empty() {
25642            return;
25643        }
25644
25645        let snapshot = self.buffer.read(cx).snapshot(cx);
25646        let snapshot_len = snapshot.len().0;
25647
25648        // Helper: search for fingerprint in buffer, return offset if found
25649        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25650            let search_start = snapshot
25651                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25652                .0;
25653            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25654
25655            let mut byte_offset = search_start;
25656            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25657                if byte_offset > search_end {
25658                    break;
25659                }
25660                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25661                    return Some(byte_offset);
25662                }
25663                byte_offset += ch.len_utf8();
25664            }
25665            None
25666        };
25667
25668        let mut search_start = 0usize;
25669
25670        let valid_folds: Vec<_> = folds
25671            .into_iter()
25672            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25673                let sfp = start_fp?;
25674                let efp = end_fp?;
25675                let efp_len = efp.len();
25676
25677                let start_matches = stored_start < snapshot_len
25678                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25679                let efp_check_pos = stored_end.saturating_sub(efp_len);
25680                let end_matches = efp_check_pos >= stored_start
25681                    && stored_end <= snapshot_len
25682                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25683
25684                let (new_start, new_end) = if start_matches && end_matches {
25685                    (stored_start, stored_end)
25686                } else if sfp == efp {
25687                    let new_start = find_fingerprint(&sfp, search_start)?;
25688                    let fold_len = stored_end - stored_start;
25689                    let new_end = new_start + fold_len;
25690                    (new_start, new_end)
25691                } else {
25692                    let new_start = find_fingerprint(&sfp, search_start)?;
25693                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25694                    let new_end = efp_pos + efp_len;
25695                    (new_start, new_end)
25696                };
25697
25698                search_start = new_end;
25699
25700                if new_end <= new_start {
25701                    return None;
25702                }
25703
25704                Some(
25705                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25706                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25707                )
25708            })
25709            .collect();
25710
25711        if !valid_folds.is_empty() {
25712            self.fold_ranges(valid_folds, false, window, cx);
25713        }
25714    }
25715
25716    fn lsp_data_enabled(&self) -> bool {
25717        self.enable_lsp_data && self.mode().is_full()
25718    }
25719
25720    fn update_lsp_data(
25721        &mut self,
25722        for_buffer: Option<BufferId>,
25723        window: &mut Window,
25724        cx: &mut Context<'_, Self>,
25725    ) {
25726        if !self.lsp_data_enabled() {
25727            return;
25728        }
25729
25730        if let Some(buffer_id) = for_buffer {
25731            self.pull_diagnostics(buffer_id, window, cx);
25732        }
25733        self.refresh_semantic_tokens(for_buffer, None, cx);
25734        self.refresh_document_colors(for_buffer, window, cx);
25735        self.refresh_folding_ranges(for_buffer, window, cx);
25736        self.refresh_document_symbols(for_buffer, cx);
25737    }
25738
25739    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25740        if !self.lsp_data_enabled() {
25741            return;
25742        }
25743        let visible_buffers: Vec<_> = self
25744            .visible_buffers(cx)
25745            .into_iter()
25746            .filter(|buffer| self.is_lsp_relevant(buffer.read(cx).file(), cx))
25747            .collect();
25748        for visible_buffer in visible_buffers {
25749            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25750        }
25751    }
25752
25753    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25754        if !self.lsp_data_enabled() {
25755            return;
25756        }
25757
25758        if !self.registered_buffers.contains_key(&buffer_id)
25759            && let Some(project) = self.project.as_ref()
25760        {
25761            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25762                project.update(cx, |project, cx| {
25763                    self.registered_buffers.insert(
25764                        buffer_id,
25765                        project.register_buffer_with_language_servers(&buffer, cx),
25766                    );
25767                });
25768            } else {
25769                self.registered_buffers.remove(&buffer_id);
25770            }
25771        }
25772    }
25773
25774    fn create_style(&self, cx: &App) -> EditorStyle {
25775        let settings = ThemeSettings::get_global(cx);
25776
25777        let mut text_style = match self.mode {
25778            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25779                color: cx.theme().colors().editor_foreground,
25780                font_family: settings.ui_font.family.clone(),
25781                font_features: settings.ui_font.features.clone(),
25782                font_fallbacks: settings.ui_font.fallbacks.clone(),
25783                font_size: rems(0.875).into(),
25784                font_weight: settings.ui_font.weight,
25785                line_height: relative(settings.buffer_line_height.value()),
25786                ..Default::default()
25787            },
25788            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25789                color: cx.theme().colors().editor_foreground,
25790                font_family: settings.buffer_font.family.clone(),
25791                font_features: settings.buffer_font.features.clone(),
25792                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25793                font_size: settings.buffer_font_size(cx).into(),
25794                font_weight: settings.buffer_font.weight,
25795                line_height: relative(settings.buffer_line_height.value()),
25796                ..Default::default()
25797            },
25798        };
25799        if let Some(text_style_refinement) = &self.text_style_refinement {
25800            text_style.refine(text_style_refinement)
25801        }
25802
25803        let background = match self.mode {
25804            EditorMode::SingleLine => cx.theme().system().transparent,
25805            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25806            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25807            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25808        };
25809
25810        EditorStyle {
25811            background,
25812            border: cx.theme().colors().border,
25813            local_player: cx.theme().players().local(),
25814            text: text_style,
25815            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25816            syntax: cx.theme().syntax().clone(),
25817            status: cx.theme().status().clone(),
25818            inlay_hints_style: make_inlay_hints_style(cx),
25819            edit_prediction_styles: make_suggestion_styles(cx),
25820            unnecessary_code_fade: settings.unnecessary_code_fade,
25821            show_underlines: self.diagnostics_enabled(),
25822        }
25823    }
25824
25825    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25826        let multibuffer = self.buffer().read(cx);
25827        let is_singleton = multibuffer.is_singleton();
25828        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25829        let buffer = multibuffer.buffer(*buffer_id)?;
25830
25831        let buffer = buffer.read(cx);
25832        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25833        let mut breadcrumbs = if is_singleton {
25834            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25835                buffer
25836                    .snapshot()
25837                    .resolve_file_path(
25838                        self.project
25839                            .as_ref()
25840                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25841                            .unwrap_or_default(),
25842                        cx,
25843                    )
25844                    .unwrap_or_else(|| {
25845                        if multibuffer.is_singleton() {
25846                            multibuffer.title(cx).to_string()
25847                        } else {
25848                            "untitled".to_string()
25849                        }
25850                    })
25851            });
25852            vec![HighlightedText {
25853                text: text.into(),
25854                highlights: vec![],
25855            }]
25856        } else {
25857            vec![]
25858        };
25859
25860        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25861            text: symbol.text.clone().into(),
25862            highlights: symbol.highlight_ranges.clone(),
25863        }));
25864        Some(breadcrumbs)
25865    }
25866
25867    fn disable_lsp_data(&mut self) {
25868        self.enable_lsp_data = false;
25869    }
25870
25871    fn disable_runnables(&mut self) {
25872        self.enable_runnables = false;
25873    }
25874
25875    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25876        self.register_visible_buffers(cx);
25877        self.colorize_brackets(false, cx);
25878        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25879        if !self.buffer().read(cx).is_singleton() {
25880            self.update_lsp_data(None, window, cx);
25881            self.refresh_runnables(None, window, cx);
25882        }
25883    }
25884}
25885
25886fn edit_for_markdown_paste<'a>(
25887    buffer: &MultiBufferSnapshot,
25888    range: Range<MultiBufferOffset>,
25889    to_insert: &'a str,
25890    url: Option<url::Url>,
25891) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25892    if url.is_none() {
25893        return (range, Cow::Borrowed(to_insert));
25894    };
25895
25896    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25897
25898    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25899        Cow::Borrowed(to_insert)
25900    } else {
25901        Cow::Owned(format!("[{old_text}]({to_insert})"))
25902    };
25903    (range, new_text)
25904}
25905
25906fn process_completion_for_edit(
25907    completion: &Completion,
25908    intent: CompletionIntent,
25909    buffer: &Entity<Buffer>,
25910    cursor_position: &text::Anchor,
25911    cx: &mut Context<Editor>,
25912) -> CompletionEdit {
25913    let buffer = buffer.read(cx);
25914    let buffer_snapshot = buffer.snapshot();
25915    let (snippet, new_text) = if completion.is_snippet() {
25916        let mut snippet_source = completion.new_text.clone();
25917        // Workaround for typescript language server issues so that methods don't expand within
25918        // strings and functions with type expressions. The previous point is used because the query
25919        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25920        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25921        let previous_point = if previous_point.column > 0 {
25922            cursor_position.to_previous_offset(&buffer_snapshot)
25923        } else {
25924            cursor_position.to_offset(&buffer_snapshot)
25925        };
25926        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25927            && scope.prefers_label_for_snippet_in_completion()
25928            && let Some(label) = completion.label()
25929            && matches!(
25930                completion.kind(),
25931                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25932            )
25933        {
25934            snippet_source = label;
25935        }
25936        match Snippet::parse(&snippet_source).log_err() {
25937            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25938            None => (None, completion.new_text.clone()),
25939        }
25940    } else {
25941        (None, completion.new_text.clone())
25942    };
25943
25944    let mut range_to_replace = {
25945        let replace_range = &completion.replace_range;
25946        if let CompletionSource::Lsp {
25947            insert_range: Some(insert_range),
25948            ..
25949        } = &completion.source
25950        {
25951            debug_assert_eq!(
25952                insert_range.start, replace_range.start,
25953                "insert_range and replace_range should start at the same position"
25954            );
25955            debug_assert!(
25956                insert_range
25957                    .start
25958                    .cmp(cursor_position, &buffer_snapshot)
25959                    .is_le(),
25960                "insert_range should start before or at cursor position"
25961            );
25962            debug_assert!(
25963                replace_range
25964                    .start
25965                    .cmp(cursor_position, &buffer_snapshot)
25966                    .is_le(),
25967                "replace_range should start before or at cursor position"
25968            );
25969
25970            let should_replace = match intent {
25971                CompletionIntent::CompleteWithInsert => false,
25972                CompletionIntent::CompleteWithReplace => true,
25973                CompletionIntent::Complete | CompletionIntent::Compose => {
25974                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
25975                        .completions
25976                        .lsp_insert_mode;
25977                    match insert_mode {
25978                        LspInsertMode::Insert => false,
25979                        LspInsertMode::Replace => true,
25980                        LspInsertMode::ReplaceSubsequence => {
25981                            let mut text_to_replace = buffer.chars_for_range(
25982                                buffer.anchor_before(replace_range.start)
25983                                    ..buffer.anchor_after(replace_range.end),
25984                            );
25985                            let mut current_needle = text_to_replace.next();
25986                            for haystack_ch in completion.label.text.chars() {
25987                                if let Some(needle_ch) = current_needle
25988                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25989                                {
25990                                    current_needle = text_to_replace.next();
25991                                }
25992                            }
25993                            current_needle.is_none()
25994                        }
25995                        LspInsertMode::ReplaceSuffix => {
25996                            if replace_range
25997                                .end
25998                                .cmp(cursor_position, &buffer_snapshot)
25999                                .is_gt()
26000                            {
26001                                let range_after_cursor = *cursor_position..replace_range.end;
26002                                let text_after_cursor = buffer
26003                                    .text_for_range(
26004                                        buffer.anchor_before(range_after_cursor.start)
26005                                            ..buffer.anchor_after(range_after_cursor.end),
26006                                    )
26007                                    .collect::<String>()
26008                                    .to_ascii_lowercase();
26009                                completion
26010                                    .label
26011                                    .text
26012                                    .to_ascii_lowercase()
26013                                    .ends_with(&text_after_cursor)
26014                            } else {
26015                                true
26016                            }
26017                        }
26018                    }
26019                }
26020            };
26021
26022            if should_replace {
26023                replace_range.clone()
26024            } else {
26025                insert_range.clone()
26026            }
26027        } else {
26028            replace_range.clone()
26029        }
26030    };
26031
26032    if range_to_replace
26033        .end
26034        .cmp(cursor_position, &buffer_snapshot)
26035        .is_lt()
26036    {
26037        range_to_replace.end = *cursor_position;
26038    }
26039
26040    CompletionEdit {
26041        new_text,
26042        replace_range: range_to_replace,
26043        snippet,
26044    }
26045}
26046
26047struct CompletionEdit {
26048    new_text: String,
26049    replace_range: Range<text::Anchor>,
26050    snippet: Option<Snippet>,
26051}
26052
26053fn comment_delimiter_for_newline(
26054    start_point: &Point,
26055    buffer: &MultiBufferSnapshot,
26056    language: &LanguageScope,
26057) -> Option<Arc<str>> {
26058    let delimiters = language.line_comment_prefixes();
26059    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26060    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26061
26062    let num_of_whitespaces = snapshot
26063        .chars_for_range(range.clone())
26064        .take_while(|c| c.is_whitespace())
26065        .count();
26066    let comment_candidate = snapshot
26067        .chars_for_range(range.clone())
26068        .skip(num_of_whitespaces)
26069        .take(max_len_of_delimiter + 2)
26070        .collect::<String>();
26071    let (delimiter, trimmed_len, is_repl) = delimiters
26072        .iter()
26073        .filter_map(|delimiter| {
26074            let prefix = delimiter.trim_end();
26075            if comment_candidate.starts_with(prefix) {
26076                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26077                {
26078                    stripped_comment.starts_with(" %%")
26079                } else {
26080                    false
26081                };
26082                Some((delimiter, prefix.len(), is_repl))
26083            } else {
26084                None
26085            }
26086        })
26087        .max_by_key(|(_, len, _)| *len)?;
26088
26089    if let Some(BlockCommentConfig {
26090        start: block_start, ..
26091    }) = language.block_comment()
26092    {
26093        let block_start_trimmed = block_start.trim_end();
26094        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26095            let line_content = snapshot
26096                .chars_for_range(range.clone())
26097                .skip(num_of_whitespaces)
26098                .take(block_start_trimmed.len())
26099                .collect::<String>();
26100
26101            if line_content.starts_with(block_start_trimmed) {
26102                return None;
26103            }
26104        }
26105    }
26106
26107    let cursor_is_placed_after_comment_marker =
26108        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26109    if cursor_is_placed_after_comment_marker {
26110        if !is_repl {
26111            return Some(delimiter.clone());
26112        }
26113
26114        let line_content_after_cursor: String = snapshot
26115            .chars_for_range(range)
26116            .skip(start_point.column as usize)
26117            .collect();
26118
26119        if line_content_after_cursor.trim().is_empty() {
26120            return None;
26121        } else {
26122            return Some(delimiter.clone());
26123        }
26124    } else {
26125        None
26126    }
26127}
26128
26129fn documentation_delimiter_for_newline(
26130    start_point: &Point,
26131    buffer: &MultiBufferSnapshot,
26132    language: &LanguageScope,
26133    newline_config: &mut NewlineConfig,
26134) -> Option<Arc<str>> {
26135    let BlockCommentConfig {
26136        start: start_tag,
26137        end: end_tag,
26138        prefix: delimiter,
26139        tab_size: len,
26140    } = language.documentation_comment()?;
26141    let is_within_block_comment = buffer
26142        .language_scope_at(*start_point)
26143        .is_some_and(|scope| scope.override_name() == Some("comment"));
26144    if !is_within_block_comment {
26145        return None;
26146    }
26147
26148    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26149
26150    let num_of_whitespaces = snapshot
26151        .chars_for_range(range.clone())
26152        .take_while(|c| c.is_whitespace())
26153        .count();
26154
26155    // 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.
26156    let column = start_point.column;
26157    let cursor_is_after_start_tag = {
26158        let start_tag_len = start_tag.len();
26159        let start_tag_line = snapshot
26160            .chars_for_range(range.clone())
26161            .skip(num_of_whitespaces)
26162            .take(start_tag_len)
26163            .collect::<String>();
26164        if start_tag_line.starts_with(start_tag.as_ref()) {
26165            num_of_whitespaces + start_tag_len <= column as usize
26166        } else {
26167            false
26168        }
26169    };
26170
26171    let cursor_is_after_delimiter = {
26172        let delimiter_trim = delimiter.trim_end();
26173        let delimiter_line = snapshot
26174            .chars_for_range(range.clone())
26175            .skip(num_of_whitespaces)
26176            .take(delimiter_trim.len())
26177            .collect::<String>();
26178        if delimiter_line.starts_with(delimiter_trim) {
26179            num_of_whitespaces + delimiter_trim.len() <= column as usize
26180        } else {
26181            false
26182        }
26183    };
26184
26185    let mut needs_extra_line = false;
26186    let mut extra_line_additional_indent = IndentSize::spaces(0);
26187
26188    let cursor_is_before_end_tag_if_exists = {
26189        let mut char_position = 0u32;
26190        let mut end_tag_offset = None;
26191
26192        'outer: for chunk in snapshot.text_for_range(range) {
26193            if let Some(byte_pos) = chunk.find(&**end_tag) {
26194                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26195                end_tag_offset = Some(char_position + chars_before_match);
26196                break 'outer;
26197            }
26198            char_position += chunk.chars().count() as u32;
26199        }
26200
26201        if let Some(end_tag_offset) = end_tag_offset {
26202            let cursor_is_before_end_tag = column <= end_tag_offset;
26203            if cursor_is_after_start_tag {
26204                if cursor_is_before_end_tag {
26205                    needs_extra_line = true;
26206                }
26207                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26208                if cursor_is_at_start_of_end_tag {
26209                    extra_line_additional_indent.len = *len;
26210                }
26211            }
26212            cursor_is_before_end_tag
26213        } else {
26214            true
26215        }
26216    };
26217
26218    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26219        && cursor_is_before_end_tag_if_exists
26220    {
26221        let additional_indent = if cursor_is_after_start_tag {
26222            IndentSize::spaces(*len)
26223        } else {
26224            IndentSize::spaces(0)
26225        };
26226
26227        *newline_config = NewlineConfig::Newline {
26228            additional_indent,
26229            extra_line_additional_indent: if needs_extra_line {
26230                Some(extra_line_additional_indent)
26231            } else {
26232                None
26233            },
26234            prevent_auto_indent: true,
26235        };
26236        Some(delimiter.clone())
26237    } else {
26238        None
26239    }
26240}
26241
26242const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26243
26244fn list_delimiter_for_newline(
26245    start_point: &Point,
26246    buffer: &MultiBufferSnapshot,
26247    language: &LanguageScope,
26248    newline_config: &mut NewlineConfig,
26249) -> Option<Arc<str>> {
26250    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26251
26252    let num_of_whitespaces = snapshot
26253        .chars_for_range(range.clone())
26254        .take_while(|c| c.is_whitespace())
26255        .count();
26256
26257    let task_list_entries: Vec<_> = language
26258        .task_list()
26259        .into_iter()
26260        .flat_map(|config| {
26261            config
26262                .prefixes
26263                .iter()
26264                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26265        })
26266        .collect();
26267    let unordered_list_entries: Vec<_> = language
26268        .unordered_list()
26269        .iter()
26270        .map(|marker| (marker.as_ref(), marker.as_ref()))
26271        .collect();
26272
26273    let all_entries: Vec<_> = task_list_entries
26274        .into_iter()
26275        .chain(unordered_list_entries)
26276        .collect();
26277
26278    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26279        let candidate: String = snapshot
26280            .chars_for_range(range.clone())
26281            .skip(num_of_whitespaces)
26282            .take(max_prefix_len)
26283            .collect();
26284
26285        if let Some((prefix, continuation)) = all_entries
26286            .iter()
26287            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26288            .max_by_key(|(prefix, _)| prefix.len())
26289        {
26290            let end_of_prefix = num_of_whitespaces + prefix.len();
26291            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26292            let has_content_after_marker = snapshot
26293                .chars_for_range(range)
26294                .skip(end_of_prefix)
26295                .any(|c| !c.is_whitespace());
26296
26297            if has_content_after_marker && cursor_is_after_prefix {
26298                return Some((*continuation).into());
26299            }
26300
26301            if start_point.column as usize == end_of_prefix {
26302                if num_of_whitespaces == 0 {
26303                    *newline_config = NewlineConfig::ClearCurrentLine;
26304                } else {
26305                    *newline_config = NewlineConfig::UnindentCurrentLine {
26306                        continuation: (*continuation).into(),
26307                    };
26308                }
26309            }
26310
26311            return None;
26312        }
26313    }
26314
26315    let candidate: String = snapshot
26316        .chars_for_range(range.clone())
26317        .skip(num_of_whitespaces)
26318        .take(ORDERED_LIST_MAX_MARKER_LEN)
26319        .collect();
26320
26321    for ordered_config in language.ordered_list() {
26322        let regex = match Regex::new(&ordered_config.pattern) {
26323            Ok(r) => r,
26324            Err(_) => continue,
26325        };
26326
26327        if let Some(captures) = regex.captures(&candidate) {
26328            let full_match = captures.get(0)?;
26329            let marker_len = full_match.len();
26330            let end_of_prefix = num_of_whitespaces + marker_len;
26331            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26332
26333            let has_content_after_marker = snapshot
26334                .chars_for_range(range)
26335                .skip(end_of_prefix)
26336                .any(|c| !c.is_whitespace());
26337
26338            if has_content_after_marker && cursor_is_after_prefix {
26339                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26340                let continuation = ordered_config
26341                    .format
26342                    .replace("{1}", &(number + 1).to_string());
26343                return Some(continuation.into());
26344            }
26345
26346            if start_point.column as usize == end_of_prefix {
26347                let continuation = ordered_config.format.replace("{1}", "1");
26348                if num_of_whitespaces == 0 {
26349                    *newline_config = NewlineConfig::ClearCurrentLine;
26350                } else {
26351                    *newline_config = NewlineConfig::UnindentCurrentLine {
26352                        continuation: continuation.into(),
26353                    };
26354                }
26355            }
26356
26357            return None;
26358        }
26359    }
26360
26361    None
26362}
26363
26364fn is_list_prefix_row(
26365    row: MultiBufferRow,
26366    buffer: &MultiBufferSnapshot,
26367    language: &LanguageScope,
26368) -> bool {
26369    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26370        return false;
26371    };
26372
26373    let num_of_whitespaces = snapshot
26374        .chars_for_range(range.clone())
26375        .take_while(|c| c.is_whitespace())
26376        .count();
26377
26378    let task_list_prefixes: Vec<_> = language
26379        .task_list()
26380        .into_iter()
26381        .flat_map(|config| {
26382            config
26383                .prefixes
26384                .iter()
26385                .map(|p| p.as_ref())
26386                .collect::<Vec<_>>()
26387        })
26388        .collect();
26389    let unordered_list_markers: Vec<_> = language
26390        .unordered_list()
26391        .iter()
26392        .map(|marker| marker.as_ref())
26393        .collect();
26394    let all_prefixes: Vec<_> = task_list_prefixes
26395        .into_iter()
26396        .chain(unordered_list_markers)
26397        .collect();
26398    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26399        let candidate: String = snapshot
26400            .chars_for_range(range.clone())
26401            .skip(num_of_whitespaces)
26402            .take(max_prefix_len)
26403            .collect();
26404        if all_prefixes
26405            .iter()
26406            .any(|prefix| candidate.starts_with(*prefix))
26407        {
26408            return true;
26409        }
26410    }
26411
26412    let ordered_list_candidate: String = snapshot
26413        .chars_for_range(range)
26414        .skip(num_of_whitespaces)
26415        .take(ORDERED_LIST_MAX_MARKER_LEN)
26416        .collect();
26417    for ordered_config in language.ordered_list() {
26418        let regex = match Regex::new(&ordered_config.pattern) {
26419            Ok(r) => r,
26420            Err(_) => continue,
26421        };
26422        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26423            return captures.get(0).is_some();
26424        }
26425    }
26426
26427    false
26428}
26429
26430#[derive(Debug)]
26431enum NewlineConfig {
26432    /// Insert newline with optional additional indent and optional extra blank line
26433    Newline {
26434        additional_indent: IndentSize,
26435        extra_line_additional_indent: Option<IndentSize>,
26436        prevent_auto_indent: bool,
26437    },
26438    /// Clear the current line
26439    ClearCurrentLine,
26440    /// Unindent the current line and add continuation
26441    UnindentCurrentLine { continuation: Arc<str> },
26442}
26443
26444impl NewlineConfig {
26445    fn has_extra_line(&self) -> bool {
26446        matches!(
26447            self,
26448            Self::Newline {
26449                extra_line_additional_indent: Some(_),
26450                ..
26451            }
26452        )
26453    }
26454
26455    fn insert_extra_newline_brackets(
26456        buffer: &MultiBufferSnapshot,
26457        range: Range<MultiBufferOffset>,
26458        language: &language::LanguageScope,
26459    ) -> bool {
26460        let leading_whitespace_len = buffer
26461            .reversed_chars_at(range.start)
26462            .take_while(|c| c.is_whitespace() && *c != '\n')
26463            .map(|c| c.len_utf8())
26464            .sum::<usize>();
26465        let trailing_whitespace_len = buffer
26466            .chars_at(range.end)
26467            .take_while(|c| c.is_whitespace() && *c != '\n')
26468            .map(|c| c.len_utf8())
26469            .sum::<usize>();
26470        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26471
26472        language.brackets().any(|(pair, enabled)| {
26473            let pair_start = pair.start.trim_end();
26474            let pair_end = pair.end.trim_start();
26475
26476            enabled
26477                && pair.newline
26478                && buffer.contains_str_at(range.end, pair_end)
26479                && buffer.contains_str_at(
26480                    range.start.saturating_sub_usize(pair_start.len()),
26481                    pair_start,
26482                )
26483        })
26484    }
26485
26486    fn insert_extra_newline_tree_sitter(
26487        buffer: &MultiBufferSnapshot,
26488        range: Range<MultiBufferOffset>,
26489    ) -> bool {
26490        let (buffer, range) = match buffer
26491            .range_to_buffer_ranges(range.start..range.end)
26492            .as_slice()
26493        {
26494            [(buffer_snapshot, range, _)] => (buffer_snapshot.clone(), range.clone()),
26495            _ => return false,
26496        };
26497        let pair = {
26498            let mut result: Option<BracketMatch<usize>> = None;
26499
26500            for pair in buffer
26501                .all_bracket_ranges(range.start.0..range.end.0)
26502                .filter(move |pair| {
26503                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26504                })
26505            {
26506                let len = pair.close_range.end - pair.open_range.start;
26507
26508                if let Some(existing) = &result {
26509                    let existing_len = existing.close_range.end - existing.open_range.start;
26510                    if len > existing_len {
26511                        continue;
26512                    }
26513                }
26514
26515                result = Some(pair);
26516            }
26517
26518            result
26519        };
26520        let Some(pair) = pair else {
26521            return false;
26522        };
26523        pair.newline_only
26524            && buffer
26525                .chars_for_range(pair.open_range.end..range.start.0)
26526                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26527                .all(|c| c.is_whitespace() && c != '\n')
26528    }
26529}
26530
26531fn update_uncommitted_diff_for_buffer(
26532    editor: Entity<Editor>,
26533    project: &Entity<Project>,
26534    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26535    buffer: Entity<MultiBuffer>,
26536    cx: &mut App,
26537) -> Task<()> {
26538    let mut tasks = Vec::new();
26539    project.update(cx, |project, cx| {
26540        for buffer in buffers {
26541            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26542                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26543            }
26544        }
26545    });
26546    cx.spawn(async move |cx| {
26547        let diffs = future::join_all(tasks).await;
26548        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26549            return;
26550        }
26551
26552        buffer.update(cx, |buffer, cx| {
26553            for diff in diffs.into_iter().flatten() {
26554                buffer.add_diff(diff, cx);
26555            }
26556        });
26557    })
26558}
26559
26560fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26561    let tab_size = tab_size.get() as usize;
26562    let mut width = offset;
26563
26564    for ch in text.chars() {
26565        width += if ch == '\t' {
26566            tab_size - (width % tab_size)
26567        } else {
26568            1
26569        };
26570    }
26571
26572    width - offset
26573}
26574
26575#[cfg(test)]
26576mod tests {
26577    use super::*;
26578
26579    #[test]
26580    fn test_string_size_with_expanded_tabs() {
26581        let nz = |val| NonZeroU32::new(val).unwrap();
26582        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26583        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26584        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26585        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26586        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26587        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26588        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26589        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26590    }
26591}
26592
26593/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26594struct WordBreakingTokenizer<'a> {
26595    input: &'a str,
26596}
26597
26598impl<'a> WordBreakingTokenizer<'a> {
26599    fn new(input: &'a str) -> Self {
26600        Self { input }
26601    }
26602}
26603
26604fn is_char_ideographic(ch: char) -> bool {
26605    use unicode_script::Script::*;
26606    use unicode_script::UnicodeScript;
26607    matches!(ch.script(), Han | Tangut | Yi)
26608}
26609
26610fn is_grapheme_ideographic(text: &str) -> bool {
26611    text.chars().any(is_char_ideographic)
26612}
26613
26614fn is_grapheme_whitespace(text: &str) -> bool {
26615    text.chars().any(|x| x.is_whitespace())
26616}
26617
26618fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26619    text.chars()
26620        .next()
26621        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26622}
26623
26624#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26625enum WordBreakToken<'a> {
26626    Word { token: &'a str, grapheme_len: usize },
26627    InlineWhitespace { token: &'a str, grapheme_len: usize },
26628    Newline,
26629}
26630
26631impl<'a> Iterator for WordBreakingTokenizer<'a> {
26632    /// Yields a span, the count of graphemes in the token, and whether it was
26633    /// whitespace. Note that it also breaks at word boundaries.
26634    type Item = WordBreakToken<'a>;
26635
26636    fn next(&mut self) -> Option<Self::Item> {
26637        use unicode_segmentation::UnicodeSegmentation;
26638        if self.input.is_empty() {
26639            return None;
26640        }
26641
26642        let mut iter = self.input.graphemes(true).peekable();
26643        let mut offset = 0;
26644        let mut grapheme_len = 0;
26645        if let Some(first_grapheme) = iter.next() {
26646            let is_newline = first_grapheme == "\n";
26647            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26648            offset += first_grapheme.len();
26649            grapheme_len += 1;
26650            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26651                if let Some(grapheme) = iter.peek().copied()
26652                    && should_stay_with_preceding_ideograph(grapheme)
26653                {
26654                    offset += grapheme.len();
26655                    grapheme_len += 1;
26656                }
26657            } else {
26658                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26659                let mut next_word_bound = words.peek().copied();
26660                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26661                    next_word_bound = words.next();
26662                }
26663                while let Some(grapheme) = iter.peek().copied() {
26664                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26665                        break;
26666                    };
26667                    if is_grapheme_whitespace(grapheme) != is_whitespace
26668                        || (grapheme == "\n") != is_newline
26669                    {
26670                        break;
26671                    };
26672                    offset += grapheme.len();
26673                    grapheme_len += 1;
26674                    iter.next();
26675                }
26676            }
26677            let token = &self.input[..offset];
26678            self.input = &self.input[offset..];
26679            if token == "\n" {
26680                Some(WordBreakToken::Newline)
26681            } else if is_whitespace {
26682                Some(WordBreakToken::InlineWhitespace {
26683                    token,
26684                    grapheme_len,
26685                })
26686            } else {
26687                Some(WordBreakToken::Word {
26688                    token,
26689                    grapheme_len,
26690                })
26691            }
26692        } else {
26693            None
26694        }
26695    }
26696}
26697
26698#[test]
26699fn test_word_breaking_tokenizer() {
26700    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26701        ("", &[]),
26702        ("  ", &[whitespace("  ", 2)]),
26703        ("Ʒ", &[word("Ʒ", 1)]),
26704        ("Ǽ", &[word("Ǽ", 1)]),
26705        ("", &[word("", 1)]),
26706        ("⋑⋑", &[word("⋑⋑", 2)]),
26707        (
26708            "原理,进而",
26709            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26710        ),
26711        (
26712            "hello world",
26713            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26714        ),
26715        (
26716            "hello, world",
26717            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26718        ),
26719        (
26720            "  hello world",
26721            &[
26722                whitespace("  ", 2),
26723                word("hello", 5),
26724                whitespace(" ", 1),
26725                word("world", 5),
26726            ],
26727        ),
26728        (
26729            "这是什么 \n 钢笔",
26730            &[
26731                word("", 1),
26732                word("", 1),
26733                word("", 1),
26734                word("", 1),
26735                whitespace(" ", 1),
26736                newline(),
26737                whitespace(" ", 1),
26738                word("", 1),
26739                word("", 1),
26740            ],
26741        ),
26742        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26743    ];
26744
26745    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26746        WordBreakToken::Word {
26747            token,
26748            grapheme_len,
26749        }
26750    }
26751
26752    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26753        WordBreakToken::InlineWhitespace {
26754            token,
26755            grapheme_len,
26756        }
26757    }
26758
26759    fn newline() -> WordBreakToken<'static> {
26760        WordBreakToken::Newline
26761    }
26762
26763    for (input, result) in tests {
26764        assert_eq!(
26765            WordBreakingTokenizer::new(input)
26766                .collect::<Vec<_>>()
26767                .as_slice(),
26768            *result,
26769        );
26770    }
26771}
26772
26773fn wrap_with_prefix(
26774    first_line_prefix: String,
26775    subsequent_lines_prefix: String,
26776    unwrapped_text: String,
26777    wrap_column: usize,
26778    tab_size: NonZeroU32,
26779    preserve_existing_whitespace: bool,
26780) -> String {
26781    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26782    let subsequent_lines_prefix_len =
26783        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26784    let mut wrapped_text = String::new();
26785    let mut current_line = first_line_prefix;
26786    let mut is_first_line = true;
26787
26788    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26789    let mut current_line_len = first_line_prefix_len;
26790    let mut in_whitespace = false;
26791    for token in tokenizer {
26792        let have_preceding_whitespace = in_whitespace;
26793        match token {
26794            WordBreakToken::Word {
26795                token,
26796                grapheme_len,
26797            } => {
26798                in_whitespace = false;
26799                let current_prefix_len = if is_first_line {
26800                    first_line_prefix_len
26801                } else {
26802                    subsequent_lines_prefix_len
26803                };
26804                if current_line_len + grapheme_len > wrap_column
26805                    && current_line_len != current_prefix_len
26806                {
26807                    wrapped_text.push_str(current_line.trim_end());
26808                    wrapped_text.push('\n');
26809                    is_first_line = false;
26810                    current_line = subsequent_lines_prefix.clone();
26811                    current_line_len = subsequent_lines_prefix_len;
26812                }
26813                current_line.push_str(token);
26814                current_line_len += grapheme_len;
26815            }
26816            WordBreakToken::InlineWhitespace {
26817                mut token,
26818                mut grapheme_len,
26819            } => {
26820                in_whitespace = true;
26821                if have_preceding_whitespace && !preserve_existing_whitespace {
26822                    continue;
26823                }
26824                if !preserve_existing_whitespace {
26825                    // Keep a single whitespace grapheme as-is
26826                    if let Some(first) =
26827                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26828                    {
26829                        token = first;
26830                    } else {
26831                        token = " ";
26832                    }
26833                    grapheme_len = 1;
26834                }
26835                let current_prefix_len = if is_first_line {
26836                    first_line_prefix_len
26837                } else {
26838                    subsequent_lines_prefix_len
26839                };
26840                if current_line_len + grapheme_len > wrap_column {
26841                    wrapped_text.push_str(current_line.trim_end());
26842                    wrapped_text.push('\n');
26843                    is_first_line = false;
26844                    current_line = subsequent_lines_prefix.clone();
26845                    current_line_len = subsequent_lines_prefix_len;
26846                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26847                    current_line.push_str(token);
26848                    current_line_len += grapheme_len;
26849                }
26850            }
26851            WordBreakToken::Newline => {
26852                in_whitespace = true;
26853                let current_prefix_len = if is_first_line {
26854                    first_line_prefix_len
26855                } else {
26856                    subsequent_lines_prefix_len
26857                };
26858                if preserve_existing_whitespace {
26859                    wrapped_text.push_str(current_line.trim_end());
26860                    wrapped_text.push('\n');
26861                    is_first_line = false;
26862                    current_line = subsequent_lines_prefix.clone();
26863                    current_line_len = subsequent_lines_prefix_len;
26864                } else if have_preceding_whitespace {
26865                    continue;
26866                } else if current_line_len + 1 > wrap_column
26867                    && current_line_len != current_prefix_len
26868                {
26869                    wrapped_text.push_str(current_line.trim_end());
26870                    wrapped_text.push('\n');
26871                    is_first_line = false;
26872                    current_line = subsequent_lines_prefix.clone();
26873                    current_line_len = subsequent_lines_prefix_len;
26874                } else if current_line_len != current_prefix_len {
26875                    current_line.push(' ');
26876                    current_line_len += 1;
26877                }
26878            }
26879        }
26880    }
26881
26882    if !current_line.is_empty() {
26883        wrapped_text.push_str(&current_line);
26884    }
26885    wrapped_text
26886}
26887
26888#[test]
26889fn test_wrap_with_prefix() {
26890    assert_eq!(
26891        wrap_with_prefix(
26892            "# ".to_string(),
26893            "# ".to_string(),
26894            "abcdefg".to_string(),
26895            4,
26896            NonZeroU32::new(4).unwrap(),
26897            false,
26898        ),
26899        "# abcdefg"
26900    );
26901    assert_eq!(
26902        wrap_with_prefix(
26903            "".to_string(),
26904            "".to_string(),
26905            "\thello world".to_string(),
26906            8,
26907            NonZeroU32::new(4).unwrap(),
26908            false,
26909        ),
26910        "hello\nworld"
26911    );
26912    assert_eq!(
26913        wrap_with_prefix(
26914            "// ".to_string(),
26915            "// ".to_string(),
26916            "xx \nyy zz aa bb cc".to_string(),
26917            12,
26918            NonZeroU32::new(4).unwrap(),
26919            false,
26920        ),
26921        "// xx yy zz\n// aa bb cc"
26922    );
26923    assert_eq!(
26924        wrap_with_prefix(
26925            String::new(),
26926            String::new(),
26927            "这是什么 \n 钢笔".to_string(),
26928            3,
26929            NonZeroU32::new(4).unwrap(),
26930            false,
26931        ),
26932        "这是什\n么 钢\n"
26933    );
26934    assert_eq!(
26935        wrap_with_prefix(
26936            String::new(),
26937            String::new(),
26938            format!("foo{}bar", '\u{2009}'), // thin space
26939            80,
26940            NonZeroU32::new(4).unwrap(),
26941            false,
26942        ),
26943        format!("foo{}bar", '\u{2009}')
26944    );
26945}
26946
26947pub trait CollaborationHub {
26948    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26949    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26950    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26951}
26952
26953impl CollaborationHub for Entity<Project> {
26954    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26955        self.read(cx).collaborators()
26956    }
26957
26958    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26959        self.read(cx).user_store().read(cx).participant_indices()
26960    }
26961
26962    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26963        let this = self.read(cx);
26964        let user_ids = this.collaborators().values().map(|c| c.user_id);
26965        this.user_store().read(cx).participant_names(user_ids, cx)
26966    }
26967}
26968
26969pub trait SemanticsProvider {
26970    fn hover(
26971        &self,
26972        buffer: &Entity<Buffer>,
26973        position: text::Anchor,
26974        cx: &mut App,
26975    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26976
26977    fn inline_values(
26978        &self,
26979        buffer_handle: Entity<Buffer>,
26980        range: Range<text::Anchor>,
26981        cx: &mut App,
26982    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26983
26984    fn applicable_inlay_chunks(
26985        &self,
26986        buffer: &Entity<Buffer>,
26987        ranges: &[Range<text::Anchor>],
26988        cx: &mut App,
26989    ) -> Vec<Range<BufferRow>>;
26990
26991    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26992
26993    fn inlay_hints(
26994        &self,
26995        invalidate: InvalidationStrategy,
26996        buffer: Entity<Buffer>,
26997        ranges: Vec<Range<text::Anchor>>,
26998        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26999        cx: &mut App,
27000    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27001
27002    fn semantic_tokens(
27003        &self,
27004        buffer: Entity<Buffer>,
27005        refresh: Option<RefreshForServer>,
27006        cx: &mut App,
27007    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27008
27009    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27010
27011    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27012
27013    fn document_highlights(
27014        &self,
27015        buffer: &Entity<Buffer>,
27016        position: text::Anchor,
27017        cx: &mut App,
27018    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27019
27020    fn definitions(
27021        &self,
27022        buffer: &Entity<Buffer>,
27023        position: text::Anchor,
27024        kind: GotoDefinitionKind,
27025        cx: &mut App,
27026    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27027
27028    fn range_for_rename(
27029        &self,
27030        buffer: &Entity<Buffer>,
27031        position: text::Anchor,
27032        cx: &mut App,
27033    ) -> Task<Result<Option<Range<text::Anchor>>>>;
27034
27035    fn perform_rename(
27036        &self,
27037        buffer: &Entity<Buffer>,
27038        position: text::Anchor,
27039        new_name: String,
27040        cx: &mut App,
27041    ) -> Option<Task<Result<ProjectTransaction>>>;
27042}
27043
27044pub trait CompletionProvider {
27045    fn completions(
27046        &self,
27047        buffer: &Entity<Buffer>,
27048        buffer_position: text::Anchor,
27049        trigger: CompletionContext,
27050        window: &mut Window,
27051        cx: &mut Context<Editor>,
27052    ) -> Task<Result<Vec<CompletionResponse>>>;
27053
27054    fn resolve_completions(
27055        &self,
27056        _buffer: Entity<Buffer>,
27057        _completion_indices: Vec<usize>,
27058        _completions: Rc<RefCell<Box<[Completion]>>>,
27059        _cx: &mut Context<Editor>,
27060    ) -> Task<Result<bool>> {
27061        Task::ready(Ok(false))
27062    }
27063
27064    fn apply_additional_edits_for_completion(
27065        &self,
27066        _buffer: Entity<Buffer>,
27067        _completions: Rc<RefCell<Box<[Completion]>>>,
27068        _completion_index: usize,
27069        _push_to_history: bool,
27070        _all_commit_ranges: Vec<Range<language::Anchor>>,
27071        _cx: &mut Context<Editor>,
27072    ) -> Task<Result<Option<language::Transaction>>> {
27073        Task::ready(Ok(None))
27074    }
27075
27076    fn is_completion_trigger(
27077        &self,
27078        buffer: &Entity<Buffer>,
27079        position: language::Anchor,
27080        text: &str,
27081        trigger_in_words: bool,
27082        cx: &mut Context<Editor>,
27083    ) -> bool;
27084
27085    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27086
27087    fn sort_completions(&self) -> bool {
27088        true
27089    }
27090
27091    fn filter_completions(&self) -> bool {
27092        true
27093    }
27094
27095    fn show_snippets(&self) -> bool {
27096        false
27097    }
27098}
27099
27100pub trait CodeActionProvider {
27101    fn id(&self) -> Arc<str>;
27102
27103    fn code_actions(
27104        &self,
27105        buffer: &Entity<Buffer>,
27106        range: Range<text::Anchor>,
27107        window: &mut Window,
27108        cx: &mut App,
27109    ) -> Task<Result<Vec<CodeAction>>>;
27110
27111    fn apply_code_action(
27112        &self,
27113        buffer_handle: Entity<Buffer>,
27114        action: CodeAction,
27115        push_to_history: bool,
27116        window: &mut Window,
27117        cx: &mut App,
27118    ) -> Task<Result<ProjectTransaction>>;
27119}
27120
27121impl CodeActionProvider for Entity<Project> {
27122    fn id(&self) -> Arc<str> {
27123        "project".into()
27124    }
27125
27126    fn code_actions(
27127        &self,
27128        buffer: &Entity<Buffer>,
27129        range: Range<text::Anchor>,
27130        _window: &mut Window,
27131        cx: &mut App,
27132    ) -> Task<Result<Vec<CodeAction>>> {
27133        self.update(cx, |project, cx| {
27134            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27135            let code_actions = project.code_actions(buffer, range, None, cx);
27136            cx.background_spawn(async move {
27137                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27138                Ok(code_lens_actions
27139                    .context("code lens fetch")?
27140                    .into_iter()
27141                    .flatten()
27142                    .chain(
27143                        code_actions
27144                            .context("code action fetch")?
27145                            .into_iter()
27146                            .flatten(),
27147                    )
27148                    .collect())
27149            })
27150        })
27151    }
27152
27153    fn apply_code_action(
27154        &self,
27155        buffer_handle: Entity<Buffer>,
27156        action: CodeAction,
27157        push_to_history: bool,
27158        _window: &mut Window,
27159        cx: &mut App,
27160    ) -> Task<Result<ProjectTransaction>> {
27161        self.update(cx, |project, cx| {
27162            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27163        })
27164    }
27165}
27166
27167fn snippet_completions(
27168    project: &Project,
27169    buffer: &Entity<Buffer>,
27170    buffer_anchor: text::Anchor,
27171    classifier: CharClassifier,
27172    cx: &mut App,
27173) -> Task<Result<CompletionResponse>> {
27174    let languages = buffer.read(cx).languages_at(buffer_anchor);
27175    let snippet_store = project.snippets().read(cx);
27176
27177    let scopes: Vec<_> = languages
27178        .iter()
27179        .filter_map(|language| {
27180            let language_name = language.lsp_id();
27181            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27182
27183            if snippets.is_empty() {
27184                None
27185            } else {
27186                Some((language.default_scope(), snippets))
27187            }
27188        })
27189        .collect();
27190
27191    if scopes.is_empty() {
27192        return Task::ready(Ok(CompletionResponse {
27193            completions: vec![],
27194            display_options: CompletionDisplayOptions::default(),
27195            is_incomplete: false,
27196        }));
27197    }
27198
27199    let snapshot = buffer.read(cx).text_snapshot();
27200    let executor = cx.background_executor().clone();
27201
27202    cx.background_spawn(async move {
27203        let is_word_char = |c| classifier.is_word(c);
27204
27205        let mut is_incomplete = false;
27206        let mut completions: Vec<Completion> = Vec::new();
27207
27208        const MAX_PREFIX_LEN: usize = 128;
27209        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27210        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27211        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27212
27213        let max_buffer_window: String = snapshot
27214            .text_for_range(window_start..buffer_offset)
27215            .collect();
27216
27217        if max_buffer_window.is_empty() {
27218            return Ok(CompletionResponse {
27219                completions: vec![],
27220                display_options: CompletionDisplayOptions::default(),
27221                is_incomplete: true,
27222            });
27223        }
27224
27225        for (_scope, snippets) in scopes.into_iter() {
27226            // Sort snippets by word count to match longer snippet prefixes first.
27227            let mut sorted_snippet_candidates = snippets
27228                .iter()
27229                .enumerate()
27230                .flat_map(|(snippet_ix, snippet)| {
27231                    snippet
27232                        .prefix
27233                        .iter()
27234                        .enumerate()
27235                        .map(move |(prefix_ix, prefix)| {
27236                            let word_count =
27237                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27238                            ((snippet_ix, prefix_ix), prefix, word_count)
27239                        })
27240                })
27241                .collect_vec();
27242            sorted_snippet_candidates
27243                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27244
27245            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27246
27247            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27248                .take(
27249                    sorted_snippet_candidates
27250                        .first()
27251                        .map(|(_, _, word_count)| *word_count)
27252                        .unwrap_or_default(),
27253                )
27254                .collect_vec();
27255
27256            const MAX_RESULTS: usize = 100;
27257            // Each match also remembers how many characters from the buffer it consumed
27258            let mut matches: Vec<(StringMatch, usize)> = vec![];
27259
27260            let mut snippet_list_cutoff_index = 0;
27261            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27262                let word_count = buffer_index + 1;
27263                // Increase `snippet_list_cutoff_index` until we have all of the
27264                // snippets with sufficiently many words.
27265                while sorted_snippet_candidates
27266                    .get(snippet_list_cutoff_index)
27267                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27268                        *snippet_word_count >= word_count
27269                    })
27270                {
27271                    snippet_list_cutoff_index += 1;
27272                }
27273
27274                // Take only the candidates with at least `word_count` many words
27275                let snippet_candidates_at_word_len =
27276                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27277
27278                let candidates = snippet_candidates_at_word_len
27279                    .iter()
27280                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27281                    .enumerate() // index in `sorted_snippet_candidates`
27282                    // First char must match
27283                    .filter(|(_ix, prefix)| {
27284                        itertools::equal(
27285                            prefix
27286                                .chars()
27287                                .next()
27288                                .into_iter()
27289                                .flat_map(|c| c.to_lowercase()),
27290                            buffer_window
27291                                .chars()
27292                                .next()
27293                                .into_iter()
27294                                .flat_map(|c| c.to_lowercase()),
27295                        )
27296                    })
27297                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27298                    .collect::<Vec<StringMatchCandidate>>();
27299
27300                matches.extend(
27301                    fuzzy::match_strings(
27302                        &candidates,
27303                        &buffer_window,
27304                        buffer_window.chars().any(|c| c.is_uppercase()),
27305                        true,
27306                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27307                        &Default::default(),
27308                        executor.clone(),
27309                    )
27310                    .await
27311                    .into_iter()
27312                    .map(|string_match| (string_match, buffer_window.len())),
27313                );
27314
27315                if matches.len() >= MAX_RESULTS {
27316                    break;
27317                }
27318            }
27319
27320            let to_lsp = |point: &text::Anchor| {
27321                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27322                point_to_lsp(end)
27323            };
27324            let lsp_end = to_lsp(&buffer_anchor);
27325
27326            if matches.len() >= MAX_RESULTS {
27327                is_incomplete = true;
27328            }
27329
27330            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27331                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27332                    sorted_snippet_candidates[string_match.candidate_id];
27333                let snippet = &snippets[snippet_index];
27334                let start = buffer_offset - buffer_window_len;
27335                let start = snapshot.anchor_before(start);
27336                let range = start..buffer_anchor;
27337                let lsp_start = to_lsp(&start);
27338                let lsp_range = lsp::Range {
27339                    start: lsp_start,
27340                    end: lsp_end,
27341                };
27342                Completion {
27343                    replace_range: range,
27344                    new_text: snippet.body.clone(),
27345                    source: CompletionSource::Lsp {
27346                        insert_range: None,
27347                        server_id: LanguageServerId(usize::MAX),
27348                        resolved: true,
27349                        lsp_completion: Box::new(lsp::CompletionItem {
27350                            label: snippet.prefix.first().unwrap().clone(),
27351                            kind: Some(CompletionItemKind::SNIPPET),
27352                            label_details: snippet.description.as_ref().map(|description| {
27353                                lsp::CompletionItemLabelDetails {
27354                                    detail: Some(description.clone()),
27355                                    description: None,
27356                                }
27357                            }),
27358                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27359                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27360                                lsp::InsertReplaceEdit {
27361                                    new_text: snippet.body.clone(),
27362                                    insert: lsp_range,
27363                                    replace: lsp_range,
27364                                },
27365                            )),
27366                            filter_text: Some(snippet.body.clone()),
27367                            sort_text: Some(char::MAX.to_string()),
27368                            ..lsp::CompletionItem::default()
27369                        }),
27370                        lsp_defaults: None,
27371                    },
27372                    label: CodeLabel {
27373                        text: matching_prefix.clone(),
27374                        runs: Vec::new(),
27375                        filter_range: 0..matching_prefix.len(),
27376                    },
27377                    icon_path: None,
27378                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27379                        single_line: snippet.name.clone().into(),
27380                        plain_text: snippet
27381                            .description
27382                            .clone()
27383                            .map(|description| description.into()),
27384                    }),
27385                    insert_text_mode: None,
27386                    confirm: None,
27387                    match_start: Some(start),
27388                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27389                }
27390            }));
27391        }
27392
27393        Ok(CompletionResponse {
27394            completions,
27395            display_options: CompletionDisplayOptions::default(),
27396            is_incomplete,
27397        })
27398    })
27399}
27400
27401impl CompletionProvider for Entity<Project> {
27402    fn completions(
27403        &self,
27404        buffer: &Entity<Buffer>,
27405        buffer_position: text::Anchor,
27406        options: CompletionContext,
27407        _window: &mut Window,
27408        cx: &mut Context<Editor>,
27409    ) -> Task<Result<Vec<CompletionResponse>>> {
27410        self.update(cx, |project, cx| {
27411            let task = project.completions(buffer, buffer_position, options, cx);
27412            cx.background_spawn(task)
27413        })
27414    }
27415
27416    fn resolve_completions(
27417        &self,
27418        buffer: Entity<Buffer>,
27419        completion_indices: Vec<usize>,
27420        completions: Rc<RefCell<Box<[Completion]>>>,
27421        cx: &mut Context<Editor>,
27422    ) -> Task<Result<bool>> {
27423        self.update(cx, |project, cx| {
27424            project.lsp_store().update(cx, |lsp_store, cx| {
27425                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27426            })
27427        })
27428    }
27429
27430    fn apply_additional_edits_for_completion(
27431        &self,
27432        buffer: Entity<Buffer>,
27433        completions: Rc<RefCell<Box<[Completion]>>>,
27434        completion_index: usize,
27435        push_to_history: bool,
27436        all_commit_ranges: Vec<Range<language::Anchor>>,
27437        cx: &mut Context<Editor>,
27438    ) -> Task<Result<Option<language::Transaction>>> {
27439        self.update(cx, |project, cx| {
27440            project.lsp_store().update(cx, |lsp_store, cx| {
27441                lsp_store.apply_additional_edits_for_completion(
27442                    buffer,
27443                    completions,
27444                    completion_index,
27445                    push_to_history,
27446                    all_commit_ranges,
27447                    cx,
27448                )
27449            })
27450        })
27451    }
27452
27453    fn is_completion_trigger(
27454        &self,
27455        buffer: &Entity<Buffer>,
27456        position: language::Anchor,
27457        text: &str,
27458        trigger_in_words: bool,
27459        cx: &mut Context<Editor>,
27460    ) -> bool {
27461        let mut chars = text.chars();
27462        let char = if let Some(char) = chars.next() {
27463            char
27464        } else {
27465            return false;
27466        };
27467        if chars.next().is_some() {
27468            return false;
27469        }
27470
27471        let buffer = buffer.read(cx);
27472        let snapshot = buffer.snapshot();
27473        let classifier = snapshot
27474            .char_classifier_at(position)
27475            .scope_context(Some(CharScopeContext::Completion));
27476        if trigger_in_words && classifier.is_word(char) {
27477            return true;
27478        }
27479
27480        buffer.completion_triggers().contains(text)
27481    }
27482
27483    fn show_snippets(&self) -> bool {
27484        true
27485    }
27486}
27487
27488impl SemanticsProvider for WeakEntity<Project> {
27489    fn hover(
27490        &self,
27491        buffer: &Entity<Buffer>,
27492        position: text::Anchor,
27493        cx: &mut App,
27494    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27495        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27496            .ok()
27497    }
27498
27499    fn document_highlights(
27500        &self,
27501        buffer: &Entity<Buffer>,
27502        position: text::Anchor,
27503        cx: &mut App,
27504    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27505        self.update(cx, |project, cx| {
27506            project.document_highlights(buffer, position, cx)
27507        })
27508        .ok()
27509    }
27510
27511    fn definitions(
27512        &self,
27513        buffer: &Entity<Buffer>,
27514        position: text::Anchor,
27515        kind: GotoDefinitionKind,
27516        cx: &mut App,
27517    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27518        self.update(cx, |project, cx| match kind {
27519            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27520            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27521            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27522            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27523        })
27524        .ok()
27525    }
27526
27527    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27528        self.update(cx, |project, cx| {
27529            if project
27530                .active_debug_session(cx)
27531                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27532            {
27533                return true;
27534            }
27535
27536            buffer.update(cx, |buffer, cx| {
27537                project.any_language_server_supports_inlay_hints(buffer, cx)
27538            })
27539        })
27540        .unwrap_or(false)
27541    }
27542
27543    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27544        self.update(cx, |project, cx| {
27545            buffer.update(cx, |buffer, cx| {
27546                project.any_language_server_supports_semantic_tokens(buffer, cx)
27547            })
27548        })
27549        .unwrap_or(false)
27550    }
27551
27552    fn inline_values(
27553        &self,
27554        buffer_handle: Entity<Buffer>,
27555        range: Range<text::Anchor>,
27556        cx: &mut App,
27557    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27558        self.update(cx, |project, cx| {
27559            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27560
27561            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27562        })
27563        .ok()
27564        .flatten()
27565    }
27566
27567    fn applicable_inlay_chunks(
27568        &self,
27569        buffer: &Entity<Buffer>,
27570        ranges: &[Range<text::Anchor>],
27571        cx: &mut App,
27572    ) -> Vec<Range<BufferRow>> {
27573        self.update(cx, |project, cx| {
27574            project.lsp_store().update(cx, |lsp_store, cx| {
27575                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27576            })
27577        })
27578        .unwrap_or_default()
27579    }
27580
27581    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27582        self.update(cx, |project, cx| {
27583            project.lsp_store().update(cx, |lsp_store, _| {
27584                lsp_store.invalidate_inlay_hints(for_buffers)
27585            })
27586        })
27587        .ok();
27588    }
27589
27590    fn inlay_hints(
27591        &self,
27592        invalidate: InvalidationStrategy,
27593        buffer: Entity<Buffer>,
27594        ranges: Vec<Range<text::Anchor>>,
27595        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27596        cx: &mut App,
27597    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27598        self.update(cx, |project, cx| {
27599            project.lsp_store().update(cx, |lsp_store, cx| {
27600                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27601            })
27602        })
27603        .ok()
27604    }
27605
27606    fn semantic_tokens(
27607        &self,
27608        buffer: Entity<Buffer>,
27609        refresh: Option<RefreshForServer>,
27610        cx: &mut App,
27611    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27612        self.update(cx, |this, cx| {
27613            this.lsp_store().update(cx, |lsp_store, cx| {
27614                lsp_store.semantic_tokens(buffer, refresh, cx)
27615            })
27616        })
27617        .ok()
27618    }
27619
27620    fn range_for_rename(
27621        &self,
27622        buffer: &Entity<Buffer>,
27623        position: text::Anchor,
27624        cx: &mut App,
27625    ) -> Task<Result<Option<Range<text::Anchor>>>> {
27626        let Some(this) = self.upgrade() else {
27627            return Task::ready(Ok(None));
27628        };
27629
27630        this.update(cx, |project, cx| {
27631            let buffer = buffer.clone();
27632            let task = project.prepare_rename(buffer.clone(), position, cx);
27633            cx.spawn(async move |_, cx| {
27634                Ok(match task.await? {
27635                    PrepareRenameResponse::Success(range) => Some(range),
27636                    PrepareRenameResponse::InvalidPosition => None,
27637                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27638                        // Fallback on using TreeSitter info to determine identifier range
27639                        buffer.read_with(cx, |buffer, _| {
27640                            let snapshot = buffer.snapshot();
27641                            let (range, kind) = snapshot.surrounding_word(position, None);
27642                            if kind != Some(CharKind::Word) {
27643                                return None;
27644                            }
27645                            Some(
27646                                snapshot.anchor_before(range.start)
27647                                    ..snapshot.anchor_after(range.end),
27648                            )
27649                        })
27650                    }
27651                })
27652            })
27653        })
27654    }
27655
27656    fn perform_rename(
27657        &self,
27658        buffer: &Entity<Buffer>,
27659        position: text::Anchor,
27660        new_name: String,
27661        cx: &mut App,
27662    ) -> Option<Task<Result<ProjectTransaction>>> {
27663        self.update(cx, |project, cx| {
27664            project.perform_rename(buffer.clone(), position, new_name, cx)
27665        })
27666        .ok()
27667    }
27668}
27669
27670fn consume_contiguous_rows(
27671    contiguous_row_selections: &mut Vec<Selection<Point>>,
27672    selection: &Selection<Point>,
27673    display_map: &DisplaySnapshot,
27674    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27675) -> (MultiBufferRow, MultiBufferRow) {
27676    contiguous_row_selections.push(selection.clone());
27677    let start_row = starting_row(selection, display_map);
27678    let mut end_row = ending_row(selection, display_map);
27679
27680    while let Some(next_selection) = selections.peek() {
27681        if next_selection.start.row <= end_row.0 {
27682            end_row = ending_row(next_selection, display_map);
27683            contiguous_row_selections.push(selections.next().unwrap().clone());
27684        } else {
27685            break;
27686        }
27687    }
27688    (start_row, end_row)
27689}
27690
27691fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27692    if selection.start.column > 0 {
27693        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27694    } else {
27695        MultiBufferRow(selection.start.row)
27696    }
27697}
27698
27699fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27700    if next_selection.end.column > 0 || next_selection.is_empty() {
27701        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27702    } else {
27703        MultiBufferRow(next_selection.end.row)
27704    }
27705}
27706
27707impl EditorSnapshot {
27708    pub fn remote_selections_in_range<'a>(
27709        &'a self,
27710        range: &'a Range<Anchor>,
27711        collaboration_hub: &dyn CollaborationHub,
27712        cx: &'a App,
27713    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27714        let participant_names = collaboration_hub.user_names(cx);
27715        let participant_indices = collaboration_hub.user_participant_indices(cx);
27716        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27717        let collaborators_by_replica_id = collaborators_by_peer_id
27718            .values()
27719            .map(|collaborator| (collaborator.replica_id, collaborator))
27720            .collect::<HashMap<_, _>>();
27721        self.buffer_snapshot()
27722            .selections_in_range(range, false)
27723            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27724                if replica_id == ReplicaId::AGENT {
27725                    Some(RemoteSelection {
27726                        replica_id,
27727                        selection,
27728                        cursor_shape,
27729                        line_mode,
27730                        collaborator_id: CollaboratorId::Agent,
27731                        user_name: Some("Agent".into()),
27732                        color: cx.theme().players().agent(),
27733                    })
27734                } else {
27735                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27736                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27737                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27738                    Some(RemoteSelection {
27739                        replica_id,
27740                        selection,
27741                        cursor_shape,
27742                        line_mode,
27743                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27744                        user_name,
27745                        color: if let Some(index) = participant_index {
27746                            cx.theme().players().color_for_participant(index.0)
27747                        } else {
27748                            cx.theme().players().absent()
27749                        },
27750                    })
27751                }
27752            })
27753    }
27754
27755    pub fn hunks_for_ranges(
27756        &self,
27757        ranges: impl IntoIterator<Item = Range<Point>>,
27758    ) -> Vec<MultiBufferDiffHunk> {
27759        let mut hunks = Vec::new();
27760        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27761            HashMap::default();
27762        for query_range in ranges {
27763            let query_rows =
27764                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27765            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27766                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27767            ) {
27768                // Include deleted hunks that are adjacent to the query range, because
27769                // otherwise they would be missed.
27770                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27771                if hunk.status().is_deleted() {
27772                    intersects_range |= hunk.row_range.start == query_rows.end;
27773                    intersects_range |= hunk.row_range.end == query_rows.start;
27774                }
27775                if intersects_range {
27776                    if !processed_buffer_rows
27777                        .entry(hunk.buffer_id)
27778                        .or_default()
27779                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27780                    {
27781                        continue;
27782                    }
27783                    hunks.push(hunk);
27784                }
27785            }
27786        }
27787
27788        hunks
27789    }
27790
27791    fn display_diff_hunks_for_rows<'a>(
27792        &'a self,
27793        display_rows: Range<DisplayRow>,
27794        folded_buffers: &'a HashSet<BufferId>,
27795    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27796        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27797        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27798
27799        self.buffer_snapshot()
27800            .diff_hunks_in_range(buffer_start..buffer_end)
27801            .filter_map(|hunk| {
27802                if folded_buffers.contains(&hunk.buffer_id)
27803                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27804                {
27805                    return None;
27806                }
27807
27808                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27809                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27810                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27811                    let line_len = self.buffer_snapshot().line_len(last_row);
27812                    Point::new(last_row.0, line_len)
27813                } else {
27814                    Point::new(hunk.row_range.end.0, 0)
27815                };
27816
27817                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27818                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27819
27820                let display_hunk = if hunk_display_start.column() != 0 {
27821                    DisplayDiffHunk::Folded {
27822                        display_row: hunk_display_start.row(),
27823                    }
27824                } else {
27825                    let mut end_row = hunk_display_end.row();
27826                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27827                        end_row.0 += 1;
27828                    }
27829                    let is_created_file = hunk.is_created_file();
27830                    let multi_buffer_range = hunk.multi_buffer_range.clone();
27831
27832                    DisplayDiffHunk::Unfolded {
27833                        status: hunk.status(),
27834                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27835                            ..hunk.diff_base_byte_range.end.0,
27836                        word_diffs: hunk.word_diffs,
27837                        display_row_range: hunk_display_start.row()..end_row,
27838                        multi_buffer_range,
27839                        is_created_file,
27840                    }
27841                };
27842
27843                Some(display_hunk)
27844            })
27845    }
27846
27847    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27848        self.display_snapshot
27849            .buffer_snapshot()
27850            .language_at(position)
27851    }
27852
27853    pub fn is_focused(&self) -> bool {
27854        self.is_focused
27855    }
27856
27857    pub fn placeholder_text(&self) -> Option<String> {
27858        self.placeholder_display_snapshot
27859            .as_ref()
27860            .map(|display_map| display_map.text())
27861    }
27862
27863    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27864        self.scroll_anchor.scroll_position(&self.display_snapshot)
27865    }
27866
27867    pub fn gutter_dimensions(
27868        &self,
27869        font_id: FontId,
27870        font_size: Pixels,
27871        style: &EditorStyle,
27872        window: &mut Window,
27873        cx: &App,
27874    ) -> GutterDimensions {
27875        if self.show_gutter
27876            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27877            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27878        {
27879            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27880                matches!(
27881                    ProjectSettings::get_global(cx).git.git_gutter,
27882                    GitGutterSetting::TrackedFiles
27883                )
27884            });
27885            let gutter_settings = EditorSettings::get_global(cx).gutter;
27886            let show_line_numbers = self
27887                .show_line_numbers
27888                .unwrap_or(gutter_settings.line_numbers);
27889            let line_gutter_width = if show_line_numbers {
27890                // Avoid flicker-like gutter resizes when the line number gains another digit by
27891                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27892                let min_width_for_number_on_gutter =
27893                    ch_advance * gutter_settings.min_line_number_digits as f32;
27894                self.max_line_number_width(style, window)
27895                    .max(min_width_for_number_on_gutter)
27896            } else {
27897                0.0.into()
27898            };
27899
27900            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27901            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27902
27903            let git_blame_entries_width =
27904                self.git_blame_gutter_max_author_length
27905                    .map(|max_author_length| {
27906                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27907                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27908
27909                        /// The number of characters to dedicate to gaps and margins.
27910                        const SPACING_WIDTH: usize = 4;
27911
27912                        let max_char_count = max_author_length.min(renderer.max_author_length())
27913                            + ::git::SHORT_SHA_LENGTH
27914                            + MAX_RELATIVE_TIMESTAMP.len()
27915                            + SPACING_WIDTH;
27916
27917                        ch_advance * max_char_count
27918                    });
27919
27920            let is_singleton = self.buffer_snapshot().is_singleton();
27921
27922            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27923            left_padding += if !is_singleton {
27924                ch_width * 4.0
27925            } else if show_runnables || show_breakpoints {
27926                ch_width * 3.0
27927            } else if show_git_gutter && show_line_numbers {
27928                ch_width * 2.0
27929            } else if show_git_gutter || show_line_numbers {
27930                ch_width
27931            } else {
27932                px(0.)
27933            };
27934
27935            let shows_folds = is_singleton && gutter_settings.folds;
27936
27937            let right_padding = if shows_folds && show_line_numbers {
27938                ch_width * 4.0
27939            } else if shows_folds || (!is_singleton && show_line_numbers) {
27940                ch_width * 3.0
27941            } else if show_line_numbers {
27942                ch_width
27943            } else {
27944                px(0.)
27945            };
27946
27947            GutterDimensions {
27948                left_padding,
27949                right_padding,
27950                width: line_gutter_width + left_padding + right_padding,
27951                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27952                git_blame_entries_width,
27953            }
27954        } else if self.offset_content {
27955            GutterDimensions::default_with_margin(font_id, font_size, cx)
27956        } else {
27957            GutterDimensions::default()
27958        }
27959    }
27960
27961    pub fn render_crease_toggle(
27962        &self,
27963        buffer_row: MultiBufferRow,
27964        row_contains_cursor: bool,
27965        editor: Entity<Editor>,
27966        window: &mut Window,
27967        cx: &mut App,
27968    ) -> Option<AnyElement> {
27969        let folded = self.is_line_folded(buffer_row);
27970        let mut is_foldable = false;
27971
27972        if let Some(crease) = self
27973            .crease_snapshot
27974            .query_row(buffer_row, self.buffer_snapshot())
27975        {
27976            is_foldable = true;
27977            match crease {
27978                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27979                    if let Some(render_toggle) = render_toggle {
27980                        let toggle_callback =
27981                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27982                                if folded {
27983                                    editor.update(cx, |editor, cx| {
27984                                        editor.fold_at(buffer_row, window, cx)
27985                                    });
27986                                } else {
27987                                    editor.update(cx, |editor, cx| {
27988                                        editor.unfold_at(buffer_row, window, cx)
27989                                    });
27990                                }
27991                            });
27992                        return Some((render_toggle)(
27993                            buffer_row,
27994                            folded,
27995                            toggle_callback,
27996                            window,
27997                            cx,
27998                        ));
27999                    }
28000                }
28001            }
28002        }
28003
28004        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28005
28006        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28007            Some(
28008                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28009                    .toggle_state(folded)
28010                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28011                        if folded {
28012                            this.unfold_at(buffer_row, window, cx);
28013                        } else {
28014                            this.fold_at(buffer_row, window, cx);
28015                        }
28016                    }))
28017                    .into_any_element(),
28018            )
28019        } else {
28020            None
28021        }
28022    }
28023
28024    pub fn render_crease_trailer(
28025        &self,
28026        buffer_row: MultiBufferRow,
28027        window: &mut Window,
28028        cx: &mut App,
28029    ) -> Option<AnyElement> {
28030        let folded = self.is_line_folded(buffer_row);
28031        if let Crease::Inline { render_trailer, .. } = self
28032            .crease_snapshot
28033            .query_row(buffer_row, self.buffer_snapshot())?
28034        {
28035            let render_trailer = render_trailer.as_ref()?;
28036            Some(render_trailer(buffer_row, folded, window, cx))
28037        } else {
28038            None
28039        }
28040    }
28041
28042    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28043        let digit_count = self.widest_line_number().ilog10() + 1;
28044        column_pixels(style, digit_count as usize, window)
28045    }
28046
28047    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28048    ///
28049    /// This is positive if `base` is before `line`.
28050    fn relative_line_delta(
28051        &self,
28052        current_selection_head: DisplayRow,
28053        first_visible_row: DisplayRow,
28054        consider_wrapped_lines: bool,
28055    ) -> i64 {
28056        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28057        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28058
28059        if consider_wrapped_lines {
28060            let wrap_snapshot = self.wrap_snapshot();
28061            let base_wrap_row = wrap_snapshot
28062                .make_wrap_point(current_selection_head, Bias::Left)
28063                .row();
28064            let wrap_row = wrap_snapshot
28065                .make_wrap_point(first_visible_row, Bias::Left)
28066                .row();
28067
28068            wrap_row.0 as i64 - base_wrap_row.0 as i64
28069        } else {
28070            let fold_snapshot = self.fold_snapshot();
28071            let base_fold_row = fold_snapshot
28072                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28073                .row();
28074            let fold_row = fold_snapshot
28075                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28076                .row();
28077
28078            fold_row as i64 - base_fold_row as i64
28079        }
28080    }
28081
28082    /// Returns the unsigned relative line number to display for each row in `rows`.
28083    ///
28084    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28085    pub fn calculate_relative_line_numbers(
28086        &self,
28087        rows: &Range<DisplayRow>,
28088        current_selection_head: DisplayRow,
28089        count_wrapped_lines: bool,
28090    ) -> HashMap<DisplayRow, u32> {
28091        let initial_offset =
28092            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28093
28094        self.row_infos(rows.start)
28095            .take(rows.len())
28096            .enumerate()
28097            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28098            .filter(|(_row, row_info)| {
28099                row_info.buffer_row.is_some()
28100                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28101            })
28102            .enumerate()
28103            .filter_map(|(i, (row, row_info))| {
28104                // We want to ensure here that the current line has absolute
28105                // numbering, even if we are in a soft-wrapped line. With the
28106                // exception that if we are in a deleted line, we should number this
28107                // relative with 0, as otherwise it would have no line number at all
28108                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28109
28110                (relative_line_number != 0
28111                    || row_info
28112                        .diff_status
28113                        .is_some_and(|status| status.is_deleted()))
28114                .then_some((row, relative_line_number))
28115            })
28116            .collect()
28117    }
28118}
28119
28120pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28121    let font_size = style.text.font_size.to_pixels(window.rem_size());
28122    let layout = window.text_system().shape_line(
28123        SharedString::from(" ".repeat(column)),
28124        font_size,
28125        &[TextRun {
28126            len: column,
28127            font: style.text.font(),
28128            color: Hsla::default(),
28129            ..Default::default()
28130        }],
28131        None,
28132    );
28133
28134    layout.width
28135}
28136
28137impl Deref for EditorSnapshot {
28138    type Target = DisplaySnapshot;
28139
28140    fn deref(&self) -> &Self::Target {
28141        &self.display_snapshot
28142    }
28143}
28144
28145#[derive(Clone, Debug, PartialEq, Eq)]
28146pub enum EditorEvent {
28147    /// Emitted when the stored review comments change (added, removed, or updated).
28148    ReviewCommentsChanged {
28149        /// The new total count of review comments.
28150        total_count: usize,
28151    },
28152    InputIgnored {
28153        text: Arc<str>,
28154    },
28155    InputHandled {
28156        utf16_range_to_replace: Option<Range<isize>>,
28157        text: Arc<str>,
28158    },
28159    BufferRangesUpdated {
28160        buffer: Entity<Buffer>,
28161        path_key: PathKey,
28162        ranges: Vec<ExcerptRange<text::Anchor>>,
28163    },
28164    BuffersRemoved {
28165        removed_buffer_ids: Vec<BufferId>,
28166    },
28167    BuffersEdited {
28168        buffer_ids: Vec<BufferId>,
28169    },
28170    BufferFoldToggled {
28171        ids: Vec<BufferId>,
28172        folded: bool,
28173    },
28174    ExpandExcerptsRequested {
28175        excerpt_anchors: Vec<Anchor>,
28176        lines: u32,
28177        direction: ExpandExcerptDirection,
28178    },
28179    StageOrUnstageRequested {
28180        stage: bool,
28181        hunks: Vec<MultiBufferDiffHunk>,
28182    },
28183    OpenExcerptsRequested {
28184        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28185        split: bool,
28186    },
28187    RestoreRequested {
28188        hunks: Vec<MultiBufferDiffHunk>,
28189    },
28190    BufferEdited,
28191    Edited {
28192        transaction_id: clock::Lamport,
28193    },
28194    Reparsed(BufferId),
28195    Focused,
28196    FocusedIn,
28197    Blurred,
28198    DirtyChanged,
28199    Saved,
28200    TitleChanged,
28201    SelectionsChanged {
28202        local: bool,
28203    },
28204    ScrollPositionChanged {
28205        local: bool,
28206        autoscroll: bool,
28207    },
28208    TransactionUndone {
28209        transaction_id: clock::Lamport,
28210    },
28211    TransactionBegun {
28212        transaction_id: clock::Lamport,
28213    },
28214    CursorShapeChanged,
28215    BreadcrumbsChanged,
28216    OutlineSymbolsChanged,
28217    PushedToNavHistory {
28218        anchor: Anchor,
28219        is_deactivate: bool,
28220    },
28221}
28222
28223impl EventEmitter<EditorEvent> for Editor {}
28224
28225impl Focusable for Editor {
28226    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28227        self.focus_handle.clone()
28228    }
28229}
28230
28231impl Render for Editor {
28232    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28233        EditorElement::new(&cx.entity(), self.create_style(cx))
28234    }
28235}
28236
28237impl EntityInputHandler for Editor {
28238    fn text_for_range(
28239        &mut self,
28240        range_utf16: Range<usize>,
28241        adjusted_range: &mut Option<Range<usize>>,
28242        _: &mut Window,
28243        cx: &mut Context<Self>,
28244    ) -> Option<String> {
28245        let snapshot = self.buffer.read(cx).read(cx);
28246        let start = snapshot.clip_offset_utf16(
28247            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28248            Bias::Left,
28249        );
28250        let end = snapshot.clip_offset_utf16(
28251            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28252            Bias::Right,
28253        );
28254        if (start.0.0..end.0.0) != range_utf16 {
28255            adjusted_range.replace(start.0.0..end.0.0);
28256        }
28257        Some(snapshot.text_for_range(start..end).collect())
28258    }
28259
28260    fn selected_text_range(
28261        &mut self,
28262        ignore_disabled_input: bool,
28263        _: &mut Window,
28264        cx: &mut Context<Self>,
28265    ) -> Option<UTF16Selection> {
28266        // Prevent the IME menu from appearing when holding down an alphabetic key
28267        // while input is disabled.
28268        if !ignore_disabled_input && !self.input_enabled {
28269            return None;
28270        }
28271
28272        let selection = self
28273            .selections
28274            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28275        let range = selection.range();
28276
28277        Some(UTF16Selection {
28278            range: range.start.0.0..range.end.0.0,
28279            reversed: selection.reversed,
28280        })
28281    }
28282
28283    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28284        let snapshot = self.buffer.read(cx).read(cx);
28285        let range = self
28286            .text_highlights(HighlightKey::InputComposition, cx)?
28287            .1
28288            .first()?;
28289        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28290    }
28291
28292    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28293        self.clear_highlights(HighlightKey::InputComposition, cx);
28294        self.ime_transaction.take();
28295    }
28296
28297    fn replace_text_in_range(
28298        &mut self,
28299        range_utf16: Option<Range<usize>>,
28300        text: &str,
28301        window: &mut Window,
28302        cx: &mut Context<Self>,
28303    ) {
28304        if !self.input_enabled {
28305            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28306            return;
28307        }
28308
28309        self.transact(window, cx, |this, window, cx| {
28310            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28311                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28312                    // During IME composition, macOS reports the replacement range
28313                    // relative to the first marked region (the only one visible via
28314                    // marked_text_range). The correct targets for replacement are the
28315                    // marked ranges themselves — one per cursor — so use them directly.
28316                    Some(marked_ranges)
28317                } else if range_utf16.start == range_utf16.end {
28318                    // An empty replacement range means "insert at cursor" with no text
28319                    // to replace. macOS reports the cursor position from its own
28320                    // (single-cursor) view of the buffer, which diverges from our actual
28321                    // cursor positions after multi-cursor edits have shifted offsets.
28322                    // Treating this as range_utf16=None lets each cursor insert in place.
28323                    None
28324                } else {
28325                    // Outside of IME composition (e.g. Accessibility Keyboard word
28326                    // completion), the range is an absolute document offset for the
28327                    // newest cursor. Fan it out to all cursors via
28328                    // selection_replacement_ranges, which applies the delta relative
28329                    // to the newest selection to every cursor.
28330                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28331                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28332                    Some(this.selection_replacement_ranges(range_utf16, cx))
28333                }
28334            } else {
28335                this.marked_text_ranges(cx)
28336            };
28337
28338            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28339                let newest_selection_id = this.selections.newest_anchor().id;
28340                this.selections
28341                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28342                    .iter()
28343                    .zip(ranges_to_replace.iter())
28344                    .find_map(|(selection, range)| {
28345                        if selection.id == newest_selection_id {
28346                            Some(
28347                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28348                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28349                            )
28350                        } else {
28351                            None
28352                        }
28353                    })
28354            });
28355
28356            cx.emit(EditorEvent::InputHandled {
28357                utf16_range_to_replace: range_to_replace,
28358                text: text.into(),
28359            });
28360
28361            if let Some(new_selected_ranges) = new_selected_ranges {
28362                // Only backspace if at least one range covers actual text. When all
28363                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28364                // Keyboard sends replacementRange=cursor..cursor), backspace would
28365                // incorrectly delete the character just before the cursor.
28366                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28367                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28368                    selections.select_ranges(new_selected_ranges)
28369                });
28370                if should_backspace {
28371                    this.backspace(&Default::default(), window, cx);
28372                }
28373            }
28374
28375            this.handle_input(text, window, cx);
28376        });
28377
28378        if let Some(transaction) = self.ime_transaction {
28379            self.buffer.update(cx, |buffer, cx| {
28380                buffer.group_until_transaction(transaction, cx);
28381            });
28382        }
28383
28384        self.unmark_text(window, cx);
28385    }
28386
28387    fn replace_and_mark_text_in_range(
28388        &mut self,
28389        range_utf16: Option<Range<usize>>,
28390        text: &str,
28391        new_selected_range_utf16: Option<Range<usize>>,
28392        window: &mut Window,
28393        cx: &mut Context<Self>,
28394    ) {
28395        if !self.input_enabled {
28396            return;
28397        }
28398
28399        let transaction = self.transact(window, cx, |this, window, cx| {
28400            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28401                let snapshot = this.buffer.read(cx).read(cx);
28402                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28403                    for marked_range in &mut marked_ranges {
28404                        marked_range.end = marked_range.start + relative_range_utf16.end;
28405                        marked_range.start += relative_range_utf16.start;
28406                        marked_range.start =
28407                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28408                        marked_range.end =
28409                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28410                    }
28411                }
28412                Some(marked_ranges)
28413            } else if let Some(range_utf16) = range_utf16 {
28414                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28415                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28416                Some(this.selection_replacement_ranges(range_utf16, cx))
28417            } else {
28418                None
28419            };
28420
28421            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28422                let newest_selection_id = this.selections.newest_anchor().id;
28423                this.selections
28424                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28425                    .iter()
28426                    .zip(ranges_to_replace.iter())
28427                    .find_map(|(selection, range)| {
28428                        if selection.id == newest_selection_id {
28429                            Some(
28430                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28431                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28432                            )
28433                        } else {
28434                            None
28435                        }
28436                    })
28437            });
28438
28439            cx.emit(EditorEvent::InputHandled {
28440                utf16_range_to_replace: range_to_replace,
28441                text: text.into(),
28442            });
28443
28444            if let Some(ranges) = ranges_to_replace {
28445                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28446                    s.select_ranges(ranges)
28447                });
28448            }
28449
28450            let marked_ranges = {
28451                let snapshot = this.buffer.read(cx).read(cx);
28452                this.selections
28453                    .disjoint_anchors_arc()
28454                    .iter()
28455                    .map(|selection| {
28456                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28457                    })
28458                    .collect::<Vec<_>>()
28459            };
28460
28461            if text.is_empty() {
28462                this.unmark_text(window, cx);
28463            } else {
28464                this.highlight_text(
28465                    HighlightKey::InputComposition,
28466                    marked_ranges.clone(),
28467                    HighlightStyle {
28468                        underline: Some(UnderlineStyle {
28469                            thickness: px(1.),
28470                            color: None,
28471                            wavy: false,
28472                        }),
28473                        ..Default::default()
28474                    },
28475                    cx,
28476                );
28477            }
28478
28479            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28480            let use_autoclose = this.use_autoclose;
28481            let use_auto_surround = this.use_auto_surround;
28482            this.set_use_autoclose(false);
28483            this.set_use_auto_surround(false);
28484            this.handle_input(text, window, cx);
28485            this.set_use_autoclose(use_autoclose);
28486            this.set_use_auto_surround(use_auto_surround);
28487
28488            if let Some(new_selected_range) = new_selected_range_utf16 {
28489                let snapshot = this.buffer.read(cx).read(cx);
28490                let new_selected_ranges = marked_ranges
28491                    .into_iter()
28492                    .map(|marked_range| {
28493                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28494                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28495                            insertion_start.0 + new_selected_range.start,
28496                        ));
28497                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28498                            insertion_start.0 + new_selected_range.end,
28499                        ));
28500                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28501                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28502                    })
28503                    .collect::<Vec<_>>();
28504
28505                drop(snapshot);
28506                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28507                    selections.select_ranges(new_selected_ranges)
28508                });
28509            }
28510        });
28511
28512        self.ime_transaction = self.ime_transaction.or(transaction);
28513        if let Some(transaction) = self.ime_transaction {
28514            self.buffer.update(cx, |buffer, cx| {
28515                buffer.group_until_transaction(transaction, cx);
28516            });
28517        }
28518
28519        if self
28520            .text_highlights(HighlightKey::InputComposition, cx)
28521            .is_none()
28522        {
28523            self.ime_transaction.take();
28524        }
28525    }
28526
28527    fn bounds_for_range(
28528        &mut self,
28529        range_utf16: Range<usize>,
28530        element_bounds: gpui::Bounds<Pixels>,
28531        window: &mut Window,
28532        cx: &mut Context<Self>,
28533    ) -> Option<gpui::Bounds<Pixels>> {
28534        let text_layout_details = self.text_layout_details(window, cx);
28535        let CharacterDimensions {
28536            em_width,
28537            em_advance,
28538            line_height,
28539        } = self.character_dimensions(window, cx);
28540
28541        let snapshot = self.snapshot(window, cx);
28542        let scroll_position = snapshot.scroll_position();
28543        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28544
28545        let start =
28546            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28547        let x = Pixels::from(
28548            ScrollOffset::from(
28549                snapshot.x_for_display_point(start, &text_layout_details)
28550                    + self.gutter_dimensions.full_width(),
28551            ) - scroll_left,
28552        );
28553        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28554
28555        Some(Bounds {
28556            origin: element_bounds.origin + point(x, y),
28557            size: size(em_width, line_height),
28558        })
28559    }
28560
28561    fn character_index_for_point(
28562        &mut self,
28563        point: gpui::Point<Pixels>,
28564        _window: &mut Window,
28565        _cx: &mut Context<Self>,
28566    ) -> Option<usize> {
28567        let position_map = self.last_position_map.as_ref()?;
28568        if !position_map.text_hitbox.contains(&point) {
28569            return None;
28570        }
28571        let display_point = position_map.point_for_position(point).previous_valid;
28572        let anchor = position_map
28573            .snapshot
28574            .display_point_to_anchor(display_point, Bias::Left);
28575        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28576        Some(utf16_offset.0.0)
28577    }
28578
28579    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28580        self.expects_character_input
28581    }
28582}
28583
28584trait SelectionExt {
28585    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28586    fn spanned_rows(
28587        &self,
28588        include_end_if_at_line_start: bool,
28589        map: &DisplaySnapshot,
28590    ) -> Range<MultiBufferRow>;
28591}
28592
28593impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28594    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28595        let start = self
28596            .start
28597            .to_point(map.buffer_snapshot())
28598            .to_display_point(map);
28599        let end = self
28600            .end
28601            .to_point(map.buffer_snapshot())
28602            .to_display_point(map);
28603        if self.reversed {
28604            end..start
28605        } else {
28606            start..end
28607        }
28608    }
28609
28610    fn spanned_rows(
28611        &self,
28612        include_end_if_at_line_start: bool,
28613        map: &DisplaySnapshot,
28614    ) -> Range<MultiBufferRow> {
28615        let start = self.start.to_point(map.buffer_snapshot());
28616        let mut end = self.end.to_point(map.buffer_snapshot());
28617        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28618            end.row -= 1;
28619        }
28620
28621        let buffer_start = map.prev_line_boundary(start).0;
28622        let buffer_end = map.next_line_boundary(end).0;
28623        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28624    }
28625}
28626
28627impl<T: InvalidationRegion> InvalidationStack<T> {
28628    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28629    where
28630        S: Clone + ToOffset,
28631    {
28632        while let Some(region) = self.last() {
28633            let all_selections_inside_invalidation_ranges =
28634                if selections.len() == region.ranges().len() {
28635                    selections
28636                        .iter()
28637                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28638                        .all(|(selection, invalidation_range)| {
28639                            let head = selection.head().to_offset(buffer);
28640                            invalidation_range.start <= head && invalidation_range.end >= head
28641                        })
28642                } else {
28643                    false
28644                };
28645
28646            if all_selections_inside_invalidation_ranges {
28647                break;
28648            } else {
28649                self.pop();
28650            }
28651        }
28652    }
28653}
28654
28655#[derive(Clone)]
28656struct ErasedEditorImpl(Entity<Editor>);
28657
28658impl ui_input::ErasedEditor for ErasedEditorImpl {
28659    fn text(&self, cx: &App) -> String {
28660        self.0.read(cx).text(cx)
28661    }
28662
28663    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28664        self.0.update(cx, |this, cx| {
28665            this.set_text(text, window, cx);
28666        })
28667    }
28668
28669    fn clear(&self, window: &mut Window, cx: &mut App) {
28670        self.0.update(cx, |this, cx| this.clear(window, cx));
28671    }
28672
28673    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28674        self.0.update(cx, |this, cx| {
28675            this.set_placeholder_text(text, window, cx);
28676        });
28677    }
28678
28679    fn focus_handle(&self, cx: &App) -> FocusHandle {
28680        self.0.read(cx).focus_handle(cx)
28681    }
28682
28683    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28684        let settings = ThemeSettings::get_global(cx);
28685        let theme_color = cx.theme().colors();
28686
28687        let text_style = TextStyle {
28688            font_family: settings.ui_font.family.clone(),
28689            font_features: settings.ui_font.features.clone(),
28690            font_size: rems(0.875).into(),
28691            font_weight: settings.ui_font.weight,
28692            font_style: FontStyle::Normal,
28693            line_height: relative(1.2),
28694            color: theme_color.text,
28695            ..Default::default()
28696        };
28697        let editor_style = EditorStyle {
28698            background: theme_color.ghost_element_background,
28699            local_player: cx.theme().players().local(),
28700            syntax: cx.theme().syntax().clone(),
28701            text: text_style,
28702            ..Default::default()
28703        };
28704        EditorElement::new(&self.0, editor_style).into_any()
28705    }
28706
28707    fn as_any(&self) -> &dyn Any {
28708        &self.0
28709    }
28710
28711    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28712        self.0.update(cx, |editor, cx| {
28713            let editor_offset = editor.buffer().read(cx).len(cx);
28714            editor.change_selections(
28715                SelectionEffects::scroll(Autoscroll::Next),
28716                window,
28717                cx,
28718                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28719            );
28720        });
28721    }
28722
28723    fn subscribe(
28724        &self,
28725        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28726        window: &mut Window,
28727        cx: &mut App,
28728    ) -> Subscription {
28729        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28730            let event = match event {
28731                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28732                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28733                _ => return,
28734            };
28735            (callback)(event, window, cx);
28736        })
28737    }
28738
28739    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28740        self.0.update(cx, |editor, cx| {
28741            editor.set_masked(masked, cx);
28742        });
28743    }
28744}
28745impl<T> Default for InvalidationStack<T> {
28746    fn default() -> Self {
28747        Self(Default::default())
28748    }
28749}
28750
28751impl<T> Deref for InvalidationStack<T> {
28752    type Target = Vec<T>;
28753
28754    fn deref(&self) -> &Self::Target {
28755        &self.0
28756    }
28757}
28758
28759impl<T> DerefMut for InvalidationStack<T> {
28760    fn deref_mut(&mut self) -> &mut Self::Target {
28761        &mut self.0
28762    }
28763}
28764
28765impl InvalidationRegion for SnippetState {
28766    fn ranges(&self) -> &[Range<Anchor>] {
28767        &self.ranges[self.active_index]
28768    }
28769}
28770
28771fn edit_prediction_edit_text(
28772    current_snapshot: &BufferSnapshot,
28773    edits: &[(Range<Anchor>, impl AsRef<str>)],
28774    edit_preview: &EditPreview,
28775    include_deletions: bool,
28776    multibuffer_snapshot: &MultiBufferSnapshot,
28777    cx: &App,
28778) -> HighlightedText {
28779    let edits = edits
28780        .iter()
28781        .filter_map(|(anchor, text)| {
28782            Some((
28783                multibuffer_snapshot
28784                    .anchor_range_to_buffer_anchor_range(anchor.clone())?
28785                    .1,
28786                text,
28787            ))
28788        })
28789        .collect::<Vec<_>>();
28790
28791    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28792}
28793
28794fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28795    // Fallback for providers that don't provide edit_preview (like Copilot)
28796    // Just show the raw edit text with basic styling
28797    let mut text = String::new();
28798    let mut highlights = Vec::new();
28799
28800    let insertion_highlight_style = HighlightStyle {
28801        color: Some(cx.theme().colors().text),
28802        ..Default::default()
28803    };
28804
28805    for (_, edit_text) in edits {
28806        let start_offset = text.len();
28807        text.push_str(edit_text);
28808        let end_offset = text.len();
28809
28810        if start_offset < end_offset {
28811            highlights.push((start_offset..end_offset, insertion_highlight_style));
28812        }
28813    }
28814
28815    HighlightedText {
28816        text: text.into(),
28817        highlights,
28818    }
28819}
28820
28821pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28822    match severity {
28823        lsp::DiagnosticSeverity::ERROR => colors.error,
28824        lsp::DiagnosticSeverity::WARNING => colors.warning,
28825        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28826        lsp::DiagnosticSeverity::HINT => colors.info,
28827        _ => colors.ignored,
28828    }
28829}
28830
28831pub fn styled_runs_for_code_label<'a>(
28832    label: &'a CodeLabel,
28833    syntax_theme: &'a theme::SyntaxTheme,
28834    local_player: &'a theme::PlayerColor,
28835) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28836    let fade_out = HighlightStyle {
28837        fade_out: Some(0.35),
28838        ..Default::default()
28839    };
28840
28841    if label.runs.is_empty() {
28842        let desc_start = label.filter_range.end;
28843        let fade_run =
28844            (desc_start < label.text.len()).then(|| (desc_start..label.text.len(), fade_out));
28845        return Either::Left(fade_run.into_iter());
28846    }
28847
28848    let mut prev_end = label.filter_range.end;
28849    Either::Right(
28850        label
28851            .runs
28852            .iter()
28853            .enumerate()
28854            .flat_map(move |(ix, (range, highlight_id))| {
28855                let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28856                    HighlightStyle {
28857                        color: Some(local_player.cursor),
28858                        ..Default::default()
28859                    }
28860                } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28861                    HighlightStyle {
28862                        background_color: Some(local_player.selection),
28863                        ..Default::default()
28864                    }
28865                } else if let Some(style) = syntax_theme.get(*highlight_id).cloned() {
28866                    style
28867                } else {
28868                    return Default::default();
28869                };
28870
28871                let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28872                let muted_style = style.highlight(fade_out);
28873                if range.start >= label.filter_range.end {
28874                    if range.start > prev_end {
28875                        runs.push((prev_end..range.start, fade_out));
28876                    }
28877                    runs.push((range.clone(), muted_style));
28878                } else if range.end <= label.filter_range.end {
28879                    runs.push((range.clone(), style));
28880                } else {
28881                    runs.push((range.start..label.filter_range.end, style));
28882                    runs.push((label.filter_range.end..range.end, muted_style));
28883                }
28884                prev_end = cmp::max(prev_end, range.end);
28885
28886                if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28887                    runs.push((prev_end..label.text.len(), fade_out));
28888                }
28889
28890                runs
28891            }),
28892    )
28893}
28894
28895pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28896    let mut prev_index = 0;
28897    let mut prev_codepoint: Option<char> = None;
28898    text.char_indices()
28899        .chain([(text.len(), '\0')])
28900        .filter_map(move |(index, codepoint)| {
28901            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28902            let is_boundary = index == text.len()
28903                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28904                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28905            if is_boundary {
28906                let chunk = &text[prev_index..index];
28907                prev_index = index;
28908                Some(chunk)
28909            } else {
28910                None
28911            }
28912        })
28913}
28914
28915/// Given a string of text immediately before the cursor, iterates over possible
28916/// strings a snippet could match to. More precisely: returns an iterator over
28917/// suffixes of `text` created by splitting at word boundaries (before & after
28918/// every non-word character).
28919///
28920/// Shorter suffixes are returned first.
28921pub(crate) fn snippet_candidate_suffixes<'a>(
28922    text: &'a str,
28923    is_word_char: &'a dyn Fn(char) -> bool,
28924) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28925    let mut prev_index = text.len();
28926    let mut prev_codepoint = None;
28927    text.char_indices()
28928        .rev()
28929        .chain([(0, '\0')])
28930        .filter_map(move |(index, codepoint)| {
28931            let prev_index = std::mem::replace(&mut prev_index, index);
28932            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28933            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28934                None
28935            } else {
28936                let chunk = &text[prev_index..]; // go to end of string
28937                Some(chunk)
28938            }
28939        })
28940}
28941
28942pub trait RangeToAnchorExt: Sized {
28943    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28944
28945    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28946        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28947        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28948    }
28949}
28950
28951impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28952    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28953        let start_offset = self.start.to_offset(snapshot);
28954        let end_offset = self.end.to_offset(snapshot);
28955        if start_offset == end_offset {
28956            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28957        } else {
28958            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28959        }
28960    }
28961}
28962
28963pub trait RowExt {
28964    fn as_f64(&self) -> f64;
28965
28966    fn next_row(&self) -> Self;
28967
28968    fn previous_row(&self) -> Self;
28969
28970    fn minus(&self, other: Self) -> u32;
28971}
28972
28973impl RowExt for DisplayRow {
28974    fn as_f64(&self) -> f64 {
28975        self.0 as _
28976    }
28977
28978    fn next_row(&self) -> Self {
28979        Self(self.0 + 1)
28980    }
28981
28982    fn previous_row(&self) -> Self {
28983        Self(self.0.saturating_sub(1))
28984    }
28985
28986    fn minus(&self, other: Self) -> u32 {
28987        self.0 - other.0
28988    }
28989}
28990
28991impl RowExt for MultiBufferRow {
28992    fn as_f64(&self) -> f64 {
28993        self.0 as _
28994    }
28995
28996    fn next_row(&self) -> Self {
28997        Self(self.0 + 1)
28998    }
28999
29000    fn previous_row(&self) -> Self {
29001        Self(self.0.saturating_sub(1))
29002    }
29003
29004    fn minus(&self, other: Self) -> u32 {
29005        self.0 - other.0
29006    }
29007}
29008
29009trait RowRangeExt {
29010    type Row;
29011
29012    fn len(&self) -> usize;
29013
29014    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29015}
29016
29017impl RowRangeExt for Range<MultiBufferRow> {
29018    type Row = MultiBufferRow;
29019
29020    fn len(&self) -> usize {
29021        (self.end.0 - self.start.0) as usize
29022    }
29023
29024    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29025        (self.start.0..self.end.0).map(MultiBufferRow)
29026    }
29027}
29028
29029impl RowRangeExt for Range<DisplayRow> {
29030    type Row = DisplayRow;
29031
29032    fn len(&self) -> usize {
29033        (self.end.0 - self.start.0) as usize
29034    }
29035
29036    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29037        (self.start.0..self.end.0).map(DisplayRow)
29038    }
29039}
29040
29041/// If select range has more than one line, we
29042/// just point the cursor to range.start.
29043fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29044    if range.start.row == range.end.row {
29045        range
29046    } else {
29047        range.start..range.start
29048    }
29049}
29050pub struct KillRing(ClipboardItem);
29051impl Global for KillRing {}
29052
29053const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29054
29055enum BreakpointPromptEditAction {
29056    Log,
29057    Condition,
29058    HitCondition,
29059}
29060
29061struct BreakpointPromptEditor {
29062    pub(crate) prompt: Entity<Editor>,
29063    editor: WeakEntity<Editor>,
29064    breakpoint_anchor: Anchor,
29065    breakpoint: Breakpoint,
29066    edit_action: BreakpointPromptEditAction,
29067    block_ids: HashSet<CustomBlockId>,
29068    editor_margins: Arc<Mutex<EditorMargins>>,
29069    _subscriptions: Vec<Subscription>,
29070}
29071
29072impl BreakpointPromptEditor {
29073    const MAX_LINES: u8 = 4;
29074
29075    fn new(
29076        editor: WeakEntity<Editor>,
29077        breakpoint_anchor: Anchor,
29078        breakpoint: Breakpoint,
29079        edit_action: BreakpointPromptEditAction,
29080        window: &mut Window,
29081        cx: &mut Context<Self>,
29082    ) -> Self {
29083        let base_text = match edit_action {
29084            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29085            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29086            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29087        }
29088        .map(|msg| msg.to_string())
29089        .unwrap_or_default();
29090
29091        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29092        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29093
29094        let prompt = cx.new(|cx| {
29095            let mut prompt = Editor::new(
29096                EditorMode::AutoHeight {
29097                    min_lines: 1,
29098                    max_lines: Some(Self::MAX_LINES as usize),
29099                },
29100                buffer,
29101                None,
29102                window,
29103                cx,
29104            );
29105            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29106            prompt.set_show_cursor_when_unfocused(false, cx);
29107            prompt.set_placeholder_text(
29108                match edit_action {
29109                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29110                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29111                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29112                },
29113                window,
29114                cx,
29115            );
29116
29117            prompt
29118        });
29119
29120        Self {
29121            prompt,
29122            editor,
29123            breakpoint_anchor,
29124            breakpoint,
29125            edit_action,
29126            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29127            block_ids: Default::default(),
29128            _subscriptions: vec![],
29129        }
29130    }
29131
29132    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29133        self.block_ids.extend(block_ids)
29134    }
29135
29136    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29137        if let Some(editor) = self.editor.upgrade() {
29138            let message = self
29139                .prompt
29140                .read(cx)
29141                .buffer
29142                .read(cx)
29143                .as_singleton()
29144                .expect("A multi buffer in breakpoint prompt isn't possible")
29145                .read(cx)
29146                .as_rope()
29147                .to_string();
29148
29149            editor.update(cx, |editor, cx| {
29150                editor.edit_breakpoint_at_anchor(
29151                    self.breakpoint_anchor,
29152                    self.breakpoint.clone(),
29153                    match self.edit_action {
29154                        BreakpointPromptEditAction::Log => {
29155                            BreakpointEditAction::EditLogMessage(message.into())
29156                        }
29157                        BreakpointPromptEditAction::Condition => {
29158                            BreakpointEditAction::EditCondition(message.into())
29159                        }
29160                        BreakpointPromptEditAction::HitCondition => {
29161                            BreakpointEditAction::EditHitCondition(message.into())
29162                        }
29163                    },
29164                    cx,
29165                );
29166
29167                editor.remove_blocks(self.block_ids.clone(), None, cx);
29168                cx.focus_self(window);
29169            });
29170        }
29171    }
29172
29173    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29174        self.editor
29175            .update(cx, |editor, cx| {
29176                editor.remove_blocks(self.block_ids.clone(), None, cx);
29177                window.focus(&editor.focus_handle, cx);
29178            })
29179            .log_err();
29180    }
29181
29182    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29183        let settings = ThemeSettings::get_global(cx);
29184        let text_style = TextStyle {
29185            color: if self.prompt.read(cx).read_only(cx) {
29186                cx.theme().colors().text_disabled
29187            } else {
29188                cx.theme().colors().text
29189            },
29190            font_family: settings.buffer_font.family.clone(),
29191            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29192            font_size: settings.buffer_font_size(cx).into(),
29193            font_weight: settings.buffer_font.weight,
29194            line_height: relative(settings.buffer_line_height.value()),
29195            ..Default::default()
29196        };
29197        EditorElement::new(
29198            &self.prompt,
29199            EditorStyle {
29200                background: cx.theme().colors().editor_background,
29201                local_player: cx.theme().players().local(),
29202                text: text_style,
29203                ..Default::default()
29204            },
29205        )
29206    }
29207
29208    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29209        let focus_handle = self.prompt.focus_handle(cx);
29210        IconButton::new("cancel", IconName::Close)
29211            .icon_color(Color::Muted)
29212            .shape(IconButtonShape::Square)
29213            .tooltip(move |_window, cx| {
29214                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29215            })
29216            .on_click(cx.listener(|this, _, window, cx| {
29217                this.cancel(&menu::Cancel, window, cx);
29218            }))
29219    }
29220
29221    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29222        let focus_handle = self.prompt.focus_handle(cx);
29223        IconButton::new("confirm", IconName::Return)
29224            .icon_color(Color::Muted)
29225            .shape(IconButtonShape::Square)
29226            .tooltip(move |_window, cx| {
29227                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29228            })
29229            .on_click(cx.listener(|this, _, window, cx| {
29230                this.confirm(&menu::Confirm, window, cx);
29231            }))
29232    }
29233}
29234
29235impl Render for BreakpointPromptEditor {
29236    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29237        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29238        let editor_margins = *self.editor_margins.lock();
29239        let gutter_dimensions = editor_margins.gutter;
29240        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29241        let right_padding = editor_margins.right + px(9.);
29242        h_flex()
29243            .key_context("Editor")
29244            .bg(cx.theme().colors().editor_background)
29245            .border_y_1()
29246            .border_color(cx.theme().status().info_border)
29247            .size_full()
29248            .py(window.line_height() / 2.5)
29249            .pr(right_padding)
29250            .on_action(cx.listener(Self::confirm))
29251            .on_action(cx.listener(Self::cancel))
29252            .child(
29253                WithRemSize::new(ui_font_size)
29254                    .h_full()
29255                    .w(left_gutter_width)
29256                    .flex()
29257                    .flex_row()
29258                    .flex_shrink_0()
29259                    .items_center()
29260                    .justify_center()
29261                    .gap_1()
29262                    .child(self.render_close_button(cx)),
29263            )
29264            .child(
29265                h_flex()
29266                    .w_full()
29267                    .justify_between()
29268                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29269                    .child(
29270                        WithRemSize::new(ui_font_size)
29271                            .flex()
29272                            .flex_row()
29273                            .items_center()
29274                            .child(self.render_confirm_button(cx)),
29275                    ),
29276            )
29277    }
29278}
29279
29280impl Focusable for BreakpointPromptEditor {
29281    fn focus_handle(&self, cx: &App) -> FocusHandle {
29282        self.prompt.focus_handle(cx)
29283    }
29284}
29285
29286fn all_edits_insertions_or_deletions(
29287    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29288    snapshot: &MultiBufferSnapshot,
29289) -> bool {
29290    let mut all_insertions = true;
29291    let mut all_deletions = true;
29292
29293    for (range, new_text) in edits.iter() {
29294        let range_is_empty = range.to_offset(snapshot).is_empty();
29295        let text_is_empty = new_text.is_empty();
29296
29297        if range_is_empty != text_is_empty {
29298            if range_is_empty {
29299                all_deletions = false;
29300            } else {
29301                all_insertions = false;
29302            }
29303        } else {
29304            return false;
29305        }
29306
29307        if !all_insertions && !all_deletions {
29308            return false;
29309        }
29310    }
29311    all_insertions || all_deletions
29312}
29313
29314struct MissingEditPredictionKeybindingTooltip;
29315
29316impl Render for MissingEditPredictionKeybindingTooltip {
29317    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29318        ui::tooltip_container(cx, |container, cx| {
29319            container
29320                .flex_shrink_0()
29321                .max_w_80()
29322                .min_h(rems_from_px(124.))
29323                .justify_between()
29324                .child(
29325                    v_flex()
29326                        .flex_1()
29327                        .text_ui_sm(cx)
29328                        .child(Label::new("Conflict with Accept Keybinding"))
29329                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29330                )
29331                .child(
29332                    h_flex()
29333                        .pb_1()
29334                        .gap_1()
29335                        .items_end()
29336                        .w_full()
29337                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29338                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29339                        }))
29340                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29341                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29342                        })),
29343                )
29344        })
29345    }
29346}
29347
29348#[derive(Debug, Clone, Copy, PartialEq)]
29349pub struct LineHighlight {
29350    pub background: Background,
29351    pub border: Option<gpui::Hsla>,
29352    pub include_gutter: bool,
29353    pub type_id: Option<TypeId>,
29354}
29355
29356struct LineManipulationResult {
29357    pub new_text: String,
29358    pub line_count_before: usize,
29359    pub line_count_after: usize,
29360}
29361
29362fn render_diff_hunk_controls(
29363    row: u32,
29364    status: &DiffHunkStatus,
29365    hunk_range: Range<Anchor>,
29366    is_created_file: bool,
29367    line_height: Pixels,
29368    editor: &Entity<Editor>,
29369    _window: &mut Window,
29370    cx: &mut App,
29371) -> AnyElement {
29372    h_flex()
29373        .h(line_height)
29374        .mr_1()
29375        .gap_1()
29376        .px_0p5()
29377        .pb_1()
29378        .border_x_1()
29379        .border_b_1()
29380        .border_color(cx.theme().colors().border_variant)
29381        .rounded_b_lg()
29382        .bg(cx.theme().colors().editor_background)
29383        .gap_1()
29384        .block_mouse_except_scroll()
29385        .shadow_md()
29386        .child(if status.has_secondary_hunk() {
29387            Button::new(("stage", row as u64), "Stage")
29388                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29389                .tooltip({
29390                    let focus_handle = editor.focus_handle(cx);
29391                    move |_window, cx| {
29392                        Tooltip::for_action_in(
29393                            "Stage Hunk",
29394                            &::git::ToggleStaged,
29395                            &focus_handle,
29396                            cx,
29397                        )
29398                    }
29399                })
29400                .on_click({
29401                    let editor = editor.clone();
29402                    move |_event, _window, cx| {
29403                        editor.update(cx, |editor, cx| {
29404                            editor.stage_or_unstage_diff_hunks(
29405                                true,
29406                                vec![hunk_range.start..hunk_range.start],
29407                                cx,
29408                            );
29409                        });
29410                    }
29411                })
29412        } else {
29413            Button::new(("unstage", row as u64), "Unstage")
29414                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29415                .tooltip({
29416                    let focus_handle = editor.focus_handle(cx);
29417                    move |_window, cx| {
29418                        Tooltip::for_action_in(
29419                            "Unstage Hunk",
29420                            &::git::ToggleStaged,
29421                            &focus_handle,
29422                            cx,
29423                        )
29424                    }
29425                })
29426                .on_click({
29427                    let editor = editor.clone();
29428                    move |_event, _window, cx| {
29429                        editor.update(cx, |editor, cx| {
29430                            editor.stage_or_unstage_diff_hunks(
29431                                false,
29432                                vec![hunk_range.start..hunk_range.start],
29433                                cx,
29434                            );
29435                        });
29436                    }
29437                })
29438        })
29439        .child(
29440            Button::new(("restore", row as u64), "Restore")
29441                .tooltip({
29442                    let focus_handle = editor.focus_handle(cx);
29443                    move |_window, cx| {
29444                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29445                    }
29446                })
29447                .on_click({
29448                    let editor = editor.clone();
29449                    move |_event, window, cx| {
29450                        editor.update(cx, |editor, cx| {
29451                            let snapshot = editor.snapshot(window, cx);
29452                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29453                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29454                        });
29455                    }
29456                })
29457                .disabled(is_created_file),
29458        )
29459        .when(
29460            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29461            |el| {
29462                el.child(
29463                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29464                        .shape(IconButtonShape::Square)
29465                        .icon_size(IconSize::Small)
29466                        // .disabled(!has_multiple_hunks)
29467                        .tooltip({
29468                            let focus_handle = editor.focus_handle(cx);
29469                            move |_window, cx| {
29470                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29471                            }
29472                        })
29473                        .on_click({
29474                            let editor = editor.clone();
29475                            move |_event, window, cx| {
29476                                editor.update(cx, |editor, cx| {
29477                                    let snapshot = editor.snapshot(window, cx);
29478                                    let position =
29479                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29480                                    editor.go_to_hunk_before_or_after_position(
29481                                        &snapshot,
29482                                        position,
29483                                        Direction::Next,
29484                                        true,
29485                                        window,
29486                                        cx,
29487                                    );
29488                                    editor.expand_selected_diff_hunks(cx);
29489                                });
29490                            }
29491                        }),
29492                )
29493                .child(
29494                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29495                        .shape(IconButtonShape::Square)
29496                        .icon_size(IconSize::Small)
29497                        // .disabled(!has_multiple_hunks)
29498                        .tooltip({
29499                            let focus_handle = editor.focus_handle(cx);
29500                            move |_window, cx| {
29501                                Tooltip::for_action_in(
29502                                    "Previous Hunk",
29503                                    &GoToPreviousHunk,
29504                                    &focus_handle,
29505                                    cx,
29506                                )
29507                            }
29508                        })
29509                        .on_click({
29510                            let editor = editor.clone();
29511                            move |_event, window, cx| {
29512                                editor.update(cx, |editor, cx| {
29513                                    let snapshot = editor.snapshot(window, cx);
29514                                    let point =
29515                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29516                                    editor.go_to_hunk_before_or_after_position(
29517                                        &snapshot,
29518                                        point,
29519                                        Direction::Prev,
29520                                        true,
29521                                        window,
29522                                        cx,
29523                                    );
29524                                    editor.expand_selected_diff_hunks(cx);
29525                                });
29526                            }
29527                        }),
29528                )
29529            },
29530        )
29531        .into_any_element()
29532}
29533
29534pub fn multibuffer_context_lines(cx: &App) -> u32 {
29535    EditorSettings::try_get(cx)
29536        .map(|settings| settings.excerpt_context_lines)
29537        .unwrap_or(2)
29538        .min(32)
29539}