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 ranges = buffer_ids
11745            .into_iter()
11746            .flat_map(|buffer_id| snapshot.range_for_buffer(buffer_id))
11747            .collect::<Vec<_>>();
11748
11749        self.restore_hunks_in_ranges(ranges, window, cx);
11750    }
11751
11752    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11753        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11754        let selections = self
11755            .selections
11756            .all(&self.display_snapshot(cx))
11757            .into_iter()
11758            .map(|s| s.range())
11759            .collect();
11760        self.restore_hunks_in_ranges(selections, window, cx);
11761    }
11762
11763    /// Restores the diff hunks in the editor's selections and moves the cursor
11764    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11765    /// not all diff hunks are expanded.
11766    pub fn restore_and_next(
11767        &mut self,
11768        _: &::git::RestoreAndNext,
11769        window: &mut Window,
11770        cx: &mut Context<Self>,
11771    ) {
11772        let selections = self
11773            .selections
11774            .all(&self.display_snapshot(cx))
11775            .into_iter()
11776            .map(|selection| selection.range())
11777            .collect();
11778
11779        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11780        self.restore_hunks_in_ranges(selections, window, cx);
11781
11782        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11783        let wrap_around = !all_diff_hunks_expanded;
11784        let snapshot = self.snapshot(window, cx);
11785        let position = self
11786            .selections
11787            .newest::<Point>(&snapshot.display_snapshot)
11788            .head();
11789
11790        self.go_to_hunk_before_or_after_position(
11791            &snapshot,
11792            position,
11793            Direction::Next,
11794            wrap_around,
11795            window,
11796            cx,
11797        );
11798    }
11799
11800    pub fn restore_hunks_in_ranges(
11801        &mut self,
11802        ranges: Vec<Range<Point>>,
11803        window: &mut Window,
11804        cx: &mut Context<Editor>,
11805    ) {
11806        if self.delegate_stage_and_restore {
11807            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11808            if !hunks.is_empty() {
11809                cx.emit(EditorEvent::RestoreRequested { hunks });
11810            }
11811            return;
11812        }
11813        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11814        self.transact(window, cx, |editor, window, cx| {
11815            editor.restore_diff_hunks(hunks, cx);
11816            let selections = editor
11817                .selections
11818                .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
11819            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11820                s.select(selections);
11821            });
11822        });
11823    }
11824
11825    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11826        let mut revert_changes = HashMap::default();
11827        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11828        for (buffer_id, hunks) in &chunk_by {
11829            let hunks = hunks.collect::<Vec<_>>();
11830            for hunk in &hunks {
11831                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11832            }
11833            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11834        }
11835        if !revert_changes.is_empty() {
11836            self.buffer().update(cx, |multi_buffer, cx| {
11837                for (buffer_id, changes) in revert_changes {
11838                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11839                        buffer.update(cx, |buffer, cx| {
11840                            buffer.edit(
11841                                changes
11842                                    .into_iter()
11843                                    .map(|(range, text)| (range, text.to_string())),
11844                                None,
11845                                cx,
11846                            );
11847                        });
11848                    }
11849                }
11850            });
11851        }
11852    }
11853
11854    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11855        if let Some(status) = self
11856            .addons
11857            .iter()
11858            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11859        {
11860            return Some(status);
11861        }
11862        self.project
11863            .as_ref()?
11864            .read(cx)
11865            .status_for_buffer_id(buffer_id, cx)
11866    }
11867
11868    pub fn open_active_item_in_terminal(
11869        &mut self,
11870        _: &OpenInTerminal,
11871        window: &mut Window,
11872        cx: &mut Context<Self>,
11873    ) {
11874        if let Some(working_directory) = self.active_buffer(cx).and_then(|buffer| {
11875            let project_path = buffer.read(cx).project_path(cx)?;
11876            let project = self.project()?.read(cx);
11877            let entry = project.entry_for_path(&project_path, cx)?;
11878            let parent = match &entry.canonical_path {
11879                Some(canonical_path) => canonical_path.to_path_buf(),
11880                None => project.absolute_path(&project_path, cx)?,
11881            }
11882            .parent()?
11883            .to_path_buf();
11884            Some(parent)
11885        }) {
11886            window.dispatch_action(
11887                OpenTerminal {
11888                    working_directory,
11889                    local: false,
11890                }
11891                .boxed_clone(),
11892                cx,
11893            );
11894        }
11895    }
11896
11897    fn set_breakpoint_context_menu(
11898        &mut self,
11899        display_row: DisplayRow,
11900        position: Option<Anchor>,
11901        clicked_point: gpui::Point<Pixels>,
11902        window: &mut Window,
11903        cx: &mut Context<Self>,
11904    ) {
11905        let source = self
11906            .buffer
11907            .read(cx)
11908            .snapshot(cx)
11909            .anchor_before(Point::new(display_row.0, 0u32));
11910
11911        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11912
11913        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11914            self,
11915            source,
11916            clicked_point,
11917            context_menu,
11918            window,
11919            cx,
11920        );
11921    }
11922
11923    fn add_edit_breakpoint_block(
11924        &mut self,
11925        anchor: Anchor,
11926        breakpoint: &Breakpoint,
11927        edit_action: BreakpointPromptEditAction,
11928        window: &mut Window,
11929        cx: &mut Context<Self>,
11930    ) {
11931        let weak_editor = cx.weak_entity();
11932        let bp_prompt = cx.new(|cx| {
11933            BreakpointPromptEditor::new(
11934                weak_editor,
11935                anchor,
11936                breakpoint.clone(),
11937                edit_action,
11938                window,
11939                cx,
11940            )
11941        });
11942
11943        let height = bp_prompt.update(cx, |this, cx| {
11944            this.prompt
11945                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11946        });
11947        let cloned_prompt = bp_prompt.clone();
11948        let blocks = vec![BlockProperties {
11949            style: BlockStyle::Sticky,
11950            placement: BlockPlacement::Above(anchor),
11951            height: Some(height),
11952            render: Arc::new(move |cx| {
11953                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11954                cloned_prompt.clone().into_any_element()
11955            }),
11956            priority: 0,
11957        }];
11958
11959        let focus_handle = bp_prompt.focus_handle(cx);
11960        window.focus(&focus_handle, cx);
11961
11962        let block_ids = self.insert_blocks(blocks, None, cx);
11963        bp_prompt.update(cx, |prompt, _| {
11964            prompt.add_block_ids(block_ids);
11965        });
11966    }
11967
11968    pub(crate) fn breakpoint_at_row(
11969        &self,
11970        row: u32,
11971        window: &mut Window,
11972        cx: &mut Context<Self>,
11973    ) -> Option<(Anchor, Breakpoint)> {
11974        let snapshot = self.snapshot(window, cx);
11975        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11976
11977        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11978    }
11979
11980    pub(crate) fn breakpoint_at_anchor(
11981        &self,
11982        breakpoint_position: Anchor,
11983        snapshot: &EditorSnapshot,
11984        cx: &mut Context<Self>,
11985    ) -> Option<(Anchor, Breakpoint)> {
11986        let (breakpoint_position, _) = snapshot
11987            .buffer_snapshot()
11988            .anchor_to_buffer_anchor(breakpoint_position)?;
11989        let buffer = self.buffer.read(cx).buffer(breakpoint_position.buffer_id)?;
11990
11991        let buffer_snapshot = buffer.read(cx).snapshot();
11992
11993        let row = buffer_snapshot
11994            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position)
11995            .row;
11996
11997        let line_len = buffer_snapshot.line_len(row);
11998        let anchor_end = buffer_snapshot.anchor_after(Point::new(row, line_len));
11999
12000        self.breakpoint_store
12001            .as_ref()?
12002            .read_with(cx, |breakpoint_store, cx| {
12003                breakpoint_store
12004                    .breakpoints(
12005                        &buffer,
12006                        Some(breakpoint_position..anchor_end),
12007                        &buffer_snapshot,
12008                        cx,
12009                    )
12010                    .next()
12011                    .and_then(|(bp, _)| {
12012                        let breakpoint_row = buffer_snapshot
12013                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
12014                            .row;
12015
12016                        if breakpoint_row == row {
12017                            snapshot
12018                                .buffer_snapshot()
12019                                .anchor_in_excerpt(bp.position)
12020                                .map(|position| (position, bp.bp.clone()))
12021                        } else {
12022                            None
12023                        }
12024                    })
12025            })
12026    }
12027
12028    pub fn edit_log_breakpoint(
12029        &mut self,
12030        _: &EditLogBreakpoint,
12031        window: &mut Window,
12032        cx: &mut Context<Self>,
12033    ) {
12034        if self.breakpoint_store.is_none() {
12035            return;
12036        }
12037
12038        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12039            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
12040                message: None,
12041                state: BreakpointState::Enabled,
12042                condition: None,
12043                hit_condition: None,
12044            });
12045
12046            self.add_edit_breakpoint_block(
12047                anchor,
12048                &breakpoint,
12049                BreakpointPromptEditAction::Log,
12050                window,
12051                cx,
12052            );
12053        }
12054    }
12055
12056    fn breakpoints_at_cursors(
12057        &self,
12058        window: &mut Window,
12059        cx: &mut Context<Self>,
12060    ) -> Vec<(Anchor, Option<Breakpoint>)> {
12061        let snapshot = self.snapshot(window, cx);
12062        let cursors = self
12063            .selections
12064            .disjoint_anchors_arc()
12065            .iter()
12066            .map(|selection| {
12067                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12068
12069                let breakpoint_position = self
12070                    .breakpoint_at_row(cursor_position.row, window, cx)
12071                    .map(|bp| bp.0)
12072                    .unwrap_or_else(|| {
12073                        snapshot
12074                            .display_snapshot
12075                            .buffer_snapshot()
12076                            .anchor_after(Point::new(cursor_position.row, 0))
12077                    });
12078
12079                let breakpoint = self
12080                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12081                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12082
12083                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12084            })
12085            // 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.
12086            .collect::<HashMap<Anchor, _>>();
12087
12088        cursors.into_iter().collect()
12089    }
12090
12091    pub fn enable_breakpoint(
12092        &mut self,
12093        _: &crate::actions::EnableBreakpoint,
12094        window: &mut Window,
12095        cx: &mut Context<Self>,
12096    ) {
12097        if self.breakpoint_store.is_none() {
12098            return;
12099        }
12100
12101        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12102            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12103                continue;
12104            };
12105            self.edit_breakpoint_at_anchor(
12106                anchor,
12107                breakpoint,
12108                BreakpointEditAction::InvertState,
12109                cx,
12110            );
12111        }
12112    }
12113
12114    pub fn align_selections(
12115        &mut self,
12116        _: &crate::actions::AlignSelections,
12117        window: &mut Window,
12118        cx: &mut Context<Self>,
12119    ) {
12120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12121
12122        let display_snapshot = self.display_snapshot(cx);
12123
12124        struct CursorData {
12125            anchor: Anchor,
12126            point: Point,
12127        }
12128        let cursor_data: Vec<CursorData> = self
12129            .selections
12130            .disjoint_anchors()
12131            .iter()
12132            .map(|selection| {
12133                let anchor = if selection.reversed {
12134                    selection.head()
12135                } else {
12136                    selection.tail()
12137                };
12138                CursorData {
12139                    anchor: anchor,
12140                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12141                }
12142            })
12143            .collect();
12144
12145        let rows_anchors_count: Vec<usize> = cursor_data
12146            .iter()
12147            .map(|cursor| cursor.point.row)
12148            .chunk_by(|&row| row)
12149            .into_iter()
12150            .map(|(_, group)| group.count())
12151            .collect();
12152        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12153        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12154        let mut edits = Vec::new();
12155
12156        for column_idx in 0..max_columns {
12157            let mut cursor_index = 0;
12158
12159            // Calculate target_column => position that the selections will go
12160            let mut target_column = 0;
12161            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12162                // Skip rows that don't have this column
12163                if column_idx >= *cursor_count {
12164                    cursor_index += cursor_count;
12165                    continue;
12166                }
12167
12168                let point = &cursor_data[cursor_index + column_idx].point;
12169                let adjusted_column = point.column + rows_column_offset[row_idx];
12170                if adjusted_column > target_column {
12171                    target_column = adjusted_column;
12172                }
12173                cursor_index += cursor_count;
12174            }
12175
12176            // Collect edits for this column
12177            cursor_index = 0;
12178            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12179                // Skip rows that don't have this column
12180                if column_idx >= *cursor_count {
12181                    cursor_index += *cursor_count;
12182                    continue;
12183                }
12184
12185                let point = &cursor_data[cursor_index + column_idx].point;
12186                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12187                if spaces_needed > 0 {
12188                    let anchor = cursor_data[cursor_index + column_idx]
12189                        .anchor
12190                        .bias_left(&display_snapshot);
12191                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12192                }
12193                rows_column_offset[row_idx] += spaces_needed;
12194
12195                cursor_index += *cursor_count;
12196            }
12197        }
12198
12199        if !edits.is_empty() {
12200            self.transact(window, cx, |editor, _window, cx| {
12201                editor.edit(edits, cx);
12202            });
12203        }
12204    }
12205
12206    pub fn disable_breakpoint(
12207        &mut self,
12208        _: &crate::actions::DisableBreakpoint,
12209        window: &mut Window,
12210        cx: &mut Context<Self>,
12211    ) {
12212        if self.breakpoint_store.is_none() {
12213            return;
12214        }
12215
12216        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12217            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12218                continue;
12219            };
12220            self.edit_breakpoint_at_anchor(
12221                anchor,
12222                breakpoint,
12223                BreakpointEditAction::InvertState,
12224                cx,
12225            );
12226        }
12227    }
12228
12229    pub fn toggle_breakpoint(
12230        &mut self,
12231        _: &crate::actions::ToggleBreakpoint,
12232        window: &mut Window,
12233        cx: &mut Context<Self>,
12234    ) {
12235        if self.breakpoint_store.is_none() {
12236            return;
12237        }
12238
12239        let snapshot = self.snapshot(window, cx);
12240        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12241            if self.gutter_breakpoint_indicator.0.is_some() {
12242                let display_row = anchor
12243                    .to_point(snapshot.buffer_snapshot())
12244                    .to_display_point(&snapshot.display_snapshot)
12245                    .row();
12246                self.update_breakpoint_collision_on_toggle(
12247                    display_row,
12248                    &BreakpointEditAction::Toggle,
12249                );
12250            }
12251
12252            if let Some(breakpoint) = breakpoint {
12253                self.edit_breakpoint_at_anchor(
12254                    anchor,
12255                    breakpoint,
12256                    BreakpointEditAction::Toggle,
12257                    cx,
12258                );
12259            } else {
12260                self.edit_breakpoint_at_anchor(
12261                    anchor,
12262                    Breakpoint::new_standard(),
12263                    BreakpointEditAction::Toggle,
12264                    cx,
12265                );
12266            }
12267        }
12268    }
12269
12270    fn update_breakpoint_collision_on_toggle(
12271        &mut self,
12272        display_row: DisplayRow,
12273        edit_action: &BreakpointEditAction,
12274    ) {
12275        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12276            if breakpoint_indicator.display_row == display_row
12277                && matches!(edit_action, BreakpointEditAction::Toggle)
12278            {
12279                breakpoint_indicator.collides_with_existing_breakpoint =
12280                    !breakpoint_indicator.collides_with_existing_breakpoint;
12281            }
12282        }
12283    }
12284
12285    pub fn edit_breakpoint_at_anchor(
12286        &mut self,
12287        breakpoint_position: Anchor,
12288        breakpoint: Breakpoint,
12289        edit_action: BreakpointEditAction,
12290        cx: &mut Context<Self>,
12291    ) {
12292        let Some(breakpoint_store) = &self.breakpoint_store else {
12293            return;
12294        };
12295        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12296        let Some((position, _)) = buffer_snapshot.anchor_to_buffer_anchor(breakpoint_position)
12297        else {
12298            return;
12299        };
12300        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
12301            return;
12302        };
12303
12304        breakpoint_store.update(cx, |breakpoint_store, cx| {
12305            breakpoint_store.toggle_breakpoint(
12306                buffer,
12307                BreakpointWithPosition {
12308                    position,
12309                    bp: breakpoint,
12310                },
12311                edit_action,
12312                cx,
12313            );
12314        });
12315
12316        cx.notify();
12317    }
12318
12319    #[cfg(any(test, feature = "test-support"))]
12320    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12321        self.breakpoint_store.clone()
12322    }
12323
12324    pub fn prepare_restore_change(
12325        &self,
12326        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12327        hunk: &MultiBufferDiffHunk,
12328        cx: &mut App,
12329    ) -> Option<()> {
12330        if hunk.is_created_file() {
12331            return None;
12332        }
12333        let multi_buffer = self.buffer.read(cx);
12334        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
12335        let diff_snapshot = multi_buffer_snapshot.diff_for_buffer_id(hunk.buffer_id)?;
12336        let original_text = diff_snapshot
12337            .base_text()
12338            .as_rope()
12339            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12340        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
12341        let buffer = buffer.read(cx);
12342        let buffer_snapshot = buffer.snapshot();
12343        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12344        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12345            probe
12346                .0
12347                .start
12348                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12349                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12350        }) {
12351            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12352            Some(())
12353        } else {
12354            None
12355        }
12356    }
12357
12358    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12359        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12360    }
12361
12362    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12363        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12364    }
12365
12366    pub fn rotate_selections_forward(
12367        &mut self,
12368        _: &RotateSelectionsForward,
12369        window: &mut Window,
12370        cx: &mut Context<Self>,
12371    ) {
12372        self.rotate_selections(window, cx, false)
12373    }
12374
12375    pub fn rotate_selections_backward(
12376        &mut self,
12377        _: &RotateSelectionsBackward,
12378        window: &mut Window,
12379        cx: &mut Context<Self>,
12380    ) {
12381        self.rotate_selections(window, cx, true)
12382    }
12383
12384    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12385        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12386        let display_snapshot = self.display_snapshot(cx);
12387        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12388
12389        if selections.len() < 2 {
12390            return;
12391        }
12392
12393        let (edits, new_selections) = {
12394            let buffer = self.buffer.read(cx).read(cx);
12395            let has_selections = selections.iter().any(|s| !s.is_empty());
12396            if has_selections {
12397                let mut selected_texts: Vec<String> = selections
12398                    .iter()
12399                    .map(|selection| {
12400                        buffer
12401                            .text_for_range(selection.start..selection.end)
12402                            .collect()
12403                    })
12404                    .collect();
12405
12406                if reverse {
12407                    selected_texts.rotate_left(1);
12408                } else {
12409                    selected_texts.rotate_right(1);
12410                }
12411
12412                let mut offset_delta: i64 = 0;
12413                let mut new_selections = Vec::new();
12414                let edits: Vec<_> = selections
12415                    .iter()
12416                    .zip(selected_texts.iter())
12417                    .map(|(selection, new_text)| {
12418                        let old_len = (selection.end.0 - selection.start.0) as i64;
12419                        let new_len = new_text.len() as i64;
12420                        let adjusted_start =
12421                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12422                        let adjusted_end =
12423                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12424
12425                        new_selections.push(Selection {
12426                            id: selection.id,
12427                            start: adjusted_start,
12428                            end: adjusted_end,
12429                            reversed: selection.reversed,
12430                            goal: selection.goal,
12431                        });
12432
12433                        offset_delta += new_len - old_len;
12434                        (selection.start..selection.end, new_text.clone())
12435                    })
12436                    .collect();
12437                (edits, new_selections)
12438            } else {
12439                let mut all_rows: Vec<u32> = selections
12440                    .iter()
12441                    .map(|selection| buffer.offset_to_point(selection.start).row)
12442                    .collect();
12443                all_rows.sort_unstable();
12444                all_rows.dedup();
12445
12446                if all_rows.len() < 2 {
12447                    return;
12448                }
12449
12450                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12451                    .iter()
12452                    .map(|&row| {
12453                        let start = Point::new(row, 0);
12454                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12455                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12456                    })
12457                    .collect();
12458
12459                let mut line_texts: Vec<String> = line_ranges
12460                    .iter()
12461                    .map(|range| buffer.text_for_range(range.clone()).collect())
12462                    .collect();
12463
12464                if reverse {
12465                    line_texts.rotate_left(1);
12466                } else {
12467                    line_texts.rotate_right(1);
12468                }
12469
12470                let edits = line_ranges
12471                    .iter()
12472                    .zip(line_texts.iter())
12473                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12474                    .collect();
12475
12476                let num_rows = all_rows.len();
12477                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12478                    .iter()
12479                    .enumerate()
12480                    .map(|(i, &row)| (row, i))
12481                    .collect();
12482
12483                // Compute new line start offsets after rotation (handles CRLF)
12484                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12485                let first_line_start = line_ranges[0].start.0;
12486                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12487                for text in line_texts.iter().take(num_rows - 1) {
12488                    let prev_start = *new_line_starts.last().unwrap();
12489                    new_line_starts.push(prev_start + text.len() + newline_len);
12490                }
12491
12492                let new_selections = selections
12493                    .iter()
12494                    .map(|selection| {
12495                        let point = buffer.offset_to_point(selection.start);
12496                        let old_index = row_to_index[&point.row];
12497                        let new_index = if reverse {
12498                            (old_index + num_rows - 1) % num_rows
12499                        } else {
12500                            (old_index + 1) % num_rows
12501                        };
12502                        let new_offset =
12503                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12504                        Selection {
12505                            id: selection.id,
12506                            start: new_offset,
12507                            end: new_offset,
12508                            reversed: selection.reversed,
12509                            goal: selection.goal,
12510                        }
12511                    })
12512                    .collect();
12513
12514                (edits, new_selections)
12515            }
12516        };
12517
12518        self.transact(window, cx, |this, window, cx| {
12519            this.buffer.update(cx, |buffer, cx| {
12520                buffer.edit(edits, None, cx);
12521            });
12522            this.change_selections(Default::default(), window, cx, |s| {
12523                s.select(new_selections);
12524            });
12525        });
12526    }
12527
12528    fn manipulate_lines<M>(
12529        &mut self,
12530        window: &mut Window,
12531        cx: &mut Context<Self>,
12532        mut manipulate: M,
12533    ) where
12534        M: FnMut(&str) -> LineManipulationResult,
12535    {
12536        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12537
12538        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12539        let buffer = self.buffer.read(cx).snapshot(cx);
12540
12541        let mut edits = Vec::new();
12542
12543        let selections = self.selections.all::<Point>(&display_map);
12544        let mut selections = selections.iter().peekable();
12545        let mut contiguous_row_selections = Vec::new();
12546        let mut new_selections = Vec::new();
12547        let mut added_lines = 0;
12548        let mut removed_lines = 0;
12549
12550        while let Some(selection) = selections.next() {
12551            let (start_row, end_row) = consume_contiguous_rows(
12552                &mut contiguous_row_selections,
12553                selection,
12554                &display_map,
12555                &mut selections,
12556            );
12557
12558            let start_point = Point::new(start_row.0, 0);
12559            let end_point = Point::new(
12560                end_row.previous_row().0,
12561                buffer.line_len(end_row.previous_row()),
12562            );
12563            let text = buffer
12564                .text_for_range(start_point..end_point)
12565                .collect::<String>();
12566
12567            let LineManipulationResult {
12568                new_text,
12569                line_count_before,
12570                line_count_after,
12571            } = manipulate(&text);
12572
12573            edits.push((start_point..end_point, new_text));
12574
12575            // Selections must change based on added and removed line count
12576            let start_row =
12577                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12578            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12579            new_selections.push(Selection {
12580                id: selection.id,
12581                start: start_row,
12582                end: end_row,
12583                goal: SelectionGoal::None,
12584                reversed: selection.reversed,
12585            });
12586
12587            if line_count_after > line_count_before {
12588                added_lines += line_count_after - line_count_before;
12589            } else if line_count_before > line_count_after {
12590                removed_lines += line_count_before - line_count_after;
12591            }
12592        }
12593
12594        self.transact(window, cx, |this, window, cx| {
12595            let buffer = this.buffer.update(cx, |buffer, cx| {
12596                buffer.edit(edits, None, cx);
12597                buffer.snapshot(cx)
12598            });
12599
12600            // Recalculate offsets on newly edited buffer
12601            let new_selections = new_selections
12602                .iter()
12603                .map(|s| {
12604                    let start_point = Point::new(s.start.0, 0);
12605                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12606                    Selection {
12607                        id: s.id,
12608                        start: buffer.point_to_offset(start_point),
12609                        end: buffer.point_to_offset(end_point),
12610                        goal: s.goal,
12611                        reversed: s.reversed,
12612                    }
12613                })
12614                .collect();
12615
12616            this.change_selections(Default::default(), window, cx, |s| {
12617                s.select(new_selections);
12618            });
12619
12620            this.request_autoscroll(Autoscroll::fit(), cx);
12621        });
12622    }
12623
12624    fn manipulate_immutable_lines<Fn>(
12625        &mut self,
12626        window: &mut Window,
12627        cx: &mut Context<Self>,
12628        mut callback: Fn,
12629    ) where
12630        Fn: FnMut(&mut Vec<&str>),
12631    {
12632        self.manipulate_lines(window, cx, |text| {
12633            let mut lines: Vec<&str> = text.split('\n').collect();
12634            let line_count_before = lines.len();
12635
12636            callback(&mut lines);
12637
12638            LineManipulationResult {
12639                new_text: lines.join("\n"),
12640                line_count_before,
12641                line_count_after: lines.len(),
12642            }
12643        });
12644    }
12645
12646    fn manipulate_mutable_lines<Fn>(
12647        &mut self,
12648        window: &mut Window,
12649        cx: &mut Context<Self>,
12650        mut callback: Fn,
12651    ) where
12652        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12653    {
12654        self.manipulate_lines(window, cx, |text| {
12655            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12656            let line_count_before = lines.len();
12657
12658            callback(&mut lines);
12659
12660            LineManipulationResult {
12661                new_text: lines.join("\n"),
12662                line_count_before,
12663                line_count_after: lines.len(),
12664            }
12665        });
12666    }
12667
12668    pub fn convert_indentation_to_spaces(
12669        &mut self,
12670        _: &ConvertIndentationToSpaces,
12671        window: &mut Window,
12672        cx: &mut Context<Self>,
12673    ) {
12674        let settings = self.buffer.read(cx).language_settings(cx);
12675        let tab_size = settings.tab_size.get() as usize;
12676
12677        self.manipulate_mutable_lines(window, cx, |lines| {
12678            // Allocates a reasonably sized scratch buffer once for the whole loop
12679            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12680            // Avoids recomputing spaces that could be inserted many times
12681            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12682                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12683                .collect();
12684
12685            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12686                let mut chars = line.as_ref().chars();
12687                let mut col = 0;
12688                let mut changed = false;
12689
12690                for ch in chars.by_ref() {
12691                    match ch {
12692                        ' ' => {
12693                            reindented_line.push(' ');
12694                            col += 1;
12695                        }
12696                        '\t' => {
12697                            // \t are converted to spaces depending on the current column
12698                            let spaces_len = tab_size - (col % tab_size);
12699                            reindented_line.extend(&space_cache[spaces_len - 1]);
12700                            col += spaces_len;
12701                            changed = true;
12702                        }
12703                        _ => {
12704                            // If we dont append before break, the character is consumed
12705                            reindented_line.push(ch);
12706                            break;
12707                        }
12708                    }
12709                }
12710
12711                if !changed {
12712                    reindented_line.clear();
12713                    continue;
12714                }
12715                // Append the rest of the line and replace old reference with new one
12716                reindented_line.extend(chars);
12717                *line = Cow::Owned(reindented_line.clone());
12718                reindented_line.clear();
12719            }
12720        });
12721    }
12722
12723    pub fn convert_indentation_to_tabs(
12724        &mut self,
12725        _: &ConvertIndentationToTabs,
12726        window: &mut Window,
12727        cx: &mut Context<Self>,
12728    ) {
12729        let settings = self.buffer.read(cx).language_settings(cx);
12730        let tab_size = settings.tab_size.get() as usize;
12731
12732        self.manipulate_mutable_lines(window, cx, |lines| {
12733            // Allocates a reasonably sized buffer once for the whole loop
12734            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12735            // Avoids recomputing spaces that could be inserted many times
12736            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12737                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12738                .collect();
12739
12740            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12741                let mut chars = line.chars();
12742                let mut spaces_count = 0;
12743                let mut first_non_indent_char = None;
12744                let mut changed = false;
12745
12746                for ch in chars.by_ref() {
12747                    match ch {
12748                        ' ' => {
12749                            // Keep track of spaces. Append \t when we reach tab_size
12750                            spaces_count += 1;
12751                            changed = true;
12752                            if spaces_count == tab_size {
12753                                reindented_line.push('\t');
12754                                spaces_count = 0;
12755                            }
12756                        }
12757                        '\t' => {
12758                            reindented_line.push('\t');
12759                            spaces_count = 0;
12760                        }
12761                        _ => {
12762                            // Dont append it yet, we might have remaining spaces
12763                            first_non_indent_char = Some(ch);
12764                            break;
12765                        }
12766                    }
12767                }
12768
12769                if !changed {
12770                    reindented_line.clear();
12771                    continue;
12772                }
12773                // Remaining spaces that didn't make a full tab stop
12774                if spaces_count > 0 {
12775                    reindented_line.extend(&space_cache[spaces_count - 1]);
12776                }
12777                // If we consume an extra character that was not indentation, add it back
12778                if let Some(extra_char) = first_non_indent_char {
12779                    reindented_line.push(extra_char);
12780                }
12781                // Append the rest of the line and replace old reference with new one
12782                reindented_line.extend(chars);
12783                *line = Cow::Owned(reindented_line.clone());
12784                reindented_line.clear();
12785            }
12786        });
12787    }
12788
12789    pub fn convert_to_upper_case(
12790        &mut self,
12791        _: &ConvertToUpperCase,
12792        window: &mut Window,
12793        cx: &mut Context<Self>,
12794    ) {
12795        self.manipulate_text(window, cx, |text| text.to_uppercase())
12796    }
12797
12798    pub fn convert_to_lower_case(
12799        &mut self,
12800        _: &ConvertToLowerCase,
12801        window: &mut Window,
12802        cx: &mut Context<Self>,
12803    ) {
12804        self.manipulate_text(window, cx, |text| text.to_lowercase())
12805    }
12806
12807    pub fn convert_to_title_case(
12808        &mut self,
12809        _: &ConvertToTitleCase,
12810        window: &mut Window,
12811        cx: &mut Context<Self>,
12812    ) {
12813        self.manipulate_text(window, cx, |text| {
12814            Self::convert_text_case(text, Case::Title)
12815        })
12816    }
12817
12818    pub fn convert_to_snake_case(
12819        &mut self,
12820        _: &ConvertToSnakeCase,
12821        window: &mut Window,
12822        cx: &mut Context<Self>,
12823    ) {
12824        self.manipulate_text(window, cx, |text| {
12825            Self::convert_text_case(text, Case::Snake)
12826        })
12827    }
12828
12829    pub fn convert_to_kebab_case(
12830        &mut self,
12831        _: &ConvertToKebabCase,
12832        window: &mut Window,
12833        cx: &mut Context<Self>,
12834    ) {
12835        self.manipulate_text(window, cx, |text| {
12836            Self::convert_text_case(text, Case::Kebab)
12837        })
12838    }
12839
12840    pub fn convert_to_upper_camel_case(
12841        &mut self,
12842        _: &ConvertToUpperCamelCase,
12843        window: &mut Window,
12844        cx: &mut Context<Self>,
12845    ) {
12846        self.manipulate_text(window, cx, |text| {
12847            Self::convert_text_case(text, Case::UpperCamel)
12848        })
12849    }
12850
12851    pub fn convert_to_lower_camel_case(
12852        &mut self,
12853        _: &ConvertToLowerCamelCase,
12854        window: &mut Window,
12855        cx: &mut Context<Self>,
12856    ) {
12857        self.manipulate_text(window, cx, |text| {
12858            Self::convert_text_case(text, Case::Camel)
12859        })
12860    }
12861
12862    pub fn convert_to_opposite_case(
12863        &mut self,
12864        _: &ConvertToOppositeCase,
12865        window: &mut Window,
12866        cx: &mut Context<Self>,
12867    ) {
12868        self.manipulate_text(window, cx, |text| {
12869            text.chars()
12870                .fold(String::with_capacity(text.len()), |mut t, c| {
12871                    if c.is_uppercase() {
12872                        t.extend(c.to_lowercase());
12873                    } else {
12874                        t.extend(c.to_uppercase());
12875                    }
12876                    t
12877                })
12878        })
12879    }
12880
12881    pub fn convert_to_sentence_case(
12882        &mut self,
12883        _: &ConvertToSentenceCase,
12884        window: &mut Window,
12885        cx: &mut Context<Self>,
12886    ) {
12887        self.manipulate_text(window, cx, |text| {
12888            Self::convert_text_case(text, Case::Sentence)
12889        })
12890    }
12891
12892    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12893        self.manipulate_text(window, cx, |text| {
12894            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12895            if has_upper_case_characters {
12896                text.to_lowercase()
12897            } else {
12898                text.to_uppercase()
12899            }
12900        })
12901    }
12902
12903    pub fn convert_to_rot13(
12904        &mut self,
12905        _: &ConvertToRot13,
12906        window: &mut Window,
12907        cx: &mut Context<Self>,
12908    ) {
12909        self.manipulate_text(window, cx, |text| {
12910            text.chars()
12911                .map(|c| match c {
12912                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12913                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12914                    _ => c,
12915                })
12916                .collect()
12917        })
12918    }
12919
12920    fn convert_text_case(text: &str, case: Case) -> String {
12921        text.lines()
12922            .map(|line| {
12923                let trimmed_start = line.trim_start();
12924                let leading = &line[..line.len() - trimmed_start.len()];
12925                let trimmed = trimmed_start.trim_end();
12926                let trailing = &trimmed_start[trimmed.len()..];
12927                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12928            })
12929            .join("\n")
12930    }
12931
12932    pub fn convert_to_rot47(
12933        &mut self,
12934        _: &ConvertToRot47,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        self.manipulate_text(window, cx, |text| {
12939            text.chars()
12940                .map(|c| {
12941                    let code_point = c as u32;
12942                    if code_point >= 33 && code_point <= 126 {
12943                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12944                    }
12945                    c
12946                })
12947                .collect()
12948        })
12949    }
12950
12951    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12952    where
12953        Fn: FnMut(&str) -> String,
12954    {
12955        let buffer = self.buffer.read(cx).snapshot(cx);
12956
12957        let mut new_selections = Vec::new();
12958        let mut edits = Vec::new();
12959        let mut selection_adjustment = 0isize;
12960
12961        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12962            let selection_is_empty = selection.is_empty();
12963
12964            let (start, end) = if selection_is_empty {
12965                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12966                (word_range.start, word_range.end)
12967            } else {
12968                (
12969                    buffer.point_to_offset(selection.start),
12970                    buffer.point_to_offset(selection.end),
12971                )
12972            };
12973
12974            let text = buffer.text_for_range(start..end).collect::<String>();
12975            let old_length = text.len() as isize;
12976            let text = callback(&text);
12977
12978            new_selections.push(Selection {
12979                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12980                end: MultiBufferOffset(
12981                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12982                ),
12983                goal: SelectionGoal::None,
12984                id: selection.id,
12985                reversed: selection.reversed,
12986            });
12987
12988            selection_adjustment += old_length - text.len() as isize;
12989
12990            edits.push((start..end, text));
12991        }
12992
12993        self.transact(window, cx, |this, window, cx| {
12994            this.buffer.update(cx, |buffer, cx| {
12995                buffer.edit(edits, None, cx);
12996            });
12997
12998            this.change_selections(Default::default(), window, cx, |s| {
12999                s.select(new_selections);
13000            });
13001
13002            this.request_autoscroll(Autoscroll::fit(), cx);
13003        });
13004    }
13005
13006    pub fn move_selection_on_drop(
13007        &mut self,
13008        selection: &Selection<Anchor>,
13009        target: DisplayPoint,
13010        is_cut: bool,
13011        window: &mut Window,
13012        cx: &mut Context<Self>,
13013    ) {
13014        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13015        let buffer = display_map.buffer_snapshot();
13016        let mut edits = Vec::new();
13017        let insert_point = display_map
13018            .clip_point(target, Bias::Left)
13019            .to_point(&display_map);
13020        let text = buffer
13021            .text_for_range(selection.start..selection.end)
13022            .collect::<String>();
13023        if is_cut {
13024            edits.push(((selection.start..selection.end), String::new()));
13025        }
13026        let insert_anchor = buffer.anchor_before(insert_point);
13027        edits.push(((insert_anchor..insert_anchor), text));
13028        let last_edit_start = insert_anchor.bias_left(buffer);
13029        let last_edit_end = insert_anchor.bias_right(buffer);
13030        self.transact(window, cx, |this, window, cx| {
13031            this.buffer.update(cx, |buffer, cx| {
13032                buffer.edit(edits, None, cx);
13033            });
13034            this.change_selections(Default::default(), window, cx, |s| {
13035                s.select_anchor_ranges([last_edit_start..last_edit_end]);
13036            });
13037        });
13038    }
13039
13040    pub fn clear_selection_drag_state(&mut self) {
13041        self.selection_drag_state = SelectionDragState::None;
13042    }
13043
13044    pub fn duplicate(
13045        &mut self,
13046        upwards: bool,
13047        whole_lines: bool,
13048        window: &mut Window,
13049        cx: &mut Context<Self>,
13050    ) {
13051        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13052
13053        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13054        let buffer = display_map.buffer_snapshot();
13055        let selections = self.selections.all::<Point>(&display_map);
13056
13057        let mut edits = Vec::new();
13058        let mut selections_iter = selections.iter().peekable();
13059        while let Some(selection) = selections_iter.next() {
13060            let mut rows = selection.spanned_rows(false, &display_map);
13061            // duplicate line-wise
13062            if whole_lines || selection.start == selection.end {
13063                // Avoid duplicating the same lines twice.
13064                while let Some(next_selection) = selections_iter.peek() {
13065                    let next_rows = next_selection.spanned_rows(false, &display_map);
13066                    if next_rows.start < rows.end {
13067                        rows.end = next_rows.end;
13068                        selections_iter.next().unwrap();
13069                    } else {
13070                        break;
13071                    }
13072                }
13073
13074                // Copy the text from the selected row region and splice it either at the start
13075                // or end of the region.
13076                let start = Point::new(rows.start.0, 0);
13077                let end = Point::new(
13078                    rows.end.previous_row().0,
13079                    buffer.line_len(rows.end.previous_row()),
13080                );
13081
13082                let mut text = buffer.text_for_range(start..end).collect::<String>();
13083
13084                let insert_location = if upwards {
13085                    // When duplicating upward, we need to insert before the current line.
13086                    // If we're on the last line and it doesn't end with a newline,
13087                    // we need to add a newline before the duplicated content.
13088                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13089                        && buffer.max_point().column > 0
13090                        && !text.ends_with('\n');
13091
13092                    if needs_leading_newline {
13093                        text.insert(0, '\n');
13094                        end
13095                    } else {
13096                        text.push('\n');
13097                        Point::new(rows.start.0, 0)
13098                    }
13099                } else {
13100                    text.push('\n');
13101                    start
13102                };
13103                edits.push((insert_location..insert_location, text));
13104            } else {
13105                // duplicate character-wise
13106                let start = selection.start;
13107                let end = selection.end;
13108                let text = buffer.text_for_range(start..end).collect::<String>();
13109                edits.push((selection.end..selection.end, text));
13110            }
13111        }
13112
13113        self.transact(window, cx, |this, window, cx| {
13114            this.buffer.update(cx, |buffer, cx| {
13115                buffer.edit(edits, None, cx);
13116            });
13117
13118            // When duplicating upward with whole lines, move the cursor to the duplicated line
13119            if upwards && whole_lines {
13120                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13121
13122                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13123                    let mut new_ranges = Vec::new();
13124                    let selections = s.all::<Point>(&display_map);
13125                    let mut selections_iter = selections.iter().peekable();
13126
13127                    while let Some(first_selection) = selections_iter.next() {
13128                        // Group contiguous selections together to find the total row span
13129                        let mut group_selections = vec![first_selection];
13130                        let mut rows = first_selection.spanned_rows(false, &display_map);
13131
13132                        while let Some(next_selection) = selections_iter.peek() {
13133                            let next_rows = next_selection.spanned_rows(false, &display_map);
13134                            if next_rows.start < rows.end {
13135                                rows.end = next_rows.end;
13136                                group_selections.push(selections_iter.next().unwrap());
13137                            } else {
13138                                break;
13139                            }
13140                        }
13141
13142                        let row_count = rows.end.0 - rows.start.0;
13143
13144                        // Move all selections in this group up by the total number of duplicated rows
13145                        for selection in group_selections {
13146                            let new_start = Point::new(
13147                                selection.start.row.saturating_sub(row_count),
13148                                selection.start.column,
13149                            );
13150
13151                            let new_end = Point::new(
13152                                selection.end.row.saturating_sub(row_count),
13153                                selection.end.column,
13154                            );
13155
13156                            new_ranges.push(new_start..new_end);
13157                        }
13158                    }
13159
13160                    s.select_ranges(new_ranges);
13161                });
13162            }
13163
13164            this.request_autoscroll(Autoscroll::fit(), cx);
13165        });
13166    }
13167
13168    pub fn duplicate_line_up(
13169        &mut self,
13170        _: &DuplicateLineUp,
13171        window: &mut Window,
13172        cx: &mut Context<Self>,
13173    ) {
13174        self.duplicate(true, true, window, cx);
13175    }
13176
13177    pub fn duplicate_line_down(
13178        &mut self,
13179        _: &DuplicateLineDown,
13180        window: &mut Window,
13181        cx: &mut Context<Self>,
13182    ) {
13183        self.duplicate(false, true, window, cx);
13184    }
13185
13186    pub fn duplicate_selection(
13187        &mut self,
13188        _: &DuplicateSelection,
13189        window: &mut Window,
13190        cx: &mut Context<Self>,
13191    ) {
13192        self.duplicate(false, false, window, cx);
13193    }
13194
13195    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13196        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13197        if self.mode.is_single_line() {
13198            cx.propagate();
13199            return;
13200        }
13201
13202        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13203        let buffer = self.buffer.read(cx).snapshot(cx);
13204
13205        let mut edits = Vec::new();
13206        let mut unfold_ranges = Vec::new();
13207        let mut refold_creases = Vec::new();
13208
13209        let selections = self.selections.all::<Point>(&display_map);
13210        let mut selections = selections.iter().peekable();
13211        let mut contiguous_row_selections = Vec::new();
13212        let mut new_selections = Vec::new();
13213
13214        while let Some(selection) = selections.next() {
13215            // Find all the selections that span a contiguous row range
13216            let (start_row, end_row) = consume_contiguous_rows(
13217                &mut contiguous_row_selections,
13218                selection,
13219                &display_map,
13220                &mut selections,
13221            );
13222
13223            // Move the text spanned by the row range to be before the line preceding the row range
13224            if start_row.0 > 0 {
13225                let range_to_move = Point::new(
13226                    start_row.previous_row().0,
13227                    buffer.line_len(start_row.previous_row()),
13228                )
13229                    ..Point::new(
13230                        end_row.previous_row().0,
13231                        buffer.line_len(end_row.previous_row()),
13232                    );
13233                let insertion_point = display_map
13234                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13235                    .0;
13236
13237                // Don't move lines across excerpts
13238                if buffer
13239                    .excerpt_containing(insertion_point..range_to_move.end)
13240                    .is_some()
13241                {
13242                    let text = buffer
13243                        .text_for_range(range_to_move.clone())
13244                        .flat_map(|s| s.chars())
13245                        .skip(1)
13246                        .chain(['\n'])
13247                        .collect::<String>();
13248
13249                    edits.push((
13250                        buffer.anchor_after(range_to_move.start)
13251                            ..buffer.anchor_before(range_to_move.end),
13252                        String::new(),
13253                    ));
13254                    let insertion_anchor = buffer.anchor_after(insertion_point);
13255                    edits.push((insertion_anchor..insertion_anchor, text));
13256
13257                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13258
13259                    // Move selections up
13260                    new_selections.extend(contiguous_row_selections.drain(..).map(
13261                        |mut selection| {
13262                            selection.start.row -= row_delta;
13263                            selection.end.row -= row_delta;
13264                            selection
13265                        },
13266                    ));
13267
13268                    // Move folds up
13269                    unfold_ranges.push(range_to_move.clone());
13270                    for fold in display_map.folds_in_range(
13271                        buffer.anchor_before(range_to_move.start)
13272                            ..buffer.anchor_after(range_to_move.end),
13273                    ) {
13274                        let mut start = fold.range.start.to_point(&buffer);
13275                        let mut end = fold.range.end.to_point(&buffer);
13276                        start.row -= row_delta;
13277                        end.row -= row_delta;
13278                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13279                    }
13280                }
13281            }
13282
13283            // If we didn't move line(s), preserve the existing selections
13284            new_selections.append(&mut contiguous_row_selections);
13285        }
13286
13287        self.transact(window, cx, |this, window, cx| {
13288            this.unfold_ranges(&unfold_ranges, true, true, cx);
13289            this.buffer.update(cx, |buffer, cx| {
13290                for (range, text) in edits {
13291                    buffer.edit([(range, text)], None, cx);
13292                }
13293            });
13294            this.fold_creases(refold_creases, true, window, cx);
13295            this.change_selections(Default::default(), window, cx, |s| {
13296                s.select(new_selections);
13297            })
13298        });
13299    }
13300
13301    pub fn move_line_down(
13302        &mut self,
13303        _: &MoveLineDown,
13304        window: &mut Window,
13305        cx: &mut Context<Self>,
13306    ) {
13307        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13308        if self.mode.is_single_line() {
13309            cx.propagate();
13310            return;
13311        }
13312
13313        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13314        let buffer = self.buffer.read(cx).snapshot(cx);
13315
13316        let mut edits = Vec::new();
13317        let mut unfold_ranges = Vec::new();
13318        let mut refold_creases = Vec::new();
13319
13320        let selections = self.selections.all::<Point>(&display_map);
13321        let mut selections = selections.iter().peekable();
13322        let mut contiguous_row_selections = Vec::new();
13323        let mut new_selections = Vec::new();
13324
13325        while let Some(selection) = selections.next() {
13326            // Find all the selections that span a contiguous row range
13327            let (start_row, end_row) = consume_contiguous_rows(
13328                &mut contiguous_row_selections,
13329                selection,
13330                &display_map,
13331                &mut selections,
13332            );
13333
13334            // Move the text spanned by the row range to be after the last line of the row range
13335            if end_row.0 <= buffer.max_point().row {
13336                let range_to_move =
13337                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13338                let insertion_point = display_map
13339                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13340                    .0;
13341
13342                // Don't move lines across excerpt boundaries
13343                if buffer
13344                    .excerpt_containing(range_to_move.start..insertion_point)
13345                    .is_some()
13346                {
13347                    let mut text = String::from("\n");
13348                    text.extend(buffer.text_for_range(range_to_move.clone()));
13349                    text.pop(); // Drop trailing newline
13350                    edits.push((
13351                        buffer.anchor_after(range_to_move.start)
13352                            ..buffer.anchor_before(range_to_move.end),
13353                        String::new(),
13354                    ));
13355                    let insertion_anchor = buffer.anchor_after(insertion_point);
13356                    edits.push((insertion_anchor..insertion_anchor, text));
13357
13358                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13359
13360                    // Move selections down
13361                    new_selections.extend(contiguous_row_selections.drain(..).map(
13362                        |mut selection| {
13363                            selection.start.row += row_delta;
13364                            selection.end.row += row_delta;
13365                            selection
13366                        },
13367                    ));
13368
13369                    // Move folds down
13370                    unfold_ranges.push(range_to_move.clone());
13371                    for fold in display_map.folds_in_range(
13372                        buffer.anchor_before(range_to_move.start)
13373                            ..buffer.anchor_after(range_to_move.end),
13374                    ) {
13375                        let mut start = fold.range.start.to_point(&buffer);
13376                        let mut end = fold.range.end.to_point(&buffer);
13377                        start.row += row_delta;
13378                        end.row += row_delta;
13379                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13380                    }
13381                }
13382            }
13383
13384            // If we didn't move line(s), preserve the existing selections
13385            new_selections.append(&mut contiguous_row_selections);
13386        }
13387
13388        self.transact(window, cx, |this, window, cx| {
13389            this.unfold_ranges(&unfold_ranges, true, true, cx);
13390            this.buffer.update(cx, |buffer, cx| {
13391                for (range, text) in edits {
13392                    buffer.edit([(range, text)], None, cx);
13393                }
13394            });
13395            this.fold_creases(refold_creases, true, window, cx);
13396            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13397        });
13398    }
13399
13400    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13401        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13402        let text_layout_details = &self.text_layout_details(window, cx);
13403        self.transact(window, cx, |this, window, cx| {
13404            let edits = this.change_selections(Default::default(), window, cx, |s| {
13405                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13406                s.move_with(&mut |display_map, selection| {
13407                    if !selection.is_empty() {
13408                        return;
13409                    }
13410
13411                    let mut head = selection.head();
13412                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13413                    if head.column() == display_map.line_len(head.row()) {
13414                        transpose_offset = display_map
13415                            .buffer_snapshot()
13416                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13417                    }
13418
13419                    if transpose_offset == MultiBufferOffset(0) {
13420                        return;
13421                    }
13422
13423                    *head.column_mut() += 1;
13424                    head = display_map.clip_point(head, Bias::Right);
13425                    let goal = SelectionGoal::HorizontalPosition(
13426                        display_map
13427                            .x_for_display_point(head, text_layout_details)
13428                            .into(),
13429                    );
13430                    selection.collapse_to(head, goal);
13431
13432                    let transpose_start = display_map
13433                        .buffer_snapshot()
13434                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13435                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13436                        let transpose_end = display_map
13437                            .buffer_snapshot()
13438                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13439                        if let Some(ch) = display_map
13440                            .buffer_snapshot()
13441                            .chars_at(transpose_start)
13442                            .next()
13443                        {
13444                            edits.push((transpose_start..transpose_offset, String::new()));
13445                            edits.push((transpose_end..transpose_end, ch.to_string()));
13446                        }
13447                    }
13448                });
13449                edits
13450            });
13451            this.buffer
13452                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13453            let selections = this
13454                .selections
13455                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13456            this.change_selections(Default::default(), window, cx, |s| {
13457                s.select(selections);
13458            });
13459        });
13460    }
13461
13462    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13463        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13464        if self.mode.is_single_line() {
13465            cx.propagate();
13466            return;
13467        }
13468
13469        self.rewrap_impl(RewrapOptions::default(), cx)
13470    }
13471
13472    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13473        let buffer = self.buffer.read(cx).snapshot(cx);
13474        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13475
13476        #[derive(Clone, Debug, PartialEq)]
13477        enum CommentFormat {
13478            /// single line comment, with prefix for line
13479            Line(String),
13480            /// single line within a block comment, with prefix for line
13481            BlockLine(String),
13482            /// a single line of a block comment that includes the initial delimiter
13483            BlockCommentWithStart(BlockCommentConfig),
13484            /// a single line of a block comment that includes the ending delimiter
13485            BlockCommentWithEnd(BlockCommentConfig),
13486        }
13487
13488        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13489        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13490            let language_settings = buffer.language_settings_at(selection.head(), cx);
13491            let language_scope = buffer.language_scope_at(selection.head());
13492
13493            let indent_and_prefix_for_row =
13494                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13495                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13496                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13497                        &language_scope
13498                    {
13499                        let indent_end = Point::new(row, indent.len);
13500                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13501                        let line_text_after_indent = buffer
13502                            .text_for_range(indent_end..line_end)
13503                            .collect::<String>();
13504
13505                        let is_within_comment_override = buffer
13506                            .language_scope_at(indent_end)
13507                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13508                        let comment_delimiters = if is_within_comment_override {
13509                            // we are within a comment syntax node, but we don't
13510                            // yet know what kind of comment: block, doc or line
13511                            match (
13512                                language_scope.documentation_comment(),
13513                                language_scope.block_comment(),
13514                            ) {
13515                                (Some(config), _) | (_, Some(config))
13516                                    if buffer.contains_str_at(indent_end, &config.start) =>
13517                                {
13518                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13519                                }
13520                                (Some(config), _) | (_, Some(config))
13521                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13522                                {
13523                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13524                                }
13525                                (Some(config), _) | (_, Some(config))
13526                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13527                                {
13528                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13529                                }
13530                                (_, _) => language_scope
13531                                    .line_comment_prefixes()
13532                                    .iter()
13533                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13534                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13535                            }
13536                        } else {
13537                            // we not in an overridden comment node, but we may
13538                            // be within a non-overridden line comment node
13539                            language_scope
13540                                .line_comment_prefixes()
13541                                .iter()
13542                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13543                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13544                        };
13545
13546                        let rewrap_prefix = language_scope
13547                            .rewrap_prefixes()
13548                            .iter()
13549                            .find_map(|prefix_regex| {
13550                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13551                                    if mat.start() == 0 {
13552                                        Some(mat.as_str().to_string())
13553                                    } else {
13554                                        None
13555                                    }
13556                                })
13557                            })
13558                            .flatten();
13559                        (comment_delimiters, rewrap_prefix)
13560                    } else {
13561                        (None, None)
13562                    };
13563                    (indent, comment_prefix, rewrap_prefix)
13564                };
13565
13566            let mut start_row = selection.start.row;
13567            let mut end_row = selection.end.row;
13568
13569            if selection.is_empty() {
13570                let cursor_row = selection.start.row;
13571
13572                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13573                let line_prefix = match &comment_prefix {
13574                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13575                        Some(prefix.as_str())
13576                    }
13577                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13578                        prefix, ..
13579                    })) => Some(prefix.as_ref()),
13580                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13581                        start: _,
13582                        end: _,
13583                        prefix,
13584                        tab_size,
13585                    })) => {
13586                        indent_size.len += tab_size;
13587                        Some(prefix.as_ref())
13588                    }
13589                    None => None,
13590                };
13591                let indent_prefix = indent_size.chars().collect::<String>();
13592                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13593
13594                'expand_upwards: while start_row > 0 {
13595                    let prev_row = start_row - 1;
13596                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13597                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13598                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13599                    {
13600                        start_row = prev_row;
13601                    } else {
13602                        break 'expand_upwards;
13603                    }
13604                }
13605
13606                'expand_downwards: while end_row < buffer.max_point().row {
13607                    let next_row = end_row + 1;
13608                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13609                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13610                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13611                    {
13612                        end_row = next_row;
13613                    } else {
13614                        break 'expand_downwards;
13615                    }
13616                }
13617            }
13618
13619            let mut non_blank_rows_iter = (start_row..=end_row)
13620                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13621                .peekable();
13622
13623            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13624                row
13625            } else {
13626                return Vec::new();
13627            };
13628
13629            let mut ranges = Vec::new();
13630
13631            let mut current_range_start = first_row;
13632            let mut prev_row = first_row;
13633            let (
13634                mut current_range_indent,
13635                mut current_range_comment_delimiters,
13636                mut current_range_rewrap_prefix,
13637            ) = indent_and_prefix_for_row(first_row);
13638
13639            for row in non_blank_rows_iter.skip(1) {
13640                let has_paragraph_break = row > prev_row + 1;
13641
13642                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13643                    indent_and_prefix_for_row(row);
13644
13645                let has_indent_change = row_indent != current_range_indent;
13646                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13647
13648                let has_boundary_change = has_comment_change
13649                    || row_rewrap_prefix.is_some()
13650                    || (has_indent_change && current_range_comment_delimiters.is_some());
13651
13652                if has_paragraph_break || has_boundary_change {
13653                    ranges.push((
13654                        language_settings.clone(),
13655                        Point::new(current_range_start, 0)
13656                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13657                        current_range_indent,
13658                        current_range_comment_delimiters.clone(),
13659                        current_range_rewrap_prefix.clone(),
13660                    ));
13661                    current_range_start = row;
13662                    current_range_indent = row_indent;
13663                    current_range_comment_delimiters = row_comment_delimiters;
13664                    current_range_rewrap_prefix = row_rewrap_prefix;
13665                }
13666                prev_row = row;
13667            }
13668
13669            ranges.push((
13670                language_settings.clone(),
13671                Point::new(current_range_start, 0)
13672                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13673                current_range_indent,
13674                current_range_comment_delimiters,
13675                current_range_rewrap_prefix,
13676            ));
13677
13678            ranges
13679        });
13680
13681        let mut edits = Vec::new();
13682        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13683
13684        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13685            wrap_ranges
13686        {
13687            let start_row = wrap_range.start.row;
13688            let end_row = wrap_range.end.row;
13689
13690            // Skip selections that overlap with a range that has already been rewrapped.
13691            let selection_range = start_row..end_row;
13692            if rewrapped_row_ranges
13693                .iter()
13694                .any(|range| range.overlaps(&selection_range))
13695            {
13696                continue;
13697            }
13698
13699            let tab_size = language_settings.tab_size;
13700
13701            let (line_prefix, inside_comment) = match &comment_prefix {
13702                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13703                    (Some(prefix.as_str()), true)
13704                }
13705                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13706                    (Some(prefix.as_ref()), true)
13707                }
13708                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13709                    start: _,
13710                    end: _,
13711                    prefix,
13712                    tab_size,
13713                })) => {
13714                    indent_size.len += tab_size;
13715                    (Some(prefix.as_ref()), true)
13716                }
13717                None => (None, false),
13718            };
13719            let indent_prefix = indent_size.chars().collect::<String>();
13720            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13721
13722            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13723                RewrapBehavior::InComments => inside_comment,
13724                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13725                RewrapBehavior::Anywhere => true,
13726            };
13727
13728            let should_rewrap = options.override_language_settings
13729                || allow_rewrap_based_on_language
13730                || self.hard_wrap.is_some();
13731            if !should_rewrap {
13732                continue;
13733            }
13734
13735            let start = Point::new(start_row, 0);
13736            let start_offset = ToOffset::to_offset(&start, &buffer);
13737            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13738            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13739            let mut first_line_delimiter = None;
13740            let mut last_line_delimiter = None;
13741            let Some(lines_without_prefixes) = selection_text
13742                .lines()
13743                .enumerate()
13744                .map(|(ix, line)| {
13745                    let line_trimmed = line.trim_start();
13746                    if rewrap_prefix.is_some() && ix > 0 {
13747                        Ok(line_trimmed)
13748                    } else if let Some(
13749                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13750                            start,
13751                            prefix,
13752                            end,
13753                            tab_size,
13754                        })
13755                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13756                            start,
13757                            prefix,
13758                            end,
13759                            tab_size,
13760                        }),
13761                    ) = &comment_prefix
13762                    {
13763                        let line_trimmed = line_trimmed
13764                            .strip_prefix(start.as_ref())
13765                            .map(|s| {
13766                                let mut indent_size = indent_size;
13767                                indent_size.len -= tab_size;
13768                                let indent_prefix: String = indent_size.chars().collect();
13769                                first_line_delimiter = Some((indent_prefix, start));
13770                                s.trim_start()
13771                            })
13772                            .unwrap_or(line_trimmed);
13773                        let line_trimmed = line_trimmed
13774                            .strip_suffix(end.as_ref())
13775                            .map(|s| {
13776                                last_line_delimiter = Some(end);
13777                                s.trim_end()
13778                            })
13779                            .unwrap_or(line_trimmed);
13780                        let line_trimmed = line_trimmed
13781                            .strip_prefix(prefix.as_ref())
13782                            .unwrap_or(line_trimmed);
13783                        Ok(line_trimmed)
13784                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13785                        line_trimmed.strip_prefix(prefix).with_context(|| {
13786                            format!("line did not start with prefix {prefix:?}: {line:?}")
13787                        })
13788                    } else {
13789                        line_trimmed
13790                            .strip_prefix(&line_prefix.trim_start())
13791                            .with_context(|| {
13792                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13793                            })
13794                    }
13795                })
13796                .collect::<Result<Vec<_>, _>>()
13797                .log_err()
13798            else {
13799                continue;
13800            };
13801
13802            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13803                buffer
13804                    .language_settings_at(Point::new(start_row, 0), cx)
13805                    .preferred_line_length as usize
13806            });
13807
13808            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13809                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13810            } else {
13811                line_prefix.clone()
13812            };
13813
13814            let wrapped_text = {
13815                let mut wrapped_text = wrap_with_prefix(
13816                    line_prefix,
13817                    subsequent_lines_prefix,
13818                    lines_without_prefixes.join("\n"),
13819                    wrap_column,
13820                    tab_size,
13821                    options.preserve_existing_whitespace,
13822                );
13823
13824                if let Some((indent, delimiter)) = first_line_delimiter {
13825                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13826                }
13827                if let Some(last_line) = last_line_delimiter {
13828                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13829                }
13830
13831                wrapped_text
13832            };
13833
13834            // TODO: should always use char-based diff while still supporting cursor behavior that
13835            // matches vim.
13836            let mut diff_options = DiffOptions::default();
13837            if options.override_language_settings {
13838                diff_options.max_word_diff_len = 0;
13839                diff_options.max_word_diff_line_count = 0;
13840            } else {
13841                diff_options.max_word_diff_len = usize::MAX;
13842                diff_options.max_word_diff_line_count = usize::MAX;
13843            }
13844
13845            for (old_range, new_text) in
13846                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13847            {
13848                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13849                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13850                edits.push((edit_start..edit_end, new_text));
13851            }
13852
13853            rewrapped_row_ranges.push(start_row..=end_row);
13854        }
13855
13856        self.buffer
13857            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13858    }
13859
13860    pub fn cut_common(
13861        &mut self,
13862        cut_no_selection_line: bool,
13863        window: &mut Window,
13864        cx: &mut Context<Self>,
13865    ) -> ClipboardItem {
13866        let mut text = String::new();
13867        let buffer = self.buffer.read(cx).snapshot(cx);
13868        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13869        let mut clipboard_selections = Vec::with_capacity(selections.len());
13870        {
13871            let max_point = buffer.max_point();
13872            let mut is_first = true;
13873            let mut prev_selection_was_entire_line = false;
13874            for selection in &mut selections {
13875                let is_entire_line =
13876                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13877                if is_entire_line {
13878                    selection.start = Point::new(selection.start.row, 0);
13879                    if !selection.is_empty() && selection.end.column == 0 {
13880                        selection.end = cmp::min(max_point, selection.end);
13881                    } else {
13882                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13883                    }
13884                    selection.goal = SelectionGoal::None;
13885                }
13886                if is_first {
13887                    is_first = false;
13888                } else if !prev_selection_was_entire_line {
13889                    text += "\n";
13890                }
13891                prev_selection_was_entire_line = is_entire_line;
13892                let mut len = 0;
13893                for chunk in buffer.text_for_range(selection.start..selection.end) {
13894                    text.push_str(chunk);
13895                    len += chunk.len();
13896                }
13897
13898                clipboard_selections.push(ClipboardSelection::for_buffer(
13899                    len,
13900                    is_entire_line,
13901                    selection.range(),
13902                    &buffer,
13903                    self.project.as_ref(),
13904                    cx,
13905                ));
13906            }
13907        }
13908
13909        self.transact(window, cx, |this, window, cx| {
13910            this.change_selections(Default::default(), window, cx, |s| {
13911                s.select(selections);
13912            });
13913            this.insert("", window, cx);
13914        });
13915        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13916    }
13917
13918    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13919        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13920        let item = self.cut_common(true, window, cx);
13921        cx.write_to_clipboard(item);
13922    }
13923
13924    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13925        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13926        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13927            s.move_with(&mut |snapshot, sel| {
13928                if sel.is_empty() {
13929                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13930                }
13931                if sel.is_empty() {
13932                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13933                }
13934            });
13935        });
13936        let item = self.cut_common(false, window, cx);
13937        cx.set_global(KillRing(item))
13938    }
13939
13940    pub fn kill_ring_yank(
13941        &mut self,
13942        _: &KillRingYank,
13943        window: &mut Window,
13944        cx: &mut Context<Self>,
13945    ) {
13946        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13947        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13948            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13949                (kill_ring.text().to_string(), kill_ring.metadata_json())
13950            } else {
13951                return;
13952            }
13953        } else {
13954            return;
13955        };
13956        self.do_paste(&text, metadata, false, window, cx);
13957    }
13958
13959    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13960        self.do_copy(true, cx);
13961    }
13962
13963    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13964        self.do_copy(false, cx);
13965    }
13966
13967    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13968        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13969        let buffer = self.buffer.read(cx).read(cx);
13970        let mut text = String::new();
13971        let mut clipboard_selections = Vec::with_capacity(selections.len());
13972
13973        let max_point = buffer.max_point();
13974        let mut is_first = true;
13975        for selection in &selections {
13976            let mut start = selection.start;
13977            let mut end = selection.end;
13978            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13979            let mut add_trailing_newline = false;
13980            if is_entire_line {
13981                start = Point::new(start.row, 0);
13982                let next_line_start = Point::new(end.row + 1, 0);
13983                if next_line_start <= max_point {
13984                    end = next_line_start;
13985                } else {
13986                    // We're on the last line without a trailing newline.
13987                    // Copy to the end of the line and add a newline afterwards.
13988                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13989                    add_trailing_newline = true;
13990                }
13991            }
13992
13993            let mut trimmed_selections = Vec::new();
13994            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13995                let row = MultiBufferRow(start.row);
13996                let first_indent = buffer.indent_size_for_line(row);
13997                if first_indent.len == 0 || start.column > first_indent.len {
13998                    trimmed_selections.push(start..end);
13999                } else {
14000                    trimmed_selections.push(
14001                        Point::new(row.0, first_indent.len)
14002                            ..Point::new(row.0, buffer.line_len(row)),
14003                    );
14004                    for row in start.row + 1..=end.row {
14005                        let mut line_len = buffer.line_len(MultiBufferRow(row));
14006                        if row == end.row {
14007                            line_len = end.column;
14008                        }
14009                        if line_len == 0 {
14010                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
14011                            continue;
14012                        }
14013                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
14014                        if row_indent_size.len >= first_indent.len {
14015                            trimmed_selections
14016                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
14017                        } else {
14018                            trimmed_selections.clear();
14019                            trimmed_selections.push(start..end);
14020                            break;
14021                        }
14022                    }
14023                }
14024            } else {
14025                trimmed_selections.push(start..end);
14026            }
14027
14028            let is_multiline_trim = trimmed_selections.len() > 1;
14029            let mut selection_len: usize = 0;
14030            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
14031
14032            for trimmed_range in trimmed_selections {
14033                if is_first {
14034                    is_first = false;
14035                } else if is_multiline_trim || !prev_selection_was_entire_line {
14036                    text.push('\n');
14037                    if is_multiline_trim {
14038                        selection_len += 1;
14039                    }
14040                }
14041                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
14042                    text.push_str(chunk);
14043                    selection_len += chunk.len();
14044                }
14045                if add_trailing_newline {
14046                    text.push('\n');
14047                    selection_len += 1;
14048                }
14049            }
14050
14051            clipboard_selections.push(ClipboardSelection::for_buffer(
14052                selection_len,
14053                is_entire_line,
14054                start..end,
14055                &buffer,
14056                self.project.as_ref(),
14057                cx,
14058            ));
14059        }
14060
14061        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
14062            text,
14063            clipboard_selections,
14064        ));
14065    }
14066
14067    pub fn do_paste(
14068        &mut self,
14069        text: &String,
14070        clipboard_selections: Option<Vec<ClipboardSelection>>,
14071        handle_entire_lines: bool,
14072        window: &mut Window,
14073        cx: &mut Context<Self>,
14074    ) {
14075        if self.read_only(cx) {
14076            return;
14077        }
14078
14079        self.finalize_last_transaction(cx);
14080
14081        let clipboard_text = Cow::Borrowed(text.as_str());
14082
14083        self.transact(window, cx, |this, window, cx| {
14084            let had_active_edit_prediction = this.has_active_edit_prediction();
14085            let display_map = this.display_snapshot(cx);
14086            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14087            let cursor_offset = this
14088                .selections
14089                .last::<MultiBufferOffset>(&display_map)
14090                .head();
14091
14092            if let Some(mut clipboard_selections) = clipboard_selections {
14093                let all_selections_were_entire_line =
14094                    clipboard_selections.iter().all(|s| s.is_entire_line);
14095                let first_selection_indent_column =
14096                    clipboard_selections.first().map(|s| s.first_line_indent);
14097                if clipboard_selections.len() != old_selections.len() {
14098                    clipboard_selections.drain(..);
14099                }
14100                let mut auto_indent_on_paste = true;
14101
14102                this.buffer.update(cx, |buffer, cx| {
14103                    let snapshot = buffer.read(cx);
14104                    auto_indent_on_paste = snapshot
14105                        .language_settings_at(cursor_offset, cx)
14106                        .auto_indent_on_paste;
14107
14108                    let mut start_offset = 0;
14109                    let mut edits = Vec::new();
14110                    let mut original_indent_columns = Vec::new();
14111                    for (ix, selection) in old_selections.iter().enumerate() {
14112                        let to_insert;
14113                        let entire_line;
14114                        let original_indent_column;
14115                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14116                            let end_offset = start_offset + clipboard_selection.len;
14117                            to_insert = &clipboard_text[start_offset..end_offset];
14118                            entire_line = clipboard_selection.is_entire_line;
14119                            start_offset = if entire_line {
14120                                end_offset
14121                            } else {
14122                                end_offset + 1
14123                            };
14124                            original_indent_column = Some(clipboard_selection.first_line_indent);
14125                        } else {
14126                            to_insert = &*clipboard_text;
14127                            entire_line = all_selections_were_entire_line;
14128                            original_indent_column = first_selection_indent_column
14129                        }
14130
14131                        let (range, to_insert) =
14132                            if selection.is_empty() && handle_entire_lines && entire_line {
14133                                // If the corresponding selection was empty when this slice of the
14134                                // clipboard text was written, then the entire line containing the
14135                                // selection was copied. If this selection is also currently empty,
14136                                // then paste the line before the current line of the buffer.
14137                                let column = selection.start.to_point(&snapshot).column as usize;
14138                                let line_start = selection.start - column;
14139                                (line_start..line_start, Cow::Borrowed(to_insert))
14140                            } else {
14141                                let language = snapshot.language_at(selection.head());
14142                                let range = selection.range();
14143                                if let Some(language) = language
14144                                    && language.name() == "Markdown"
14145                                {
14146                                    edit_for_markdown_paste(
14147                                        &snapshot,
14148                                        range,
14149                                        to_insert,
14150                                        url::Url::parse(to_insert).ok(),
14151                                    )
14152                                } else {
14153                                    (range, Cow::Borrowed(to_insert))
14154                                }
14155                            };
14156
14157                        edits.push((range, to_insert));
14158                        original_indent_columns.push(original_indent_column);
14159                    }
14160                    drop(snapshot);
14161
14162                    buffer.edit(
14163                        edits,
14164                        if auto_indent_on_paste {
14165                            Some(AutoindentMode::Block {
14166                                original_indent_columns,
14167                            })
14168                        } else {
14169                            None
14170                        },
14171                        cx,
14172                    );
14173                });
14174
14175                let selections = this
14176                    .selections
14177                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14178                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14179            } else {
14180                let url = url::Url::parse(&clipboard_text).ok();
14181
14182                let auto_indent_mode = if !clipboard_text.is_empty() {
14183                    Some(AutoindentMode::Block {
14184                        original_indent_columns: Vec::new(),
14185                    })
14186                } else {
14187                    None
14188                };
14189
14190                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14191                    let snapshot = buffer.snapshot(cx);
14192
14193                    let anchors = old_selections
14194                        .iter()
14195                        .map(|s| {
14196                            let anchor = snapshot.anchor_after(s.head());
14197                            s.map(|_| anchor)
14198                        })
14199                        .collect::<Vec<_>>();
14200
14201                    let mut edits = Vec::new();
14202
14203                    // When pasting text without metadata (e.g. copied from an
14204                    // external editor using multiple cursors) and the number of
14205                    // lines matches the number of selections, distribute one
14206                    // line per cursor instead of pasting the whole text at each.
14207                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14208                    let distribute_lines =
14209                        old_selections.len() > 1 && lines.len() == old_selections.len();
14210
14211                    for (ix, selection) in old_selections.iter().enumerate() {
14212                        let language = snapshot.language_at(selection.head());
14213                        let range = selection.range();
14214
14215                        let text_for_cursor: &str = if distribute_lines {
14216                            lines[ix]
14217                        } else {
14218                            &clipboard_text
14219                        };
14220
14221                        let (edit_range, edit_text) = if let Some(language) = language
14222                            && language.name() == "Markdown"
14223                        {
14224                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14225                        } else {
14226                            (range, Cow::Borrowed(text_for_cursor))
14227                        };
14228
14229                        edits.push((edit_range, edit_text));
14230                    }
14231
14232                    drop(snapshot);
14233                    buffer.edit(edits, auto_indent_mode, cx);
14234
14235                    anchors
14236                });
14237
14238                this.change_selections(Default::default(), window, cx, |s| {
14239                    s.select_anchors(selection_anchors);
14240                });
14241            }
14242
14243            //   🤔                 |    ..     | show_in_menu |
14244            // | ..                  |   true        true
14245            // | had_edit_prediction |   false       true
14246
14247            let trigger_in_words =
14248                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14249
14250            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14251        });
14252    }
14253
14254    pub fn diff_clipboard_with_selection(
14255        &mut self,
14256        _: &DiffClipboardWithSelection,
14257        window: &mut Window,
14258        cx: &mut Context<Self>,
14259    ) {
14260        let selections = self
14261            .selections
14262            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14263
14264        if selections.is_empty() {
14265            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14266            return;
14267        };
14268
14269        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14270            item.entries().iter().find_map(|entry| match entry {
14271                ClipboardEntry::String(text) => Some(text.text().to_string()),
14272                _ => None,
14273            })
14274        });
14275
14276        let Some(clipboard_text) = clipboard_text else {
14277            log::warn!("Clipboard doesn't contain text.");
14278            return;
14279        };
14280
14281        window.dispatch_action(
14282            Box::new(DiffClipboardWithSelectionData {
14283                clipboard_text,
14284                editor: cx.entity(),
14285            }),
14286            cx,
14287        );
14288    }
14289
14290    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14291        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14292        if let Some(item) = cx.read_from_clipboard() {
14293            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14294                ClipboardEntry::String(s) => Some(s),
14295                _ => None,
14296            });
14297            match clipboard_string {
14298                Some(clipboard_string) => self.do_paste(
14299                    clipboard_string.text(),
14300                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14301                    true,
14302                    window,
14303                    cx,
14304                ),
14305                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14306            }
14307        }
14308    }
14309
14310    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14311        if self.read_only(cx) {
14312            return;
14313        }
14314
14315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14316
14317        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14318            if let Some((selections, _)) =
14319                self.selection_history.transaction(transaction_id).cloned()
14320            {
14321                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14322                    s.select_anchors(selections.to_vec());
14323                });
14324            } else {
14325                log::error!(
14326                    "No entry in selection_history found for undo. \
14327                     This may correspond to a bug where undo does not update the selection. \
14328                     If this is occurring, please add details to \
14329                     https://github.com/zed-industries/zed/issues/22692"
14330                );
14331            }
14332            self.request_autoscroll(Autoscroll::fit(), cx);
14333            self.unmark_text(window, cx);
14334            self.refresh_edit_prediction(true, false, window, cx);
14335            cx.emit(EditorEvent::Edited { transaction_id });
14336            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14337        }
14338    }
14339
14340    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14341        if self.read_only(cx) {
14342            return;
14343        }
14344
14345        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14346
14347        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14348            if let Some((_, Some(selections))) =
14349                self.selection_history.transaction(transaction_id).cloned()
14350            {
14351                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14352                    s.select_anchors(selections.to_vec());
14353                });
14354            } else {
14355                log::error!(
14356                    "No entry in selection_history found for redo. \
14357                     This may correspond to a bug where undo does not update the selection. \
14358                     If this is occurring, please add details to \
14359                     https://github.com/zed-industries/zed/issues/22692"
14360                );
14361            }
14362            self.request_autoscroll(Autoscroll::fit(), cx);
14363            self.unmark_text(window, cx);
14364            self.refresh_edit_prediction(true, false, window, cx);
14365            cx.emit(EditorEvent::Edited { transaction_id });
14366        }
14367    }
14368
14369    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14370        self.buffer
14371            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14372    }
14373
14374    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14375        self.buffer
14376            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14377    }
14378
14379    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14380        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14381        self.change_selections(Default::default(), window, cx, |s| {
14382            s.move_with(&mut |map, selection| {
14383                let cursor = if selection.is_empty() {
14384                    movement::left(map, selection.start)
14385                } else {
14386                    selection.start
14387                };
14388                selection.collapse_to(cursor, SelectionGoal::None);
14389            });
14390        })
14391    }
14392
14393    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14394        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14395        self.change_selections(Default::default(), window, cx, |s| {
14396            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14397        })
14398    }
14399
14400    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14401        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14402        self.change_selections(Default::default(), window, cx, |s| {
14403            s.move_with(&mut |map, selection| {
14404                let cursor = if selection.is_empty() {
14405                    movement::right(map, selection.end)
14406                } else {
14407                    selection.end
14408                };
14409                selection.collapse_to(cursor, SelectionGoal::None)
14410            });
14411        })
14412    }
14413
14414    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14415        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14416        self.change_selections(Default::default(), window, cx, |s| {
14417            s.move_heads_with(&mut |map, head, _| {
14418                (movement::right(map, head), SelectionGoal::None)
14419            });
14420        });
14421    }
14422
14423    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14424        if self.take_rename(true, window, cx).is_some() {
14425            return;
14426        }
14427
14428        if self.mode.is_single_line() {
14429            cx.propagate();
14430            return;
14431        }
14432
14433        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14434
14435        let text_layout_details = &self.text_layout_details(window, cx);
14436        let selection_count = self.selections.count();
14437        let first_selection = self.selections.first_anchor();
14438
14439        self.change_selections(Default::default(), window, cx, |s| {
14440            s.move_with(&mut |map, selection| {
14441                if !selection.is_empty() {
14442                    selection.goal = SelectionGoal::None;
14443                }
14444                let (cursor, goal) = movement::up(
14445                    map,
14446                    selection.start,
14447                    selection.goal,
14448                    false,
14449                    text_layout_details,
14450                );
14451                selection.collapse_to(cursor, goal);
14452            });
14453        });
14454
14455        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14456        {
14457            cx.propagate();
14458        }
14459    }
14460
14461    pub fn move_up_by_lines(
14462        &mut self,
14463        action: &MoveUpByLines,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) {
14467        if self.take_rename(true, window, cx).is_some() {
14468            return;
14469        }
14470
14471        if self.mode.is_single_line() {
14472            cx.propagate();
14473            return;
14474        }
14475
14476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14477
14478        let text_layout_details = &self.text_layout_details(window, cx);
14479
14480        self.change_selections(Default::default(), window, cx, |s| {
14481            s.move_with(&mut |map, selection| {
14482                if !selection.is_empty() {
14483                    selection.goal = SelectionGoal::None;
14484                }
14485                let (cursor, goal) = movement::up_by_rows(
14486                    map,
14487                    selection.start,
14488                    action.lines,
14489                    selection.goal,
14490                    false,
14491                    text_layout_details,
14492                );
14493                selection.collapse_to(cursor, goal);
14494            });
14495        })
14496    }
14497
14498    pub fn move_down_by_lines(
14499        &mut self,
14500        action: &MoveDownByLines,
14501        window: &mut Window,
14502        cx: &mut Context<Self>,
14503    ) {
14504        if self.take_rename(true, window, cx).is_some() {
14505            return;
14506        }
14507
14508        if self.mode.is_single_line() {
14509            cx.propagate();
14510            return;
14511        }
14512
14513        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14514
14515        let text_layout_details = &self.text_layout_details(window, cx);
14516
14517        self.change_selections(Default::default(), window, cx, |s| {
14518            s.move_with(&mut |map, selection| {
14519                if !selection.is_empty() {
14520                    selection.goal = SelectionGoal::None;
14521                }
14522                let (cursor, goal) = movement::down_by_rows(
14523                    map,
14524                    selection.start,
14525                    action.lines,
14526                    selection.goal,
14527                    false,
14528                    text_layout_details,
14529                );
14530                selection.collapse_to(cursor, goal);
14531            });
14532        })
14533    }
14534
14535    pub fn select_down_by_lines(
14536        &mut self,
14537        action: &SelectDownByLines,
14538        window: &mut Window,
14539        cx: &mut Context<Self>,
14540    ) {
14541        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14542        let text_layout_details = &self.text_layout_details(window, cx);
14543        self.change_selections(Default::default(), window, cx, |s| {
14544            s.move_heads_with(&mut |map, head, goal| {
14545                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14546            })
14547        })
14548    }
14549
14550    pub fn select_up_by_lines(
14551        &mut self,
14552        action: &SelectUpByLines,
14553        window: &mut Window,
14554        cx: &mut Context<Self>,
14555    ) {
14556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14557        let text_layout_details = &self.text_layout_details(window, cx);
14558        self.change_selections(Default::default(), window, cx, |s| {
14559            s.move_heads_with(&mut |map, head, goal| {
14560                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14561            })
14562        })
14563    }
14564
14565    pub fn select_page_up(
14566        &mut self,
14567        _: &SelectPageUp,
14568        window: &mut Window,
14569        cx: &mut Context<Self>,
14570    ) {
14571        let Some(row_count) = self.visible_row_count() else {
14572            return;
14573        };
14574
14575        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14576
14577        let text_layout_details = &self.text_layout_details(window, cx);
14578
14579        self.change_selections(Default::default(), window, cx, |s| {
14580            s.move_heads_with(&mut |map, head, goal| {
14581                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14582            })
14583        })
14584    }
14585
14586    pub fn move_page_up(
14587        &mut self,
14588        action: &MovePageUp,
14589        window: &mut Window,
14590        cx: &mut Context<Self>,
14591    ) {
14592        if self.take_rename(true, window, cx).is_some() {
14593            return;
14594        }
14595
14596        if self
14597            .context_menu
14598            .borrow_mut()
14599            .as_mut()
14600            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14601            .unwrap_or(false)
14602        {
14603            return;
14604        }
14605
14606        if matches!(self.mode, EditorMode::SingleLine) {
14607            cx.propagate();
14608            return;
14609        }
14610
14611        let Some(row_count) = self.visible_row_count() else {
14612            return;
14613        };
14614
14615        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14616
14617        let effects = if action.center_cursor {
14618            SelectionEffects::scroll(Autoscroll::center())
14619        } else {
14620            SelectionEffects::default()
14621        };
14622
14623        let text_layout_details = &self.text_layout_details(window, cx);
14624
14625        self.change_selections(effects, window, cx, |s| {
14626            s.move_with(&mut |map, selection| {
14627                if !selection.is_empty() {
14628                    selection.goal = SelectionGoal::None;
14629                }
14630                let (cursor, goal) = movement::up_by_rows(
14631                    map,
14632                    selection.end,
14633                    row_count,
14634                    selection.goal,
14635                    false,
14636                    text_layout_details,
14637                );
14638                selection.collapse_to(cursor, goal);
14639            });
14640        });
14641    }
14642
14643    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14645        let text_layout_details = &self.text_layout_details(window, cx);
14646        self.change_selections(Default::default(), window, cx, |s| {
14647            s.move_heads_with(&mut |map, head, goal| {
14648                movement::up(map, head, goal, false, text_layout_details)
14649            })
14650        })
14651    }
14652
14653    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14654        self.take_rename(true, window, cx);
14655
14656        if self.mode.is_single_line() {
14657            cx.propagate();
14658            return;
14659        }
14660
14661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14662
14663        let text_layout_details = &self.text_layout_details(window, cx);
14664        let selection_count = self.selections.count();
14665        let first_selection = self.selections.first_anchor();
14666
14667        self.change_selections(Default::default(), window, cx, |s| {
14668            s.move_with(&mut |map, selection| {
14669                if !selection.is_empty() {
14670                    selection.goal = SelectionGoal::None;
14671                }
14672                let (cursor, goal) = movement::down(
14673                    map,
14674                    selection.end,
14675                    selection.goal,
14676                    false,
14677                    text_layout_details,
14678                );
14679                selection.collapse_to(cursor, goal);
14680            });
14681        });
14682
14683        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14684        {
14685            cx.propagate();
14686        }
14687    }
14688
14689    pub fn select_page_down(
14690        &mut self,
14691        _: &SelectPageDown,
14692        window: &mut Window,
14693        cx: &mut Context<Self>,
14694    ) {
14695        let Some(row_count) = self.visible_row_count() else {
14696            return;
14697        };
14698
14699        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14700
14701        let text_layout_details = &self.text_layout_details(window, cx);
14702
14703        self.change_selections(Default::default(), window, cx, |s| {
14704            s.move_heads_with(&mut |map, head, goal| {
14705                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14706            })
14707        })
14708    }
14709
14710    pub fn move_page_down(
14711        &mut self,
14712        action: &MovePageDown,
14713        window: &mut Window,
14714        cx: &mut Context<Self>,
14715    ) {
14716        if self.take_rename(true, window, cx).is_some() {
14717            return;
14718        }
14719
14720        if self
14721            .context_menu
14722            .borrow_mut()
14723            .as_mut()
14724            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14725            .unwrap_or(false)
14726        {
14727            return;
14728        }
14729
14730        if matches!(self.mode, EditorMode::SingleLine) {
14731            cx.propagate();
14732            return;
14733        }
14734
14735        let Some(row_count) = self.visible_row_count() else {
14736            return;
14737        };
14738
14739        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14740
14741        let effects = if action.center_cursor {
14742            SelectionEffects::scroll(Autoscroll::center())
14743        } else {
14744            SelectionEffects::default()
14745        };
14746
14747        let text_layout_details = &self.text_layout_details(window, cx);
14748        self.change_selections(effects, window, cx, |s| {
14749            s.move_with(&mut |map, selection| {
14750                if !selection.is_empty() {
14751                    selection.goal = SelectionGoal::None;
14752                }
14753                let (cursor, goal) = movement::down_by_rows(
14754                    map,
14755                    selection.end,
14756                    row_count,
14757                    selection.goal,
14758                    false,
14759                    text_layout_details,
14760                );
14761                selection.collapse_to(cursor, goal);
14762            });
14763        });
14764    }
14765
14766    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14768        let text_layout_details = &self.text_layout_details(window, cx);
14769        self.change_selections(Default::default(), window, cx, |s| {
14770            s.move_heads_with(&mut |map, head, goal| {
14771                movement::down(map, head, goal, false, text_layout_details)
14772            })
14773        });
14774    }
14775
14776    pub fn context_menu_first(
14777        &mut self,
14778        _: &ContextMenuFirst,
14779        window: &mut Window,
14780        cx: &mut Context<Self>,
14781    ) {
14782        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14783            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14784        }
14785    }
14786
14787    pub fn context_menu_prev(
14788        &mut self,
14789        _: &ContextMenuPrevious,
14790        window: &mut Window,
14791        cx: &mut Context<Self>,
14792    ) {
14793        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14794            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14795        }
14796    }
14797
14798    pub fn context_menu_next(
14799        &mut self,
14800        _: &ContextMenuNext,
14801        window: &mut Window,
14802        cx: &mut Context<Self>,
14803    ) {
14804        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14805            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14806        }
14807    }
14808
14809    pub fn context_menu_last(
14810        &mut self,
14811        _: &ContextMenuLast,
14812        window: &mut Window,
14813        cx: &mut Context<Self>,
14814    ) {
14815        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14816            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14817        }
14818    }
14819
14820    pub fn signature_help_prev(
14821        &mut self,
14822        _: &SignatureHelpPrevious,
14823        _: &mut Window,
14824        cx: &mut Context<Self>,
14825    ) {
14826        if let Some(popover) = self.signature_help_state.popover_mut() {
14827            if popover.current_signature == 0 {
14828                popover.current_signature = popover.signatures.len() - 1;
14829            } else {
14830                popover.current_signature -= 1;
14831            }
14832            cx.notify();
14833        }
14834    }
14835
14836    pub fn signature_help_next(
14837        &mut self,
14838        _: &SignatureHelpNext,
14839        _: &mut Window,
14840        cx: &mut Context<Self>,
14841    ) {
14842        if let Some(popover) = self.signature_help_state.popover_mut() {
14843            if popover.current_signature + 1 == popover.signatures.len() {
14844                popover.current_signature = 0;
14845            } else {
14846                popover.current_signature += 1;
14847            }
14848            cx.notify();
14849        }
14850    }
14851
14852    pub fn move_to_previous_word_start(
14853        &mut self,
14854        _: &MoveToPreviousWordStart,
14855        window: &mut Window,
14856        cx: &mut Context<Self>,
14857    ) {
14858        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14859        self.change_selections(Default::default(), window, cx, |s| {
14860            s.move_cursors_with(&mut |map, head, _| {
14861                (
14862                    movement::previous_word_start(map, head),
14863                    SelectionGoal::None,
14864                )
14865            });
14866        })
14867    }
14868
14869    pub fn move_to_previous_subword_start(
14870        &mut self,
14871        _: &MoveToPreviousSubwordStart,
14872        window: &mut Window,
14873        cx: &mut Context<Self>,
14874    ) {
14875        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14876        self.change_selections(Default::default(), window, cx, |s| {
14877            s.move_cursors_with(&mut |map, head, _| {
14878                (
14879                    movement::previous_subword_start(map, head),
14880                    SelectionGoal::None,
14881                )
14882            });
14883        })
14884    }
14885
14886    pub fn select_to_previous_word_start(
14887        &mut self,
14888        _: &SelectToPreviousWordStart,
14889        window: &mut Window,
14890        cx: &mut Context<Self>,
14891    ) {
14892        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14893        self.change_selections(Default::default(), window, cx, |s| {
14894            s.move_heads_with(&mut |map, head, _| {
14895                (
14896                    movement::previous_word_start(map, head),
14897                    SelectionGoal::None,
14898                )
14899            });
14900        })
14901    }
14902
14903    pub fn select_to_previous_subword_start(
14904        &mut self,
14905        _: &SelectToPreviousSubwordStart,
14906        window: &mut Window,
14907        cx: &mut Context<Self>,
14908    ) {
14909        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14910        self.change_selections(Default::default(), window, cx, |s| {
14911            s.move_heads_with(&mut |map, head, _| {
14912                (
14913                    movement::previous_subword_start(map, head),
14914                    SelectionGoal::None,
14915                )
14916            });
14917        })
14918    }
14919
14920    pub fn delete_to_previous_word_start(
14921        &mut self,
14922        action: &DeleteToPreviousWordStart,
14923        window: &mut Window,
14924        cx: &mut Context<Self>,
14925    ) {
14926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14927        self.transact(window, cx, |this, window, cx| {
14928            this.select_autoclose_pair(window, cx);
14929            this.change_selections(Default::default(), window, cx, |s| {
14930                s.move_with(&mut |map, selection| {
14931                    if selection.is_empty() {
14932                        let mut cursor = if action.ignore_newlines {
14933                            movement::previous_word_start(map, selection.head())
14934                        } else {
14935                            movement::previous_word_start_or_newline(map, selection.head())
14936                        };
14937                        cursor = movement::adjust_greedy_deletion(
14938                            map,
14939                            selection.head(),
14940                            cursor,
14941                            action.ignore_brackets,
14942                        );
14943                        selection.set_head(cursor, SelectionGoal::None);
14944                    }
14945                });
14946            });
14947            this.insert("", window, cx);
14948        });
14949    }
14950
14951    pub fn delete_to_previous_subword_start(
14952        &mut self,
14953        action: &DeleteToPreviousSubwordStart,
14954        window: &mut Window,
14955        cx: &mut Context<Self>,
14956    ) {
14957        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14958        self.transact(window, cx, |this, window, cx| {
14959            this.select_autoclose_pair(window, cx);
14960            this.change_selections(Default::default(), window, cx, |s| {
14961                s.move_with(&mut |map, selection| {
14962                    if selection.is_empty() {
14963                        let mut cursor = if action.ignore_newlines {
14964                            movement::previous_subword_start(map, selection.head())
14965                        } else {
14966                            movement::previous_subword_start_or_newline(map, selection.head())
14967                        };
14968                        cursor = movement::adjust_greedy_deletion(
14969                            map,
14970                            selection.head(),
14971                            cursor,
14972                            action.ignore_brackets,
14973                        );
14974                        selection.set_head(cursor, SelectionGoal::None);
14975                    }
14976                });
14977            });
14978            this.insert("", window, cx);
14979        });
14980    }
14981
14982    pub fn move_to_next_word_end(
14983        &mut self,
14984        _: &MoveToNextWordEnd,
14985        window: &mut Window,
14986        cx: &mut Context<Self>,
14987    ) {
14988        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14989        self.change_selections(Default::default(), window, cx, |s| {
14990            s.move_cursors_with(&mut |map, head, _| {
14991                (movement::next_word_end(map, head), SelectionGoal::None)
14992            });
14993        })
14994    }
14995
14996    pub fn move_to_next_subword_end(
14997        &mut self,
14998        _: &MoveToNextSubwordEnd,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15003        self.change_selections(Default::default(), window, cx, |s| {
15004            s.move_cursors_with(&mut |map, head, _| {
15005                (movement::next_subword_end(map, head), SelectionGoal::None)
15006            });
15007        })
15008    }
15009
15010    pub fn select_to_next_word_end(
15011        &mut self,
15012        _: &SelectToNextWordEnd,
15013        window: &mut Window,
15014        cx: &mut Context<Self>,
15015    ) {
15016        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15017        self.change_selections(Default::default(), window, cx, |s| {
15018            s.move_heads_with(&mut |map, head, _| {
15019                (movement::next_word_end(map, head), SelectionGoal::None)
15020            });
15021        })
15022    }
15023
15024    pub fn select_to_next_subword_end(
15025        &mut self,
15026        _: &SelectToNextSubwordEnd,
15027        window: &mut Window,
15028        cx: &mut Context<Self>,
15029    ) {
15030        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15031        self.change_selections(Default::default(), window, cx, |s| {
15032            s.move_heads_with(&mut |map, head, _| {
15033                (movement::next_subword_end(map, head), SelectionGoal::None)
15034            });
15035        })
15036    }
15037
15038    pub fn delete_to_next_word_end(
15039        &mut self,
15040        action: &DeleteToNextWordEnd,
15041        window: &mut Window,
15042        cx: &mut Context<Self>,
15043    ) {
15044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15045        self.transact(window, cx, |this, window, cx| {
15046            this.change_selections(Default::default(), window, cx, |s| {
15047                s.move_with(&mut |map, selection| {
15048                    if selection.is_empty() {
15049                        let mut cursor = if action.ignore_newlines {
15050                            movement::next_word_end(map, selection.head())
15051                        } else {
15052                            movement::next_word_end_or_newline(map, selection.head())
15053                        };
15054                        cursor = movement::adjust_greedy_deletion(
15055                            map,
15056                            selection.head(),
15057                            cursor,
15058                            action.ignore_brackets,
15059                        );
15060                        selection.set_head(cursor, SelectionGoal::None);
15061                    }
15062                });
15063            });
15064            this.insert("", window, cx);
15065        });
15066    }
15067
15068    pub fn delete_to_next_subword_end(
15069        &mut self,
15070        action: &DeleteToNextSubwordEnd,
15071        window: &mut Window,
15072        cx: &mut Context<Self>,
15073    ) {
15074        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15075        self.transact(window, cx, |this, window, cx| {
15076            this.change_selections(Default::default(), window, cx, |s| {
15077                s.move_with(&mut |map, selection| {
15078                    if selection.is_empty() {
15079                        let mut cursor = if action.ignore_newlines {
15080                            movement::next_subword_end(map, selection.head())
15081                        } else {
15082                            movement::next_subword_end_or_newline(map, selection.head())
15083                        };
15084                        cursor = movement::adjust_greedy_deletion(
15085                            map,
15086                            selection.head(),
15087                            cursor,
15088                            action.ignore_brackets,
15089                        );
15090                        selection.set_head(cursor, SelectionGoal::None);
15091                    }
15092                });
15093            });
15094            this.insert("", window, cx);
15095        });
15096    }
15097
15098    pub fn move_to_beginning_of_line(
15099        &mut self,
15100        action: &MoveToBeginningOfLine,
15101        window: &mut Window,
15102        cx: &mut Context<Self>,
15103    ) {
15104        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15105        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15106        self.change_selections(Default::default(), window, cx, |s| {
15107            s.move_cursors_with(&mut |map, head, _| {
15108                (
15109                    movement::indented_line_beginning(
15110                        map,
15111                        head,
15112                        action.stop_at_soft_wraps,
15113                        stop_at_indent,
15114                    ),
15115                    SelectionGoal::None,
15116                )
15117            });
15118        })
15119    }
15120
15121    pub fn select_to_beginning_of_line(
15122        &mut self,
15123        action: &SelectToBeginningOfLine,
15124        window: &mut Window,
15125        cx: &mut Context<Self>,
15126    ) {
15127        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15128        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15129        self.change_selections(Default::default(), window, cx, |s| {
15130            s.move_heads_with(&mut |map, head, _| {
15131                (
15132                    movement::indented_line_beginning(
15133                        map,
15134                        head,
15135                        action.stop_at_soft_wraps,
15136                        stop_at_indent,
15137                    ),
15138                    SelectionGoal::None,
15139                )
15140            });
15141        });
15142    }
15143
15144    pub fn delete_to_beginning_of_line(
15145        &mut self,
15146        action: &DeleteToBeginningOfLine,
15147        window: &mut Window,
15148        cx: &mut Context<Self>,
15149    ) {
15150        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15151        self.transact(window, cx, |this, window, cx| {
15152            this.change_selections(Default::default(), window, cx, |s| {
15153                s.move_with(&mut |_, selection| {
15154                    selection.reversed = true;
15155                });
15156            });
15157
15158            this.select_to_beginning_of_line(
15159                &SelectToBeginningOfLine {
15160                    stop_at_soft_wraps: false,
15161                    stop_at_indent: action.stop_at_indent,
15162                },
15163                window,
15164                cx,
15165            );
15166            this.backspace(&Backspace, window, cx);
15167        });
15168    }
15169
15170    pub fn move_to_end_of_line(
15171        &mut self,
15172        action: &MoveToEndOfLine,
15173        window: &mut Window,
15174        cx: &mut Context<Self>,
15175    ) {
15176        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15177        self.change_selections(Default::default(), window, cx, |s| {
15178            s.move_cursors_with(&mut |map, head, _| {
15179                (
15180                    movement::line_end(map, head, action.stop_at_soft_wraps),
15181                    SelectionGoal::None,
15182                )
15183            });
15184        })
15185    }
15186
15187    pub fn select_to_end_of_line(
15188        &mut self,
15189        action: &SelectToEndOfLine,
15190        window: &mut Window,
15191        cx: &mut Context<Self>,
15192    ) {
15193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15194        self.change_selections(Default::default(), window, cx, |s| {
15195            s.move_heads_with(&mut |map, head, _| {
15196                (
15197                    movement::line_end(map, head, action.stop_at_soft_wraps),
15198                    SelectionGoal::None,
15199                )
15200            });
15201        })
15202    }
15203
15204    pub fn delete_to_end_of_line(
15205        &mut self,
15206        _: &DeleteToEndOfLine,
15207        window: &mut Window,
15208        cx: &mut Context<Self>,
15209    ) {
15210        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15211        self.transact(window, cx, |this, window, cx| {
15212            this.select_to_end_of_line(
15213                &SelectToEndOfLine {
15214                    stop_at_soft_wraps: false,
15215                },
15216                window,
15217                cx,
15218            );
15219            this.delete(&Delete, window, cx);
15220        });
15221    }
15222
15223    pub fn cut_to_end_of_line(
15224        &mut self,
15225        action: &CutToEndOfLine,
15226        window: &mut Window,
15227        cx: &mut Context<Self>,
15228    ) {
15229        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15230        self.transact(window, cx, |this, window, cx| {
15231            this.select_to_end_of_line(
15232                &SelectToEndOfLine {
15233                    stop_at_soft_wraps: false,
15234                },
15235                window,
15236                cx,
15237            );
15238            if !action.stop_at_newlines {
15239                this.change_selections(Default::default(), window, cx, |s| {
15240                    s.move_with(&mut |_, sel| {
15241                        if sel.is_empty() {
15242                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15243                        }
15244                    });
15245                });
15246            }
15247            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15248            let item = this.cut_common(false, window, cx);
15249            cx.write_to_clipboard(item);
15250        });
15251    }
15252
15253    pub fn move_to_start_of_paragraph(
15254        &mut self,
15255        _: &MoveToStartOfParagraph,
15256        window: &mut Window,
15257        cx: &mut Context<Self>,
15258    ) {
15259        if matches!(self.mode, EditorMode::SingleLine) {
15260            cx.propagate();
15261            return;
15262        }
15263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15264        self.change_selections(Default::default(), window, cx, |s| {
15265            s.move_with(&mut |map, selection| {
15266                selection.collapse_to(
15267                    movement::start_of_paragraph(map, selection.head(), 1),
15268                    SelectionGoal::None,
15269                )
15270            });
15271        })
15272    }
15273
15274    pub fn move_to_end_of_paragraph(
15275        &mut self,
15276        _: &MoveToEndOfParagraph,
15277        window: &mut Window,
15278        cx: &mut Context<Self>,
15279    ) {
15280        if matches!(self.mode, EditorMode::SingleLine) {
15281            cx.propagate();
15282            return;
15283        }
15284        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15285        self.change_selections(Default::default(), window, cx, |s| {
15286            s.move_with(&mut |map, selection| {
15287                selection.collapse_to(
15288                    movement::end_of_paragraph(map, selection.head(), 1),
15289                    SelectionGoal::None,
15290                )
15291            });
15292        })
15293    }
15294
15295    pub fn select_to_start_of_paragraph(
15296        &mut self,
15297        _: &SelectToStartOfParagraph,
15298        window: &mut Window,
15299        cx: &mut Context<Self>,
15300    ) {
15301        if matches!(self.mode, EditorMode::SingleLine) {
15302            cx.propagate();
15303            return;
15304        }
15305        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15306        self.change_selections(Default::default(), window, cx, |s| {
15307            s.move_heads_with(&mut |map, head, _| {
15308                (
15309                    movement::start_of_paragraph(map, head, 1),
15310                    SelectionGoal::None,
15311                )
15312            });
15313        })
15314    }
15315
15316    pub fn select_to_end_of_paragraph(
15317        &mut self,
15318        _: &SelectToEndOfParagraph,
15319        window: &mut Window,
15320        cx: &mut Context<Self>,
15321    ) {
15322        if matches!(self.mode, EditorMode::SingleLine) {
15323            cx.propagate();
15324            return;
15325        }
15326        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15327        self.change_selections(Default::default(), window, cx, |s| {
15328            s.move_heads_with(&mut |map, head, _| {
15329                (
15330                    movement::end_of_paragraph(map, head, 1),
15331                    SelectionGoal::None,
15332                )
15333            });
15334        })
15335    }
15336
15337    pub fn move_to_start_of_excerpt(
15338        &mut self,
15339        _: &MoveToStartOfExcerpt,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) {
15343        if matches!(self.mode, EditorMode::SingleLine) {
15344            cx.propagate();
15345            return;
15346        }
15347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15348        self.change_selections(Default::default(), window, cx, |s| {
15349            s.move_with(&mut |map, selection| {
15350                selection.collapse_to(
15351                    movement::start_of_excerpt(
15352                        map,
15353                        selection.head(),
15354                        workspace::searchable::Direction::Prev,
15355                    ),
15356                    SelectionGoal::None,
15357                )
15358            });
15359        })
15360    }
15361
15362    pub fn move_to_start_of_next_excerpt(
15363        &mut self,
15364        _: &MoveToStartOfNextExcerpt,
15365        window: &mut Window,
15366        cx: &mut Context<Self>,
15367    ) {
15368        if matches!(self.mode, EditorMode::SingleLine) {
15369            cx.propagate();
15370            return;
15371        }
15372
15373        self.change_selections(Default::default(), window, cx, |s| {
15374            s.move_with(&mut |map, selection| {
15375                selection.collapse_to(
15376                    movement::start_of_excerpt(
15377                        map,
15378                        selection.head(),
15379                        workspace::searchable::Direction::Next,
15380                    ),
15381                    SelectionGoal::None,
15382                )
15383            });
15384        })
15385    }
15386
15387    pub fn move_to_end_of_excerpt(
15388        &mut self,
15389        _: &MoveToEndOfExcerpt,
15390        window: &mut Window,
15391        cx: &mut Context<Self>,
15392    ) {
15393        if matches!(self.mode, EditorMode::SingleLine) {
15394            cx.propagate();
15395            return;
15396        }
15397        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15398        self.change_selections(Default::default(), window, cx, |s| {
15399            s.move_with(&mut |map, selection| {
15400                selection.collapse_to(
15401                    movement::end_of_excerpt(
15402                        map,
15403                        selection.head(),
15404                        workspace::searchable::Direction::Next,
15405                    ),
15406                    SelectionGoal::None,
15407                )
15408            });
15409        })
15410    }
15411
15412    pub fn move_to_end_of_previous_excerpt(
15413        &mut self,
15414        _: &MoveToEndOfPreviousExcerpt,
15415        window: &mut Window,
15416        cx: &mut Context<Self>,
15417    ) {
15418        if matches!(self.mode, EditorMode::SingleLine) {
15419            cx.propagate();
15420            return;
15421        }
15422        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15423        self.change_selections(Default::default(), window, cx, |s| {
15424            s.move_with(&mut |map, selection| {
15425                selection.collapse_to(
15426                    movement::end_of_excerpt(
15427                        map,
15428                        selection.head(),
15429                        workspace::searchable::Direction::Prev,
15430                    ),
15431                    SelectionGoal::None,
15432                )
15433            });
15434        })
15435    }
15436
15437    pub fn select_to_start_of_excerpt(
15438        &mut self,
15439        _: &SelectToStartOfExcerpt,
15440        window: &mut Window,
15441        cx: &mut Context<Self>,
15442    ) {
15443        if matches!(self.mode, EditorMode::SingleLine) {
15444            cx.propagate();
15445            return;
15446        }
15447        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15448        self.change_selections(Default::default(), window, cx, |s| {
15449            s.move_heads_with(&mut |map, head, _| {
15450                (
15451                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15452                    SelectionGoal::None,
15453                )
15454            });
15455        })
15456    }
15457
15458    pub fn select_to_start_of_next_excerpt(
15459        &mut self,
15460        _: &SelectToStartOfNextExcerpt,
15461        window: &mut Window,
15462        cx: &mut Context<Self>,
15463    ) {
15464        if matches!(self.mode, EditorMode::SingleLine) {
15465            cx.propagate();
15466            return;
15467        }
15468        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15469        self.change_selections(Default::default(), window, cx, |s| {
15470            s.move_heads_with(&mut |map, head, _| {
15471                (
15472                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15473                    SelectionGoal::None,
15474                )
15475            });
15476        })
15477    }
15478
15479    pub fn select_to_end_of_excerpt(
15480        &mut self,
15481        _: &SelectToEndOfExcerpt,
15482        window: &mut Window,
15483        cx: &mut Context<Self>,
15484    ) {
15485        if matches!(self.mode, EditorMode::SingleLine) {
15486            cx.propagate();
15487            return;
15488        }
15489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15490        self.change_selections(Default::default(), window, cx, |s| {
15491            s.move_heads_with(&mut |map, head, _| {
15492                (
15493                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15494                    SelectionGoal::None,
15495                )
15496            });
15497        })
15498    }
15499
15500    pub fn select_to_end_of_previous_excerpt(
15501        &mut self,
15502        _: &SelectToEndOfPreviousExcerpt,
15503        window: &mut Window,
15504        cx: &mut Context<Self>,
15505    ) {
15506        if matches!(self.mode, EditorMode::SingleLine) {
15507            cx.propagate();
15508            return;
15509        }
15510        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15511        self.change_selections(Default::default(), window, cx, |s| {
15512            s.move_heads_with(&mut |map, head, _| {
15513                (
15514                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15515                    SelectionGoal::None,
15516                )
15517            });
15518        })
15519    }
15520
15521    pub fn move_to_beginning(
15522        &mut self,
15523        _: &MoveToBeginning,
15524        window: &mut Window,
15525        cx: &mut Context<Self>,
15526    ) {
15527        if matches!(self.mode, EditorMode::SingleLine) {
15528            cx.propagate();
15529            return;
15530        }
15531        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15532        self.change_selections(Default::default(), window, cx, |s| {
15533            s.select_ranges(vec![Anchor::Min..Anchor::Min]);
15534        });
15535    }
15536
15537    pub fn select_to_beginning(
15538        &mut self,
15539        _: &SelectToBeginning,
15540        window: &mut Window,
15541        cx: &mut Context<Self>,
15542    ) {
15543        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15544        selection.set_head(Point::zero(), SelectionGoal::None);
15545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15546        self.change_selections(Default::default(), window, cx, |s| {
15547            s.select(vec![selection]);
15548        });
15549    }
15550
15551    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15552        if matches!(self.mode, EditorMode::SingleLine) {
15553            cx.propagate();
15554            return;
15555        }
15556        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15557        let cursor = self.buffer.read(cx).read(cx).len();
15558        self.change_selections(Default::default(), window, cx, |s| {
15559            s.select_ranges(vec![cursor..cursor])
15560        });
15561    }
15562
15563    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15564        self.nav_history = nav_history;
15565    }
15566
15567    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15568        self.nav_history.as_ref()
15569    }
15570
15571    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15572        self.push_to_nav_history(
15573            self.selections.newest_anchor().head(),
15574            None,
15575            false,
15576            true,
15577            cx,
15578        );
15579    }
15580
15581    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15582        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15583        let buffer = self.buffer.read(cx).read(cx);
15584        let cursor_position = cursor_anchor.to_point(&buffer);
15585        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15586        let scroll_top_row = scroll_anchor.top_row(&buffer);
15587        drop(buffer);
15588
15589        NavigationData {
15590            cursor_anchor,
15591            cursor_position,
15592            scroll_anchor,
15593            scroll_top_row,
15594        }
15595    }
15596
15597    fn navigation_entry(
15598        &self,
15599        cursor_anchor: Anchor,
15600        cx: &mut Context<Self>,
15601    ) -> Option<NavigationEntry> {
15602        let Some(history) = self.nav_history.clone() else {
15603            return None;
15604        };
15605        let data = self.navigation_data(cursor_anchor, cx);
15606        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15607    }
15608
15609    fn push_to_nav_history(
15610        &mut self,
15611        cursor_anchor: Anchor,
15612        new_position: Option<Point>,
15613        is_deactivate: bool,
15614        always: bool,
15615        cx: &mut Context<Self>,
15616    ) {
15617        let data = self.navigation_data(cursor_anchor, cx);
15618        if let Some(nav_history) = self.nav_history.as_mut() {
15619            if let Some(new_position) = new_position {
15620                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15621                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15622                    return;
15623                }
15624            }
15625
15626            let cursor_row = data.cursor_position.row;
15627            nav_history.push(Some(data), Some(cursor_row), cx);
15628            cx.emit(EditorEvent::PushedToNavHistory {
15629                anchor: cursor_anchor,
15630                is_deactivate,
15631            })
15632        }
15633    }
15634
15635    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15636        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15637        let buffer = self.buffer.read(cx).snapshot(cx);
15638        let mut selection = self
15639            .selections
15640            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15641        selection.set_head(buffer.len(), SelectionGoal::None);
15642        self.change_selections(Default::default(), window, cx, |s| {
15643            s.select(vec![selection]);
15644        });
15645    }
15646
15647    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15648        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15649        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15650            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
15651        });
15652    }
15653
15654    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15655        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15656        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15657        let mut selections = self.selections.all::<Point>(&display_map);
15658        let max_point = display_map.buffer_snapshot().max_point();
15659        for selection in &mut selections {
15660            let rows = selection.spanned_rows(true, &display_map);
15661            selection.start = Point::new(rows.start.0, 0);
15662            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15663            selection.reversed = false;
15664        }
15665        self.change_selections(Default::default(), window, cx, |s| {
15666            s.select(selections);
15667        });
15668    }
15669
15670    pub fn split_selection_into_lines(
15671        &mut self,
15672        action: &SplitSelectionIntoLines,
15673        window: &mut Window,
15674        cx: &mut Context<Self>,
15675    ) {
15676        let selections = self
15677            .selections
15678            .all::<Point>(&self.display_snapshot(cx))
15679            .into_iter()
15680            .map(|selection| selection.start..selection.end)
15681            .collect::<Vec<_>>();
15682        self.unfold_ranges(&selections, true, false, cx);
15683
15684        let mut new_selection_ranges = Vec::new();
15685        {
15686            let buffer = self.buffer.read(cx).read(cx);
15687            for selection in selections {
15688                for row in selection.start.row..selection.end.row {
15689                    let line_start = Point::new(row, 0);
15690                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15691
15692                    if action.keep_selections {
15693                        // Keep the selection range for each line
15694                        let selection_start = if row == selection.start.row {
15695                            selection.start
15696                        } else {
15697                            line_start
15698                        };
15699                        new_selection_ranges.push(selection_start..line_end);
15700                    } else {
15701                        // Collapse to cursor at end of line
15702                        new_selection_ranges.push(line_end..line_end);
15703                    }
15704                }
15705
15706                let is_multiline_selection = selection.start.row != selection.end.row;
15707                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15708                // so this action feels more ergonomic when paired with other selection operations
15709                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15710                if !should_skip_last {
15711                    if action.keep_selections {
15712                        if is_multiline_selection {
15713                            let line_start = Point::new(selection.end.row, 0);
15714                            new_selection_ranges.push(line_start..selection.end);
15715                        } else {
15716                            new_selection_ranges.push(selection.start..selection.end);
15717                        }
15718                    } else {
15719                        new_selection_ranges.push(selection.end..selection.end);
15720                    }
15721                }
15722            }
15723        }
15724        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15725            s.select_ranges(new_selection_ranges);
15726        });
15727    }
15728
15729    pub fn add_selection_above(
15730        &mut self,
15731        action: &AddSelectionAbove,
15732        window: &mut Window,
15733        cx: &mut Context<Self>,
15734    ) {
15735        self.add_selection(true, action.skip_soft_wrap, window, cx);
15736    }
15737
15738    pub fn add_selection_below(
15739        &mut self,
15740        action: &AddSelectionBelow,
15741        window: &mut Window,
15742        cx: &mut Context<Self>,
15743    ) {
15744        self.add_selection(false, action.skip_soft_wrap, window, cx);
15745    }
15746
15747    fn add_selection(
15748        &mut self,
15749        above: bool,
15750        skip_soft_wrap: bool,
15751        window: &mut Window,
15752        cx: &mut Context<Self>,
15753    ) {
15754        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15755
15756        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15757        let all_selections = self.selections.all::<Point>(&display_map);
15758        let text_layout_details = self.text_layout_details(window, cx);
15759
15760        let (mut columnar_selections, new_selections_to_columnarize) = {
15761            if let Some(state) = self.add_selections_state.as_ref() {
15762                let columnar_selection_ids: HashSet<_> = state
15763                    .groups
15764                    .iter()
15765                    .flat_map(|group| group.stack.iter())
15766                    .copied()
15767                    .collect();
15768
15769                all_selections
15770                    .into_iter()
15771                    .partition(|s| columnar_selection_ids.contains(&s.id))
15772            } else {
15773                (Vec::new(), all_selections)
15774            }
15775        };
15776
15777        let mut state = self
15778            .add_selections_state
15779            .take()
15780            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15781
15782        for selection in new_selections_to_columnarize {
15783            let range = selection.display_range(&display_map).sorted();
15784            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15785            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15786            let positions = start_x.min(end_x)..start_x.max(end_x);
15787            let mut stack = Vec::new();
15788            for row in range.start.row().0..=range.end.row().0 {
15789                if let Some(selection) = self.selections.build_columnar_selection(
15790                    &display_map,
15791                    DisplayRow(row),
15792                    &positions,
15793                    selection.reversed,
15794                    &text_layout_details,
15795                ) {
15796                    stack.push(selection.id);
15797                    columnar_selections.push(selection);
15798                }
15799            }
15800            if !stack.is_empty() {
15801                if above {
15802                    stack.reverse();
15803                }
15804                state.groups.push(AddSelectionsGroup { above, stack });
15805            }
15806        }
15807
15808        let mut final_selections = Vec::new();
15809        let end_row = if above {
15810            DisplayRow(0)
15811        } else {
15812            display_map.max_point().row()
15813        };
15814
15815        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15816        // positions to place new selections, so we need to keep track of the
15817        // column range of the oldest selection in each group, because
15818        // intermediate selections may have been clamped to shorter lines.
15819        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15820            let mut map = HashMap::default();
15821            for group in state.groups.iter() {
15822                if let Some(oldest_id) = group.stack.first() {
15823                    if let Some(oldest_selection) =
15824                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15825                    {
15826                        let snapshot = display_map.buffer_snapshot();
15827                        let start_col =
15828                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15829                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15830                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15831                        for id in &group.stack {
15832                            map.insert(*id, goal_columns.clone());
15833                        }
15834                    }
15835                }
15836            }
15837            map
15838        } else {
15839            HashMap::default()
15840        };
15841
15842        let mut last_added_item_per_group = HashMap::default();
15843        for group in state.groups.iter_mut() {
15844            if let Some(last_id) = group.stack.last() {
15845                last_added_item_per_group.insert(*last_id, group);
15846            }
15847        }
15848
15849        for selection in columnar_selections {
15850            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15851                if above == group.above {
15852                    let range = selection.display_range(&display_map).sorted();
15853                    debug_assert_eq!(range.start.row(), range.end.row());
15854                    let row = range.start.row();
15855                    let positions =
15856                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15857                            Pixels::from(start)..Pixels::from(end)
15858                        } else {
15859                            let start_x =
15860                                display_map.x_for_display_point(range.start, &text_layout_details);
15861                            let end_x =
15862                                display_map.x_for_display_point(range.end, &text_layout_details);
15863                            start_x.min(end_x)..start_x.max(end_x)
15864                        };
15865
15866                    let maybe_new_selection = if skip_soft_wrap {
15867                        let goal_columns = goal_columns_by_selection_id
15868                            .remove(&selection.id)
15869                            .unwrap_or_else(|| {
15870                                let snapshot = display_map.buffer_snapshot();
15871                                let start_col =
15872                                    snapshot.point_to_point_utf16(selection.start).column;
15873                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15874                                start_col.min(end_col)..start_col.max(end_col)
15875                            });
15876                        self.selections.find_next_columnar_selection_by_buffer_row(
15877                            &display_map,
15878                            row,
15879                            end_row,
15880                            above,
15881                            &goal_columns,
15882                            selection.reversed,
15883                            &text_layout_details,
15884                        )
15885                    } else {
15886                        self.selections.find_next_columnar_selection_by_display_row(
15887                            &display_map,
15888                            row,
15889                            end_row,
15890                            above,
15891                            &positions,
15892                            selection.reversed,
15893                            &text_layout_details,
15894                        )
15895                    };
15896
15897                    if let Some(new_selection) = maybe_new_selection {
15898                        group.stack.push(new_selection.id);
15899                        if above {
15900                            final_selections.push(new_selection);
15901                            final_selections.push(selection);
15902                        } else {
15903                            final_selections.push(selection);
15904                            final_selections.push(new_selection);
15905                        }
15906                    } else {
15907                        final_selections.push(selection);
15908                    }
15909                } else {
15910                    group.stack.pop();
15911                }
15912            } else {
15913                final_selections.push(selection);
15914            }
15915        }
15916
15917        self.change_selections(Default::default(), window, cx, |s| {
15918            s.select(final_selections);
15919        });
15920
15921        let final_selection_ids: HashSet<_> = self
15922            .selections
15923            .all::<Point>(&display_map)
15924            .iter()
15925            .map(|s| s.id)
15926            .collect();
15927        state.groups.retain_mut(|group| {
15928            // selections might get merged above so we remove invalid items from stacks
15929            group.stack.retain(|id| final_selection_ids.contains(id));
15930
15931            // single selection in stack can be treated as initial state
15932            group.stack.len() > 1
15933        });
15934
15935        if !state.groups.is_empty() {
15936            self.add_selections_state = Some(state);
15937        }
15938    }
15939
15940    pub fn insert_snippet_at_selections(
15941        &mut self,
15942        action: &InsertSnippet,
15943        window: &mut Window,
15944        cx: &mut Context<Self>,
15945    ) {
15946        self.try_insert_snippet_at_selections(action, window, cx)
15947            .log_err();
15948    }
15949
15950    fn try_insert_snippet_at_selections(
15951        &mut self,
15952        action: &InsertSnippet,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) -> Result<()> {
15956        let insertion_ranges = self
15957            .selections
15958            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15959            .into_iter()
15960            .map(|selection| selection.range())
15961            .collect_vec();
15962
15963        let snippet = if let Some(snippet_body) = &action.snippet {
15964            if action.language.is_none() && action.name.is_none() {
15965                Snippet::parse(snippet_body)?
15966            } else {
15967                bail!("`snippet` is mutually exclusive with `language` and `name`")
15968            }
15969        } else if let Some(name) = &action.name {
15970            let project = self.project().context("no project")?;
15971            let snippet_store = project.read(cx).snippets().read(cx);
15972            let snippet = snippet_store
15973                .snippets_for(action.language.clone(), cx)
15974                .into_iter()
15975                .find(|snippet| snippet.name == *name)
15976                .context("snippet not found")?;
15977            Snippet::parse(&snippet.body)?
15978        } else {
15979            // todo(andrew): open modal to select snippet
15980            bail!("`name` or `snippet` is required")
15981        };
15982
15983        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15984    }
15985
15986    fn select_match_ranges(
15987        &mut self,
15988        range: Range<MultiBufferOffset>,
15989        reversed: bool,
15990        replace_newest: bool,
15991        auto_scroll: Option<Autoscroll>,
15992        window: &mut Window,
15993        cx: &mut Context<Editor>,
15994    ) {
15995        self.unfold_ranges(
15996            std::slice::from_ref(&range),
15997            false,
15998            auto_scroll.is_some(),
15999            cx,
16000        );
16001        let effects = if let Some(scroll) = auto_scroll {
16002            SelectionEffects::scroll(scroll)
16003        } else {
16004            SelectionEffects::no_scroll()
16005        };
16006        self.change_selections(effects, window, cx, |s| {
16007            if replace_newest {
16008                s.delete(s.newest_anchor().id);
16009            }
16010            if reversed {
16011                s.insert_range(range.end..range.start);
16012            } else {
16013                s.insert_range(range);
16014            }
16015        });
16016    }
16017
16018    pub fn select_next_match_internal(
16019        &mut self,
16020        display_map: &DisplaySnapshot,
16021        replace_newest: bool,
16022        autoscroll: Option<Autoscroll>,
16023        window: &mut Window,
16024        cx: &mut Context<Self>,
16025    ) -> Result<()> {
16026        let buffer = display_map.buffer_snapshot();
16027        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16028        if let Some(mut select_next_state) = self.select_next_state.take() {
16029            let query = &select_next_state.query;
16030            if !select_next_state.done {
16031                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16032                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16033                let mut next_selected_range = None;
16034
16035                let bytes_after_last_selection =
16036                    buffer.bytes_in_range(last_selection.end..buffer.len());
16037                let bytes_before_first_selection =
16038                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
16039                let query_matches = query
16040                    .stream_find_iter(bytes_after_last_selection)
16041                    .map(|result| (last_selection.end, result))
16042                    .chain(
16043                        query
16044                            .stream_find_iter(bytes_before_first_selection)
16045                            .map(|result| (MultiBufferOffset(0), result)),
16046                    );
16047
16048                for (start_offset, query_match) in query_matches {
16049                    let query_match = query_match.unwrap(); // can only fail due to I/O
16050                    let offset_range =
16051                        start_offset + query_match.start()..start_offset + query_match.end();
16052
16053                    if !select_next_state.wordwise
16054                        || (!buffer.is_inside_word(offset_range.start, None)
16055                            && !buffer.is_inside_word(offset_range.end, None))
16056                    {
16057                        let idx = selections
16058                            .partition_point(|selection| selection.end <= offset_range.start);
16059                        let overlaps = selections
16060                            .get(idx)
16061                            .map_or(false, |selection| selection.start < offset_range.end);
16062
16063                        if !overlaps {
16064                            next_selected_range = Some(offset_range);
16065                            break;
16066                        }
16067                    }
16068                }
16069
16070                if let Some(next_selected_range) = next_selected_range {
16071                    self.select_match_ranges(
16072                        next_selected_range,
16073                        last_selection.reversed,
16074                        replace_newest,
16075                        autoscroll,
16076                        window,
16077                        cx,
16078                    );
16079                } else {
16080                    select_next_state.done = true;
16081                }
16082            }
16083
16084            self.select_next_state = Some(select_next_state);
16085        } else {
16086            let mut only_carets = true;
16087            let mut same_text_selected = true;
16088            let mut selected_text = None;
16089
16090            let mut selections_iter = selections.iter().peekable();
16091            while let Some(selection) = selections_iter.next() {
16092                if selection.start != selection.end {
16093                    only_carets = false;
16094                }
16095
16096                if same_text_selected {
16097                    if selected_text.is_none() {
16098                        selected_text =
16099                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16100                    }
16101
16102                    if let Some(next_selection) = selections_iter.peek() {
16103                        if next_selection.len() == selection.len() {
16104                            let next_selected_text = buffer
16105                                .text_for_range(next_selection.range())
16106                                .collect::<String>();
16107                            if Some(next_selected_text) != selected_text {
16108                                same_text_selected = false;
16109                                selected_text = None;
16110                            }
16111                        } else {
16112                            same_text_selected = false;
16113                            selected_text = None;
16114                        }
16115                    }
16116                }
16117            }
16118
16119            if only_carets {
16120                for selection in &mut selections {
16121                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16122                    selection.start = word_range.start;
16123                    selection.end = word_range.end;
16124                    selection.goal = SelectionGoal::None;
16125                    selection.reversed = false;
16126                    self.select_match_ranges(
16127                        selection.start..selection.end,
16128                        selection.reversed,
16129                        replace_newest,
16130                        autoscroll,
16131                        window,
16132                        cx,
16133                    );
16134                }
16135
16136                if selections.len() == 1 {
16137                    let selection = selections
16138                        .last()
16139                        .expect("ensured that there's only one selection");
16140                    let query = buffer
16141                        .text_for_range(selection.start..selection.end)
16142                        .collect::<String>();
16143                    let is_empty = query.is_empty();
16144                    let select_state = SelectNextState {
16145                        query: self.build_query(&[query], cx)?,
16146                        wordwise: true,
16147                        done: is_empty,
16148                    };
16149                    self.select_next_state = Some(select_state);
16150                } else {
16151                    self.select_next_state = None;
16152                }
16153            } else if let Some(selected_text) = selected_text {
16154                self.select_next_state = Some(SelectNextState {
16155                    query: self.build_query(&[selected_text], cx)?,
16156                    wordwise: false,
16157                    done: false,
16158                });
16159                self.select_next_match_internal(
16160                    display_map,
16161                    replace_newest,
16162                    autoscroll,
16163                    window,
16164                    cx,
16165                )?;
16166            }
16167        }
16168        Ok(())
16169    }
16170
16171    pub fn select_all_matches(
16172        &mut self,
16173        _action: &SelectAllMatches,
16174        window: &mut Window,
16175        cx: &mut Context<Self>,
16176    ) -> Result<()> {
16177        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16178
16179        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16180
16181        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16182        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16183        else {
16184            return Ok(());
16185        };
16186
16187        let mut new_selections = Vec::new();
16188        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
16189        let reversed = initial_selection.reversed;
16190        let buffer = display_map.buffer_snapshot();
16191        let query_matches = select_next_state
16192            .query
16193            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16194
16195        for query_match in query_matches.into_iter() {
16196            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16197            let offset_range = if reversed {
16198                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16199            } else {
16200                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16201            };
16202
16203            let is_partial_word_match = select_next_state.wordwise
16204                && (buffer.is_inside_word(offset_range.start, None)
16205                    || buffer.is_inside_word(offset_range.end, None));
16206
16207            let is_initial_selection = MultiBufferOffset(query_match.start())
16208                == initial_selection.start
16209                && MultiBufferOffset(query_match.end()) == initial_selection.end;
16210
16211            if !is_partial_word_match && !is_initial_selection {
16212                new_selections.push(offset_range);
16213            }
16214        }
16215
16216        // Ensure that the initial range is the last selection, as
16217        // `MutableSelectionsCollection::select_ranges` makes the last selection
16218        // the newest selection, which the editor then relies on as the primary
16219        // cursor for scroll targeting. Without this, the last match would then
16220        // be automatically focused when the user started editing the selected
16221        // matches.
16222        let initial_directed_range = if reversed {
16223            initial_selection.end..initial_selection.start
16224        } else {
16225            initial_selection.start..initial_selection.end
16226        };
16227        new_selections.push(initial_directed_range);
16228
16229        select_next_state.done = true;
16230        self.unfold_ranges(&new_selections, false, false, cx);
16231        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16232            selections.select_ranges(new_selections)
16233        });
16234
16235        Ok(())
16236    }
16237
16238    pub fn select_next(
16239        &mut self,
16240        action: &SelectNext,
16241        window: &mut Window,
16242        cx: &mut Context<Self>,
16243    ) -> Result<()> {
16244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16246        self.select_next_match_internal(
16247            &display_map,
16248            action.replace_newest,
16249            Some(Autoscroll::newest()),
16250            window,
16251            cx,
16252        )
16253    }
16254
16255    pub fn select_previous(
16256        &mut self,
16257        action: &SelectPrevious,
16258        window: &mut Window,
16259        cx: &mut Context<Self>,
16260    ) -> Result<()> {
16261        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16262        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16263        let buffer = display_map.buffer_snapshot();
16264        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16265        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16266            let query = &select_prev_state.query;
16267            if !select_prev_state.done {
16268                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16269                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16270                let mut next_selected_range = None;
16271                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16272                let bytes_before_last_selection =
16273                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16274                let bytes_after_first_selection =
16275                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16276                let query_matches = query
16277                    .stream_find_iter(bytes_before_last_selection)
16278                    .map(|result| (last_selection.start, result))
16279                    .chain(
16280                        query
16281                            .stream_find_iter(bytes_after_first_selection)
16282                            .map(|result| (buffer.len(), result)),
16283                    );
16284                for (end_offset, query_match) in query_matches {
16285                    let query_match = query_match.unwrap(); // can only fail due to I/O
16286                    let offset_range =
16287                        end_offset - query_match.end()..end_offset - query_match.start();
16288
16289                    if !select_prev_state.wordwise
16290                        || (!buffer.is_inside_word(offset_range.start, None)
16291                            && !buffer.is_inside_word(offset_range.end, None))
16292                    {
16293                        next_selected_range = Some(offset_range);
16294                        break;
16295                    }
16296                }
16297
16298                if let Some(next_selected_range) = next_selected_range {
16299                    self.select_match_ranges(
16300                        next_selected_range,
16301                        last_selection.reversed,
16302                        action.replace_newest,
16303                        Some(Autoscroll::newest()),
16304                        window,
16305                        cx,
16306                    );
16307                } else {
16308                    select_prev_state.done = true;
16309                }
16310            }
16311
16312            self.select_prev_state = Some(select_prev_state);
16313        } else {
16314            let mut only_carets = true;
16315            let mut same_text_selected = true;
16316            let mut selected_text = None;
16317
16318            let mut selections_iter = selections.iter().peekable();
16319            while let Some(selection) = selections_iter.next() {
16320                if selection.start != selection.end {
16321                    only_carets = false;
16322                }
16323
16324                if same_text_selected {
16325                    if selected_text.is_none() {
16326                        selected_text =
16327                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16328                    }
16329
16330                    if let Some(next_selection) = selections_iter.peek() {
16331                        if next_selection.len() == selection.len() {
16332                            let next_selected_text = buffer
16333                                .text_for_range(next_selection.range())
16334                                .collect::<String>();
16335                            if Some(next_selected_text) != selected_text {
16336                                same_text_selected = false;
16337                                selected_text = None;
16338                            }
16339                        } else {
16340                            same_text_selected = false;
16341                            selected_text = None;
16342                        }
16343                    }
16344                }
16345            }
16346
16347            if only_carets {
16348                for selection in &mut selections {
16349                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16350                    selection.start = word_range.start;
16351                    selection.end = word_range.end;
16352                    selection.goal = SelectionGoal::None;
16353                    selection.reversed = false;
16354                    self.select_match_ranges(
16355                        selection.start..selection.end,
16356                        selection.reversed,
16357                        action.replace_newest,
16358                        Some(Autoscroll::newest()),
16359                        window,
16360                        cx,
16361                    );
16362                }
16363                if selections.len() == 1 {
16364                    let selection = selections
16365                        .last()
16366                        .expect("ensured that there's only one selection");
16367                    let query = buffer
16368                        .text_for_range(selection.start..selection.end)
16369                        .collect::<String>();
16370                    let is_empty = query.is_empty();
16371                    let select_state = SelectNextState {
16372                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16373                        wordwise: true,
16374                        done: is_empty,
16375                    };
16376                    self.select_prev_state = Some(select_state);
16377                } else {
16378                    self.select_prev_state = None;
16379                }
16380            } else if let Some(selected_text) = selected_text {
16381                self.select_prev_state = Some(SelectNextState {
16382                    query: self
16383                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16384                    wordwise: false,
16385                    done: false,
16386                });
16387                self.select_previous(action, window, cx)?;
16388            }
16389        }
16390        Ok(())
16391    }
16392
16393    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16394    /// setting the case sensitivity based on the global
16395    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16396    /// editor's settings.
16397    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16398    where
16399        I: IntoIterator<Item = P>,
16400        P: AsRef<[u8]>,
16401    {
16402        let case_sensitive = self
16403            .select_next_is_case_sensitive
16404            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16405
16406        let mut builder = AhoCorasickBuilder::new();
16407        builder.ascii_case_insensitive(!case_sensitive);
16408        builder.build(patterns)
16409    }
16410
16411    pub fn find_next_match(
16412        &mut self,
16413        _: &FindNextMatch,
16414        window: &mut Window,
16415        cx: &mut Context<Self>,
16416    ) -> Result<()> {
16417        let selections = self.selections.disjoint_anchors_arc();
16418        match selections.first() {
16419            Some(first) if selections.len() >= 2 => {
16420                self.change_selections(Default::default(), window, cx, |s| {
16421                    s.select_ranges([first.range()]);
16422                });
16423            }
16424            _ => self.select_next(
16425                &SelectNext {
16426                    replace_newest: true,
16427                },
16428                window,
16429                cx,
16430            )?,
16431        }
16432        Ok(())
16433    }
16434
16435    pub fn find_previous_match(
16436        &mut self,
16437        _: &FindPreviousMatch,
16438        window: &mut Window,
16439        cx: &mut Context<Self>,
16440    ) -> Result<()> {
16441        let selections = self.selections.disjoint_anchors_arc();
16442        match selections.last() {
16443            Some(last) if selections.len() >= 2 => {
16444                self.change_selections(Default::default(), window, cx, |s| {
16445                    s.select_ranges([last.range()]);
16446                });
16447            }
16448            _ => self.select_previous(
16449                &SelectPrevious {
16450                    replace_newest: true,
16451                },
16452                window,
16453                cx,
16454            )?,
16455        }
16456        Ok(())
16457    }
16458
16459    pub fn toggle_comments(
16460        &mut self,
16461        action: &ToggleComments,
16462        window: &mut Window,
16463        cx: &mut Context<Self>,
16464    ) {
16465        if self.read_only(cx) {
16466            return;
16467        }
16468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16469        let text_layout_details = &self.text_layout_details(window, cx);
16470        self.transact(window, cx, |this, window, cx| {
16471            let mut selections = this
16472                .selections
16473                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16474            let mut edits = Vec::new();
16475            let mut selection_edit_ranges = Vec::new();
16476            let mut last_toggled_row = None;
16477            let snapshot = this.buffer.read(cx).read(cx);
16478            let empty_str: Arc<str> = Arc::default();
16479            let mut suffixes_inserted = Vec::new();
16480            let ignore_indent = action.ignore_indent;
16481
16482            fn comment_prefix_range(
16483                snapshot: &MultiBufferSnapshot,
16484                row: MultiBufferRow,
16485                comment_prefix: &str,
16486                comment_prefix_whitespace: &str,
16487                ignore_indent: bool,
16488            ) -> Range<Point> {
16489                let indent_size = if ignore_indent {
16490                    0
16491                } else {
16492                    snapshot.indent_size_for_line(row).len
16493                };
16494
16495                let start = Point::new(row.0, indent_size);
16496
16497                let mut line_bytes = snapshot
16498                    .bytes_in_range(start..snapshot.max_point())
16499                    .flatten()
16500                    .copied();
16501
16502                // If this line currently begins with the line comment prefix, then record
16503                // the range containing the prefix.
16504                if line_bytes
16505                    .by_ref()
16506                    .take(comment_prefix.len())
16507                    .eq(comment_prefix.bytes())
16508                {
16509                    // Include any whitespace that matches the comment prefix.
16510                    let matching_whitespace_len = line_bytes
16511                        .zip(comment_prefix_whitespace.bytes())
16512                        .take_while(|(a, b)| a == b)
16513                        .count() as u32;
16514                    let end = Point::new(
16515                        start.row,
16516                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16517                    );
16518                    start..end
16519                } else {
16520                    start..start
16521                }
16522            }
16523
16524            fn comment_suffix_range(
16525                snapshot: &MultiBufferSnapshot,
16526                row: MultiBufferRow,
16527                comment_suffix: &str,
16528                comment_suffix_has_leading_space: bool,
16529            ) -> Range<Point> {
16530                let end = Point::new(row.0, snapshot.line_len(row));
16531                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16532
16533                let mut line_end_bytes = snapshot
16534                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16535                    .flatten()
16536                    .copied();
16537
16538                let leading_space_len = if suffix_start_column > 0
16539                    && line_end_bytes.next() == Some(b' ')
16540                    && comment_suffix_has_leading_space
16541                {
16542                    1
16543                } else {
16544                    0
16545                };
16546
16547                // If this line currently begins with the line comment prefix, then record
16548                // the range containing the prefix.
16549                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16550                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16551                    start..end
16552                } else {
16553                    end..end
16554                }
16555            }
16556
16557            // TODO: Handle selections that cross excerpts
16558            for selection in &mut selections {
16559                let start_column = snapshot
16560                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16561                    .len;
16562                let language = if let Some(language) =
16563                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16564                {
16565                    language
16566                } else {
16567                    continue;
16568                };
16569
16570                selection_edit_ranges.clear();
16571
16572                // If multiple selections contain a given row, avoid processing that
16573                // row more than once.
16574                let mut start_row = MultiBufferRow(selection.start.row);
16575                if last_toggled_row == Some(start_row) {
16576                    start_row = start_row.next_row();
16577                }
16578                let end_row =
16579                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16580                        MultiBufferRow(selection.end.row - 1)
16581                    } else {
16582                        MultiBufferRow(selection.end.row)
16583                    };
16584                last_toggled_row = Some(end_row);
16585
16586                if start_row > end_row {
16587                    continue;
16588                }
16589
16590                // If the language has line comments, toggle those.
16591                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16592
16593                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16594                if ignore_indent {
16595                    full_comment_prefixes = full_comment_prefixes
16596                        .into_iter()
16597                        .map(|s| Arc::from(s.trim_end()))
16598                        .collect();
16599                }
16600
16601                if !full_comment_prefixes.is_empty() {
16602                    let first_prefix = full_comment_prefixes
16603                        .first()
16604                        .expect("prefixes is non-empty");
16605                    let prefix_trimmed_lengths = full_comment_prefixes
16606                        .iter()
16607                        .map(|p| p.trim_end_matches(' ').len())
16608                        .collect::<SmallVec<[usize; 4]>>();
16609
16610                    let mut all_selection_lines_are_comments = true;
16611
16612                    for row in start_row.0..=end_row.0 {
16613                        let row = MultiBufferRow(row);
16614                        if start_row < end_row && snapshot.is_line_blank(row) {
16615                            continue;
16616                        }
16617
16618                        let prefix_range = full_comment_prefixes
16619                            .iter()
16620                            .zip(prefix_trimmed_lengths.iter().copied())
16621                            .map(|(prefix, trimmed_prefix_len)| {
16622                                comment_prefix_range(
16623                                    snapshot.deref(),
16624                                    row,
16625                                    &prefix[..trimmed_prefix_len],
16626                                    &prefix[trimmed_prefix_len..],
16627                                    ignore_indent,
16628                                )
16629                            })
16630                            .max_by_key(|range| range.end.column - range.start.column)
16631                            .expect("prefixes is non-empty");
16632
16633                        if prefix_range.is_empty() {
16634                            all_selection_lines_are_comments = false;
16635                        }
16636
16637                        selection_edit_ranges.push(prefix_range);
16638                    }
16639
16640                    if all_selection_lines_are_comments {
16641                        edits.extend(
16642                            selection_edit_ranges
16643                                .iter()
16644                                .cloned()
16645                                .map(|range| (range, empty_str.clone())),
16646                        );
16647                    } else {
16648                        let min_column = selection_edit_ranges
16649                            .iter()
16650                            .map(|range| range.start.column)
16651                            .min()
16652                            .unwrap_or(0);
16653                        edits.extend(selection_edit_ranges.iter().map(|range| {
16654                            let position = Point::new(range.start.row, min_column);
16655                            (position..position, first_prefix.clone())
16656                        }));
16657                    }
16658                } else if let Some(BlockCommentConfig {
16659                    start: full_comment_prefix,
16660                    end: comment_suffix,
16661                    ..
16662                }) = language.block_comment()
16663                {
16664                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16665                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16666                    let prefix_range = comment_prefix_range(
16667                        snapshot.deref(),
16668                        start_row,
16669                        comment_prefix,
16670                        comment_prefix_whitespace,
16671                        ignore_indent,
16672                    );
16673                    let suffix_range = comment_suffix_range(
16674                        snapshot.deref(),
16675                        end_row,
16676                        comment_suffix.trim_start_matches(' '),
16677                        comment_suffix.starts_with(' '),
16678                    );
16679
16680                    if prefix_range.is_empty() || suffix_range.is_empty() {
16681                        edits.push((
16682                            prefix_range.start..prefix_range.start,
16683                            full_comment_prefix.clone(),
16684                        ));
16685                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16686                        suffixes_inserted.push((end_row, comment_suffix.len()));
16687                    } else {
16688                        edits.push((prefix_range, empty_str.clone()));
16689                        edits.push((suffix_range, empty_str.clone()));
16690                    }
16691                } else {
16692                    continue;
16693                }
16694            }
16695
16696            drop(snapshot);
16697            this.buffer.update(cx, |buffer, cx| {
16698                buffer.edit(edits, None, cx);
16699            });
16700
16701            // Adjust selections so that they end before any comment suffixes that
16702            // were inserted.
16703            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16704            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16705            let snapshot = this.buffer.read(cx).read(cx);
16706            for selection in &mut selections {
16707                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16708                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16709                        Ordering::Less => {
16710                            suffixes_inserted.next();
16711                            continue;
16712                        }
16713                        Ordering::Greater => break,
16714                        Ordering::Equal => {
16715                            if selection.end.column == snapshot.line_len(row) {
16716                                if selection.is_empty() {
16717                                    selection.start.column -= suffix_len as u32;
16718                                }
16719                                selection.end.column -= suffix_len as u32;
16720                            }
16721                            break;
16722                        }
16723                    }
16724                }
16725            }
16726
16727            drop(snapshot);
16728            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16729
16730            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16731            let selections_on_single_row = selections.windows(2).all(|selections| {
16732                selections[0].start.row == selections[1].start.row
16733                    && selections[0].end.row == selections[1].end.row
16734                    && selections[0].start.row == selections[0].end.row
16735            });
16736            let selections_selecting = selections
16737                .iter()
16738                .any(|selection| selection.start != selection.end);
16739            let advance_downwards = action.advance_downwards
16740                && selections_on_single_row
16741                && !selections_selecting
16742                && !matches!(this.mode, EditorMode::SingleLine);
16743
16744            if advance_downwards {
16745                let snapshot = this.buffer.read(cx).snapshot(cx);
16746
16747                this.change_selections(Default::default(), window, cx, |s| {
16748                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16749                        let mut point = display_point.to_point(display_snapshot);
16750                        point.row += 1;
16751                        point = snapshot.clip_point(point, Bias::Left);
16752                        let display_point = point.to_display_point(display_snapshot);
16753                        let goal = SelectionGoal::HorizontalPosition(
16754                            display_snapshot
16755                                .x_for_display_point(display_point, text_layout_details)
16756                                .into(),
16757                        );
16758                        (display_point, goal)
16759                    })
16760                });
16761            }
16762        });
16763    }
16764
16765    pub fn select_enclosing_symbol(
16766        &mut self,
16767        _: &SelectEnclosingSymbol,
16768        window: &mut Window,
16769        cx: &mut Context<Self>,
16770    ) {
16771        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16772
16773        let buffer = self.buffer.read(cx).snapshot(cx);
16774        let old_selections = self
16775            .selections
16776            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16777            .into_boxed_slice();
16778
16779        fn update_selection(
16780            selection: &Selection<MultiBufferOffset>,
16781            buffer_snap: &MultiBufferSnapshot,
16782        ) -> Option<Selection<MultiBufferOffset>> {
16783            let cursor = selection.head();
16784            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16785            for symbol in symbols.iter().rev() {
16786                let start = symbol.range.start.to_offset(buffer_snap);
16787                let end = symbol.range.end.to_offset(buffer_snap);
16788                let new_range = start..end;
16789                if start < selection.start || end > selection.end {
16790                    return Some(Selection {
16791                        id: selection.id,
16792                        start: new_range.start,
16793                        end: new_range.end,
16794                        goal: SelectionGoal::None,
16795                        reversed: selection.reversed,
16796                    });
16797                }
16798            }
16799            None
16800        }
16801
16802        let mut selected_larger_symbol = false;
16803        let new_selections = old_selections
16804            .iter()
16805            .map(|selection| match update_selection(selection, &buffer) {
16806                Some(new_selection) => {
16807                    if new_selection.range() != selection.range() {
16808                        selected_larger_symbol = true;
16809                    }
16810                    new_selection
16811                }
16812                None => selection.clone(),
16813            })
16814            .collect::<Vec<_>>();
16815
16816        if selected_larger_symbol {
16817            self.change_selections(Default::default(), window, cx, |s| {
16818                s.select(new_selections);
16819            });
16820        }
16821    }
16822
16823    pub fn select_larger_syntax_node(
16824        &mut self,
16825        _: &SelectLargerSyntaxNode,
16826        window: &mut Window,
16827        cx: &mut Context<Self>,
16828    ) {
16829        let Some(visible_row_count) = self.visible_row_count() else {
16830            return;
16831        };
16832        let old_selections: Box<[_]> = self
16833            .selections
16834            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16835            .into();
16836        if old_selections.is_empty() {
16837            return;
16838        }
16839
16840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16841
16842        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16843        let buffer = self.buffer.read(cx).snapshot(cx);
16844
16845        let mut selected_larger_node = false;
16846        let mut new_selections = old_selections
16847            .iter()
16848            .map(|selection| {
16849                let old_range = selection.start..selection.end;
16850
16851                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16852                    // manually select word at selection
16853                    if ["string_content", "inline"].contains(&node.kind()) {
16854                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16855                        // ignore if word is already selected
16856                        if !word_range.is_empty() && old_range != word_range {
16857                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16858                            // only select word if start and end point belongs to same word
16859                            if word_range == last_word_range {
16860                                selected_larger_node = true;
16861                                return Selection {
16862                                    id: selection.id,
16863                                    start: word_range.start,
16864                                    end: word_range.end,
16865                                    goal: SelectionGoal::None,
16866                                    reversed: selection.reversed,
16867                                };
16868                            }
16869                        }
16870                    }
16871                }
16872
16873                let mut new_range = old_range.clone();
16874                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16875                    new_range = range;
16876                    if !node.is_named() {
16877                        continue;
16878                    }
16879                    if !display_map.intersects_fold(new_range.start)
16880                        && !display_map.intersects_fold(new_range.end)
16881                    {
16882                        break;
16883                    }
16884                }
16885
16886                selected_larger_node |= new_range != old_range;
16887                Selection {
16888                    id: selection.id,
16889                    start: new_range.start,
16890                    end: new_range.end,
16891                    goal: SelectionGoal::None,
16892                    reversed: selection.reversed,
16893                }
16894            })
16895            .collect::<Vec<_>>();
16896
16897        if !selected_larger_node {
16898            return; // don't put this call in the history
16899        }
16900
16901        // scroll based on transformation done to the last selection created by the user
16902        let (last_old, last_new) = old_selections
16903            .last()
16904            .zip(new_selections.last().cloned())
16905            .expect("old_selections isn't empty");
16906
16907        let is_selection_reversed = if new_selections.len() == 1 {
16908            let should_be_reversed = last_old.start != last_new.start;
16909            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
16910            should_be_reversed
16911        } else {
16912            last_new.reversed
16913        };
16914
16915        if selected_larger_node {
16916            self.select_syntax_node_history.disable_clearing = true;
16917            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16918                s.select(new_selections.clone());
16919            });
16920            self.select_syntax_node_history.disable_clearing = false;
16921        }
16922
16923        let start_row = last_new.start.to_display_point(&display_map).row().0;
16924        let end_row = last_new.end.to_display_point(&display_map).row().0;
16925        let selection_height = end_row - start_row + 1;
16926        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16927
16928        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16929        let scroll_behavior = if fits_on_the_screen {
16930            self.request_autoscroll(Autoscroll::fit(), cx);
16931            SelectSyntaxNodeScrollBehavior::FitSelection
16932        } else if is_selection_reversed {
16933            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16934            SelectSyntaxNodeScrollBehavior::CursorTop
16935        } else {
16936            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16937            SelectSyntaxNodeScrollBehavior::CursorBottom
16938        };
16939
16940        let old_selections: Box<[Selection<Anchor>]> = old_selections
16941            .iter()
16942            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16943            .collect();
16944        self.select_syntax_node_history.push((
16945            old_selections,
16946            scroll_behavior,
16947            is_selection_reversed,
16948        ));
16949    }
16950
16951    pub fn select_smaller_syntax_node(
16952        &mut self,
16953        _: &SelectSmallerSyntaxNode,
16954        window: &mut Window,
16955        cx: &mut Context<Self>,
16956    ) {
16957        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16958
16959        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16960            self.select_syntax_node_history.pop()
16961        {
16962            if let Some(selection) = selections.last_mut() {
16963                selection.reversed = is_selection_reversed;
16964            }
16965
16966            let snapshot = self.buffer.read(cx).snapshot(cx);
16967            let selections: Vec<Selection<MultiBufferOffset>> = selections
16968                .iter()
16969                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16970                .collect();
16971
16972            self.select_syntax_node_history.disable_clearing = true;
16973            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16974                s.select(selections);
16975            });
16976            self.select_syntax_node_history.disable_clearing = false;
16977
16978            match scroll_behavior {
16979                SelectSyntaxNodeScrollBehavior::CursorTop => {
16980                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16981                }
16982                SelectSyntaxNodeScrollBehavior::FitSelection => {
16983                    self.request_autoscroll(Autoscroll::fit(), cx);
16984                }
16985                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16986                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16987                }
16988            }
16989        }
16990    }
16991
16992    pub fn unwrap_syntax_node(
16993        &mut self,
16994        _: &UnwrapSyntaxNode,
16995        window: &mut Window,
16996        cx: &mut Context<Self>,
16997    ) {
16998        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16999
17000        let buffer = self.buffer.read(cx).snapshot(cx);
17001        let selections = self
17002            .selections
17003            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17004            .into_iter()
17005            // subtracting the offset requires sorting
17006            .sorted_by_key(|i| i.start);
17007
17008        let full_edits = selections
17009            .into_iter()
17010            .filter_map(|selection| {
17011                let child = if selection.is_empty()
17012                    && let Some((_, ancestor_range)) =
17013                        buffer.syntax_ancestor(selection.start..selection.end)
17014                {
17015                    ancestor_range
17016                } else {
17017                    selection.range()
17018                };
17019
17020                let mut parent = child.clone();
17021                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
17022                    parent = ancestor_range;
17023                    if parent.start < child.start || parent.end > child.end {
17024                        break;
17025                    }
17026                }
17027
17028                if parent == child {
17029                    return None;
17030                }
17031                let text = buffer.text_for_range(child).collect::<String>();
17032                Some((selection.id, parent, text))
17033            })
17034            .collect::<Vec<_>>();
17035        if full_edits.is_empty() {
17036            return;
17037        }
17038
17039        self.transact(window, cx, |this, window, cx| {
17040            this.buffer.update(cx, |buffer, cx| {
17041                buffer.edit(
17042                    full_edits
17043                        .iter()
17044                        .map(|(_, p, t)| (p.clone(), t.clone()))
17045                        .collect::<Vec<_>>(),
17046                    None,
17047                    cx,
17048                );
17049            });
17050            this.change_selections(Default::default(), window, cx, |s| {
17051                let mut offset = 0;
17052                let mut selections = vec![];
17053                for (id, parent, text) in full_edits {
17054                    let start = parent.start - offset;
17055                    offset += (parent.end - parent.start) - text.len();
17056                    selections.push(Selection {
17057                        id,
17058                        start,
17059                        end: start + text.len(),
17060                        reversed: false,
17061                        goal: Default::default(),
17062                    });
17063                }
17064                s.select(selections);
17065            });
17066        });
17067    }
17068
17069    pub fn select_next_syntax_node(
17070        &mut self,
17071        _: &SelectNextSyntaxNode,
17072        window: &mut Window,
17073        cx: &mut Context<Self>,
17074    ) {
17075        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
17076        if old_selections.is_empty() {
17077            return;
17078        }
17079
17080        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17081
17082        let buffer = self.buffer.read(cx).snapshot(cx);
17083        let mut selected_sibling = false;
17084
17085        let new_selections = old_selections
17086            .iter()
17087            .map(|selection| {
17088                let old_range =
17089                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
17090                if let Some(results) = buffer.map_excerpt_ranges(
17091                    old_range,
17092                    |buf, _excerpt_range, input_buffer_range| {
17093                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
17094                            return Vec::new();
17095                        };
17096                        vec![(
17097                            BufferOffset(node.byte_range().start)
17098                                ..BufferOffset(node.byte_range().end),
17099                            (),
17100                        )]
17101                    },
17102                ) && let [(new_range, _)] = results.as_slice()
17103                {
17104                    selected_sibling = true;
17105                    let new_range =
17106                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
17107                    Selection {
17108                        id: selection.id,
17109                        start: new_range.start,
17110                        end: new_range.end,
17111                        goal: SelectionGoal::None,
17112                        reversed: selection.reversed,
17113                    }
17114                } else {
17115                    selection.clone()
17116                }
17117            })
17118            .collect::<Vec<_>>();
17119
17120        if selected_sibling {
17121            self.change_selections(
17122                SelectionEffects::scroll(Autoscroll::fit()),
17123                window,
17124                cx,
17125                |s| {
17126                    s.select(new_selections);
17127                },
17128            );
17129        }
17130    }
17131
17132    pub fn select_prev_syntax_node(
17133        &mut self,
17134        _: &SelectPreviousSyntaxNode,
17135        window: &mut Window,
17136        cx: &mut Context<Self>,
17137    ) {
17138        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
17139
17140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17141
17142        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
17143        let mut selected_sibling = false;
17144
17145        let new_selections = old_selections
17146            .iter()
17147            .map(|selection| {
17148                let old_range = selection.start.to_offset(&multibuffer_snapshot)
17149                    ..selection.end.to_offset(&multibuffer_snapshot);
17150                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
17151                    old_range,
17152                    |buf, _excerpt_range, input_buffer_range| {
17153                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
17154                            return Vec::new();
17155                        };
17156                        vec![(
17157                            BufferOffset(node.byte_range().start)
17158                                ..BufferOffset(node.byte_range().end),
17159                            (),
17160                        )]
17161                    },
17162                ) && let [(new_range, _)] = results.as_slice()
17163                {
17164                    selected_sibling = true;
17165                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
17166                        ..multibuffer_snapshot.anchor_before(new_range.end);
17167                    Selection {
17168                        id: selection.id,
17169                        start: new_range.start,
17170                        end: new_range.end,
17171                        goal: SelectionGoal::None,
17172                        reversed: selection.reversed,
17173                    }
17174                } else {
17175                    selection.clone()
17176                }
17177            })
17178            .collect::<Vec<_>>();
17179
17180        if selected_sibling {
17181            self.change_selections(
17182                SelectionEffects::scroll(Autoscroll::fit()),
17183                window,
17184                cx,
17185                |s| {
17186                    s.select(new_selections);
17187                },
17188            );
17189        }
17190    }
17191
17192    pub fn move_to_start_of_larger_syntax_node(
17193        &mut self,
17194        _: &MoveToStartOfLargerSyntaxNode,
17195        window: &mut Window,
17196        cx: &mut Context<Self>,
17197    ) {
17198        self.move_cursors_to_syntax_nodes(window, cx, false);
17199    }
17200
17201    pub fn move_to_end_of_larger_syntax_node(
17202        &mut self,
17203        _: &MoveToEndOfLargerSyntaxNode,
17204        window: &mut Window,
17205        cx: &mut Context<Self>,
17206    ) {
17207        self.move_cursors_to_syntax_nodes(window, cx, true);
17208    }
17209
17210    fn find_syntax_node_boundary(
17211        &self,
17212        selection_pos: MultiBufferOffset,
17213        move_to_end: bool,
17214        display_map: &DisplaySnapshot,
17215        buffer: &MultiBufferSnapshot,
17216    ) -> MultiBufferOffset {
17217        let old_range = selection_pos..selection_pos;
17218        let mut new_pos = selection_pos;
17219        let mut search_range = old_range;
17220        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17221            search_range = range.clone();
17222            if !node.is_named()
17223                || display_map.intersects_fold(range.start)
17224                || display_map.intersects_fold(range.end)
17225                // If cursor is already at the end of the syntax node, continue searching
17226                || (move_to_end && range.end == selection_pos)
17227                // If cursor is already at the start of the syntax node, continue searching
17228                || (!move_to_end && range.start == selection_pos)
17229            {
17230                continue;
17231            }
17232
17233            // If we found a string_content node, find the largest parent that is still string_content
17234            // Enables us to skip to the end of strings without taking multiple steps inside the string
17235            let (_, final_range) = if node.kind() == "string_content" {
17236                let mut current_node = node;
17237                let mut current_range = range;
17238                while let Some((parent, parent_range)) =
17239                    buffer.syntax_ancestor(current_range.clone())
17240                {
17241                    if parent.kind() == "string_content" {
17242                        current_node = parent;
17243                        current_range = parent_range;
17244                    } else {
17245                        break;
17246                    }
17247                }
17248
17249                (current_node, current_range)
17250            } else {
17251                (node, range)
17252            };
17253
17254            new_pos = if move_to_end {
17255                final_range.end
17256            } else {
17257                final_range.start
17258            };
17259
17260            break;
17261        }
17262
17263        new_pos
17264    }
17265
17266    fn move_cursors_to_syntax_nodes(
17267        &mut self,
17268        window: &mut Window,
17269        cx: &mut Context<Self>,
17270        move_to_end: bool,
17271    ) -> bool {
17272        let old_selections: Box<[_]> = self
17273            .selections
17274            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17275            .into();
17276        if old_selections.is_empty() {
17277            return false;
17278        }
17279
17280        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17281
17282        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17283        let buffer = self.buffer.read(cx).snapshot(cx);
17284
17285        let mut any_cursor_moved = false;
17286        let new_selections = old_selections
17287            .iter()
17288            .map(|selection| {
17289                if !selection.is_empty() {
17290                    return selection.clone();
17291                }
17292
17293                let selection_pos = selection.head();
17294                let new_pos = self.find_syntax_node_boundary(
17295                    selection_pos,
17296                    move_to_end,
17297                    &display_map,
17298                    &buffer,
17299                );
17300
17301                any_cursor_moved |= new_pos != selection_pos;
17302
17303                Selection {
17304                    id: selection.id,
17305                    start: new_pos,
17306                    end: new_pos,
17307                    goal: SelectionGoal::None,
17308                    reversed: false,
17309                }
17310            })
17311            .collect::<Vec<_>>();
17312
17313        self.change_selections(Default::default(), window, cx, |s| {
17314            s.select(new_selections);
17315        });
17316        self.request_autoscroll(Autoscroll::newest(), cx);
17317
17318        any_cursor_moved
17319    }
17320
17321    pub fn select_to_start_of_larger_syntax_node(
17322        &mut self,
17323        _: &SelectToStartOfLargerSyntaxNode,
17324        window: &mut Window,
17325        cx: &mut Context<Self>,
17326    ) {
17327        self.select_to_syntax_nodes(window, cx, false);
17328    }
17329
17330    pub fn select_to_end_of_larger_syntax_node(
17331        &mut self,
17332        _: &SelectToEndOfLargerSyntaxNode,
17333        window: &mut Window,
17334        cx: &mut Context<Self>,
17335    ) {
17336        self.select_to_syntax_nodes(window, cx, true);
17337    }
17338
17339    fn select_to_syntax_nodes(
17340        &mut self,
17341        window: &mut Window,
17342        cx: &mut Context<Self>,
17343        move_to_end: bool,
17344    ) {
17345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17346
17347        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17348        let buffer = self.buffer.read(cx).snapshot(cx);
17349        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17350
17351        let new_selections = old_selections
17352            .iter()
17353            .map(|selection| {
17354                let new_pos = self.find_syntax_node_boundary(
17355                    selection.head(),
17356                    move_to_end,
17357                    &display_map,
17358                    &buffer,
17359                );
17360
17361                let mut new_selection = selection.clone();
17362                new_selection.set_head(new_pos, SelectionGoal::None);
17363                new_selection
17364            })
17365            .collect::<Vec<_>>();
17366
17367        self.change_selections(Default::default(), window, cx, |s| {
17368            s.select(new_selections);
17369        });
17370    }
17371
17372    pub fn move_to_enclosing_bracket(
17373        &mut self,
17374        _: &MoveToEnclosingBracket,
17375        window: &mut Window,
17376        cx: &mut Context<Self>,
17377    ) {
17378        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17379        self.change_selections(Default::default(), window, cx, |s| {
17380            s.move_offsets_with(&mut |snapshot, selection| {
17381                let Some(enclosing_bracket_ranges) =
17382                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17383                else {
17384                    return;
17385                };
17386
17387                let mut best_length = usize::MAX;
17388                let mut best_inside = false;
17389                let mut best_in_bracket_range = false;
17390                let mut best_destination = None;
17391                for (open, close) in enclosing_bracket_ranges {
17392                    let close = close.to_inclusive();
17393                    let length = *close.end() - open.start;
17394                    let inside = selection.start >= open.end && selection.end <= *close.start();
17395                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17396                        || close.contains(&selection.head());
17397
17398                    // If best is next to a bracket and current isn't, skip
17399                    if !in_bracket_range && best_in_bracket_range {
17400                        continue;
17401                    }
17402
17403                    // Prefer smaller lengths unless best is inside and current isn't
17404                    if length > best_length && (best_inside || !inside) {
17405                        continue;
17406                    }
17407
17408                    best_length = length;
17409                    best_inside = inside;
17410                    best_in_bracket_range = in_bracket_range;
17411                    best_destination = Some(
17412                        if close.contains(&selection.start) && close.contains(&selection.end) {
17413                            if inside { open.end } else { open.start }
17414                        } else if inside {
17415                            *close.start()
17416                        } else {
17417                            *close.end()
17418                        },
17419                    );
17420                }
17421
17422                if let Some(destination) = best_destination {
17423                    selection.collapse_to(destination, SelectionGoal::None);
17424                }
17425            })
17426        });
17427    }
17428
17429    pub fn undo_selection(
17430        &mut self,
17431        _: &UndoSelection,
17432        window: &mut Window,
17433        cx: &mut Context<Self>,
17434    ) {
17435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17436        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17437            self.selection_history.mode = SelectionHistoryMode::Undoing;
17438            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17439                this.end_selection(window, cx);
17440                this.change_selections(
17441                    SelectionEffects::scroll(Autoscroll::newest()),
17442                    window,
17443                    cx,
17444                    |s| s.select_anchors(entry.selections.to_vec()),
17445                );
17446            });
17447            self.selection_history.mode = SelectionHistoryMode::Normal;
17448
17449            self.select_next_state = entry.select_next_state;
17450            self.select_prev_state = entry.select_prev_state;
17451            self.add_selections_state = entry.add_selections_state;
17452        }
17453    }
17454
17455    pub fn redo_selection(
17456        &mut self,
17457        _: &RedoSelection,
17458        window: &mut Window,
17459        cx: &mut Context<Self>,
17460    ) {
17461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17462        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17463            self.selection_history.mode = SelectionHistoryMode::Redoing;
17464            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17465                this.end_selection(window, cx);
17466                this.change_selections(
17467                    SelectionEffects::scroll(Autoscroll::newest()),
17468                    window,
17469                    cx,
17470                    |s| s.select_anchors(entry.selections.to_vec()),
17471                );
17472            });
17473            self.selection_history.mode = SelectionHistoryMode::Normal;
17474
17475            self.select_next_state = entry.select_next_state;
17476            self.select_prev_state = entry.select_prev_state;
17477            self.add_selections_state = entry.add_selections_state;
17478        }
17479    }
17480
17481    pub fn expand_excerpts(
17482        &mut self,
17483        action: &ExpandExcerpts,
17484        _: &mut Window,
17485        cx: &mut Context<Self>,
17486    ) {
17487        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17488    }
17489
17490    pub fn expand_excerpts_down(
17491        &mut self,
17492        action: &ExpandExcerptsDown,
17493        _: &mut Window,
17494        cx: &mut Context<Self>,
17495    ) {
17496        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17497    }
17498
17499    pub fn expand_excerpts_up(
17500        &mut self,
17501        action: &ExpandExcerptsUp,
17502        _: &mut Window,
17503        cx: &mut Context<Self>,
17504    ) {
17505        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17506    }
17507
17508    pub fn expand_excerpts_for_direction(
17509        &mut self,
17510        lines: u32,
17511        direction: ExpandExcerptDirection,
17512        cx: &mut Context<Self>,
17513    ) {
17514        let selections = self.selections.disjoint_anchors_arc();
17515
17516        let lines = if lines == 0 {
17517            EditorSettings::get_global(cx).expand_excerpt_lines
17518        } else {
17519            lines
17520        };
17521
17522        let snapshot = self.buffer.read(cx).snapshot(cx);
17523        let excerpt_anchors = selections
17524            .iter()
17525            .flat_map(|selection| {
17526                snapshot
17527                    .range_to_buffer_ranges(selection.range())
17528                    .into_iter()
17529                    .filter_map(|(buffer_snapshot, range, _)| {
17530                        snapshot.anchor_in_excerpt(buffer_snapshot.anchor_after(range.start))
17531                    })
17532            })
17533            .collect::<Vec<_>>();
17534
17535        if self.delegate_expand_excerpts {
17536            cx.emit(EditorEvent::ExpandExcerptsRequested {
17537                excerpt_anchors,
17538                lines,
17539                direction,
17540            });
17541            return;
17542        }
17543
17544        self.buffer.update(cx, |buffer, cx| {
17545            buffer.expand_excerpts(excerpt_anchors, lines, direction, cx)
17546        })
17547    }
17548
17549    pub(crate) fn expand_excerpt(
17550        &mut self,
17551        excerpt_anchor: Anchor,
17552        direction: ExpandExcerptDirection,
17553        window: &mut Window,
17554        cx: &mut Context<Self>,
17555    ) {
17556        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17557
17558        if self.delegate_expand_excerpts {
17559            cx.emit(EditorEvent::ExpandExcerptsRequested {
17560                excerpt_anchors: vec![excerpt_anchor],
17561                lines: lines_to_expand,
17562                direction,
17563            });
17564            return;
17565        }
17566
17567        let current_scroll_position = self.scroll_position(cx);
17568        let mut scroll = None;
17569
17570        if direction == ExpandExcerptDirection::Down {
17571            let multi_buffer = self.buffer.read(cx);
17572            let snapshot = multi_buffer.snapshot(cx);
17573            if let Some((buffer_snapshot, excerpt_range)) =
17574                snapshot.excerpt_containing(excerpt_anchor..excerpt_anchor)
17575            {
17576                let excerpt_end_row =
17577                    Point::from_anchor(&excerpt_range.context.end, &buffer_snapshot).row;
17578                let last_row = buffer_snapshot.max_point().row;
17579                let lines_below = last_row.saturating_sub(excerpt_end_row);
17580                if lines_below >= lines_to_expand {
17581                    scroll = Some(
17582                        current_scroll_position
17583                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17584                    );
17585                }
17586            }
17587        }
17588        if direction == ExpandExcerptDirection::Up
17589            && self
17590                .buffer
17591                .read(cx)
17592                .snapshot(cx)
17593                .excerpt_before(excerpt_anchor)
17594                .is_none()
17595        {
17596            scroll = Some(current_scroll_position);
17597        }
17598
17599        self.buffer.update(cx, |buffer, cx| {
17600            buffer.expand_excerpts([excerpt_anchor], lines_to_expand, direction, cx)
17601        });
17602
17603        if let Some(new_scroll_position) = scroll {
17604            self.set_scroll_position(new_scroll_position, window, cx);
17605        }
17606    }
17607
17608    pub fn go_to_singleton_buffer_point(
17609        &mut self,
17610        point: Point,
17611        window: &mut Window,
17612        cx: &mut Context<Self>,
17613    ) {
17614        self.go_to_singleton_buffer_range(point..point, window, cx);
17615    }
17616
17617    pub fn go_to_singleton_buffer_range(
17618        &mut self,
17619        range: Range<Point>,
17620        window: &mut Window,
17621        cx: &mut Context<Self>,
17622    ) {
17623        let multibuffer = self.buffer().read(cx);
17624        if !multibuffer.is_singleton() {
17625            return;
17626        };
17627        let anchor_range = range.to_anchors(&multibuffer.snapshot(cx));
17628        self.change_selections(
17629            SelectionEffects::default().nav_history(true),
17630            window,
17631            cx,
17632            |s| s.select_anchor_ranges([anchor_range]),
17633        );
17634    }
17635
17636    pub fn go_to_diagnostic(
17637        &mut self,
17638        action: &GoToDiagnostic,
17639        window: &mut Window,
17640        cx: &mut Context<Self>,
17641    ) {
17642        if !self.diagnostics_enabled() {
17643            return;
17644        }
17645        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17646        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17647    }
17648
17649    pub fn go_to_prev_diagnostic(
17650        &mut self,
17651        action: &GoToPreviousDiagnostic,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) {
17655        if !self.diagnostics_enabled() {
17656            return;
17657        }
17658        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17659        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17660    }
17661
17662    pub fn go_to_diagnostic_impl(
17663        &mut self,
17664        direction: Direction,
17665        severity: GoToDiagnosticSeverityFilter,
17666        window: &mut Window,
17667        cx: &mut Context<Self>,
17668    ) {
17669        let buffer = self.buffer.read(cx).snapshot(cx);
17670        let selection = self
17671            .selections
17672            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17673
17674        let mut active_group_id = None;
17675        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17676            && active_group.active_range.start.to_offset(&buffer) == selection.start
17677        {
17678            active_group_id = Some(active_group.group_id);
17679        }
17680
17681        fn filtered<'a>(
17682            severity: GoToDiagnosticSeverityFilter,
17683            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17684        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17685            diagnostics
17686                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17687                .filter(|entry| entry.range.start != entry.range.end)
17688                .filter(|entry| !entry.diagnostic.is_unnecessary)
17689        }
17690
17691        let before = filtered(
17692            severity,
17693            buffer
17694                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17695                .filter(|entry| entry.range.start <= selection.start),
17696        );
17697        let after = filtered(
17698            severity,
17699            buffer
17700                .diagnostics_in_range(selection.start..buffer.len())
17701                .filter(|entry| entry.range.start >= selection.start),
17702        );
17703
17704        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17705        if direction == Direction::Prev {
17706            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17707            {
17708                for diagnostic in prev_diagnostics.into_iter().rev() {
17709                    if diagnostic.range.start != selection.start
17710                        || active_group_id
17711                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17712                    {
17713                        found = Some(diagnostic);
17714                        break 'outer;
17715                    }
17716                }
17717            }
17718        } else {
17719            for diagnostic in after.chain(before) {
17720                if diagnostic.range.start != selection.start
17721                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17722                {
17723                    found = Some(diagnostic);
17724                    break;
17725                }
17726            }
17727        }
17728        let Some(next_diagnostic) = found else {
17729            return;
17730        };
17731
17732        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17733        let Some((buffer_anchor, _)) = buffer.anchor_to_buffer_anchor(next_diagnostic_start) else {
17734            return;
17735        };
17736        let buffer_id = buffer_anchor.buffer_id;
17737        let snapshot = self.snapshot(window, cx);
17738        if snapshot.intersects_fold(next_diagnostic.range.start) {
17739            self.unfold_ranges(
17740                std::slice::from_ref(&next_diagnostic.range),
17741                true,
17742                false,
17743                cx,
17744            );
17745        }
17746        self.change_selections(Default::default(), window, cx, |s| {
17747            s.select_ranges(vec![
17748                next_diagnostic.range.start..next_diagnostic.range.start,
17749            ])
17750        });
17751        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17752        self.refresh_edit_prediction(false, true, window, cx);
17753    }
17754
17755    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17756        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17757        let snapshot = self.snapshot(window, cx);
17758        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17759        self.go_to_hunk_before_or_after_position(
17760            &snapshot,
17761            selection.head(),
17762            Direction::Next,
17763            true,
17764            window,
17765            cx,
17766        );
17767    }
17768
17769    pub fn go_to_hunk_before_or_after_position(
17770        &mut self,
17771        snapshot: &EditorSnapshot,
17772        position: Point,
17773        direction: Direction,
17774        wrap_around: bool,
17775        window: &mut Window,
17776        cx: &mut Context<Editor>,
17777    ) {
17778        let row = if direction == Direction::Next {
17779            self.hunk_after_position(snapshot, position, wrap_around)
17780                .map(|hunk| hunk.row_range.start)
17781        } else {
17782            self.hunk_before_position(snapshot, position, wrap_around)
17783        };
17784
17785        if let Some(row) = row {
17786            let destination = Point::new(row.0, 0);
17787            let autoscroll = Autoscroll::center();
17788
17789            self.unfold_ranges(&[destination..destination], false, false, cx);
17790            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17791                s.select_ranges([destination..destination]);
17792            });
17793        }
17794    }
17795
17796    fn hunk_after_position(
17797        &mut self,
17798        snapshot: &EditorSnapshot,
17799        position: Point,
17800        wrap_around: bool,
17801    ) -> Option<MultiBufferDiffHunk> {
17802        let result = snapshot
17803            .buffer_snapshot()
17804            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17805            .find(|hunk| hunk.row_range.start.0 > position.row);
17806
17807        if wrap_around {
17808            result.or_else(|| {
17809                snapshot
17810                    .buffer_snapshot()
17811                    .diff_hunks_in_range(Point::zero()..position)
17812                    .find(|hunk| hunk.row_range.end.0 < position.row)
17813            })
17814        } else {
17815            result
17816        }
17817    }
17818
17819    fn go_to_prev_hunk(
17820        &mut self,
17821        _: &GoToPreviousHunk,
17822        window: &mut Window,
17823        cx: &mut Context<Self>,
17824    ) {
17825        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17826        let snapshot = self.snapshot(window, cx);
17827        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17828        self.go_to_hunk_before_or_after_position(
17829            &snapshot,
17830            selection.head(),
17831            Direction::Prev,
17832            true,
17833            window,
17834            cx,
17835        );
17836    }
17837
17838    fn hunk_before_position(
17839        &mut self,
17840        snapshot: &EditorSnapshot,
17841        position: Point,
17842        wrap_around: bool,
17843    ) -> Option<MultiBufferRow> {
17844        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17845
17846        if wrap_around {
17847            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17848        } else {
17849            result
17850        }
17851    }
17852
17853    fn go_to_next_change(
17854        &mut self,
17855        _: &GoToNextChange,
17856        window: &mut Window,
17857        cx: &mut Context<Self>,
17858    ) {
17859        if let Some(selections) = self
17860            .change_list
17861            .next_change(1, Direction::Next)
17862            .map(|s| s.to_vec())
17863        {
17864            self.change_selections(Default::default(), window, cx, |s| {
17865                let map = s.display_snapshot();
17866                s.select_display_ranges(selections.iter().map(|a| {
17867                    let point = a.to_display_point(&map);
17868                    point..point
17869                }))
17870            })
17871        }
17872    }
17873
17874    fn go_to_previous_change(
17875        &mut self,
17876        _: &GoToPreviousChange,
17877        window: &mut Window,
17878        cx: &mut Context<Self>,
17879    ) {
17880        if let Some(selections) = self
17881            .change_list
17882            .next_change(1, Direction::Prev)
17883            .map(|s| s.to_vec())
17884        {
17885            self.change_selections(Default::default(), window, cx, |s| {
17886                let map = s.display_snapshot();
17887                s.select_display_ranges(selections.iter().map(|a| {
17888                    let point = a.to_display_point(&map);
17889                    point..point
17890                }))
17891            })
17892        }
17893    }
17894
17895    pub fn go_to_next_document_highlight(
17896        &mut self,
17897        _: &GoToNextDocumentHighlight,
17898        window: &mut Window,
17899        cx: &mut Context<Self>,
17900    ) {
17901        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17902    }
17903
17904    pub fn go_to_prev_document_highlight(
17905        &mut self,
17906        _: &GoToPreviousDocumentHighlight,
17907        window: &mut Window,
17908        cx: &mut Context<Self>,
17909    ) {
17910        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17911    }
17912
17913    pub fn go_to_document_highlight_before_or_after_position(
17914        &mut self,
17915        direction: Direction,
17916        window: &mut Window,
17917        cx: &mut Context<Editor>,
17918    ) {
17919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17920        let snapshot = self.snapshot(window, cx);
17921        let buffer = &snapshot.buffer_snapshot();
17922        let position = self
17923            .selections
17924            .newest::<Point>(&snapshot.display_snapshot)
17925            .head();
17926        let anchor_position = buffer.anchor_after(position);
17927
17928        // Get all document highlights (both read and write)
17929        let mut all_highlights = Vec::new();
17930
17931        if let Some((_, read_highlights)) = self
17932            .background_highlights
17933            .get(&HighlightKey::DocumentHighlightRead)
17934        {
17935            all_highlights.extend(read_highlights.iter());
17936        }
17937
17938        if let Some((_, write_highlights)) = self
17939            .background_highlights
17940            .get(&HighlightKey::DocumentHighlightWrite)
17941        {
17942            all_highlights.extend(write_highlights.iter());
17943        }
17944
17945        if all_highlights.is_empty() {
17946            return;
17947        }
17948
17949        // Sort highlights by position
17950        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17951
17952        let target_highlight = match direction {
17953            Direction::Next => {
17954                // Find the first highlight after the current position
17955                all_highlights
17956                    .iter()
17957                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17958            }
17959            Direction::Prev => {
17960                // Find the last highlight before the current position
17961                all_highlights
17962                    .iter()
17963                    .rev()
17964                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17965            }
17966        };
17967
17968        if let Some(highlight) = target_highlight {
17969            let destination = highlight.start.to_point(buffer);
17970            let autoscroll = Autoscroll::center();
17971
17972            self.unfold_ranges(&[destination..destination], false, false, cx);
17973            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17974                s.select_ranges([destination..destination]);
17975            });
17976        }
17977    }
17978
17979    fn go_to_line<T: 'static>(
17980        &mut self,
17981        position: Anchor,
17982        highlight_color: Option<Hsla>,
17983        window: &mut Window,
17984        cx: &mut Context<Self>,
17985    ) {
17986        let snapshot = self.snapshot(window, cx).display_snapshot;
17987        let position = position.to_point(&snapshot.buffer_snapshot());
17988        let start = snapshot
17989            .buffer_snapshot()
17990            .clip_point(Point::new(position.row, 0), Bias::Left);
17991        let end = start + Point::new(1, 0);
17992        let start = snapshot.buffer_snapshot().anchor_before(start);
17993        let end = snapshot.buffer_snapshot().anchor_before(end);
17994
17995        self.highlight_rows::<T>(
17996            start..end,
17997            highlight_color
17998                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17999            Default::default(),
18000            cx,
18001        );
18002
18003        if self.buffer.read(cx).is_singleton() {
18004            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
18005        }
18006    }
18007
18008    pub fn go_to_definition(
18009        &mut self,
18010        _: &GoToDefinition,
18011        window: &mut Window,
18012        cx: &mut Context<Self>,
18013    ) -> Task<Result<Navigated>> {
18014        let definition =
18015            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
18016        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
18017        cx.spawn_in(window, async move |editor, cx| {
18018            if definition.await? == Navigated::Yes {
18019                return Ok(Navigated::Yes);
18020            }
18021            match fallback_strategy {
18022                GoToDefinitionFallback::None => Ok(Navigated::No),
18023                GoToDefinitionFallback::FindAllReferences => {
18024                    match editor.update_in(cx, |editor, window, cx| {
18025                        editor.find_all_references(&FindAllReferences::default(), window, cx)
18026                    })? {
18027                        Some(references) => references.await,
18028                        None => Ok(Navigated::No),
18029                    }
18030                }
18031            }
18032        })
18033    }
18034
18035    pub fn go_to_declaration(
18036        &mut self,
18037        _: &GoToDeclaration,
18038        window: &mut Window,
18039        cx: &mut Context<Self>,
18040    ) -> Task<Result<Navigated>> {
18041        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
18042    }
18043
18044    pub fn go_to_declaration_split(
18045        &mut self,
18046        _: &GoToDeclaration,
18047        window: &mut Window,
18048        cx: &mut Context<Self>,
18049    ) -> Task<Result<Navigated>> {
18050        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
18051    }
18052
18053    pub fn go_to_implementation(
18054        &mut self,
18055        _: &GoToImplementation,
18056        window: &mut Window,
18057        cx: &mut Context<Self>,
18058    ) -> Task<Result<Navigated>> {
18059        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
18060    }
18061
18062    pub fn go_to_implementation_split(
18063        &mut self,
18064        _: &GoToImplementationSplit,
18065        window: &mut Window,
18066        cx: &mut Context<Self>,
18067    ) -> Task<Result<Navigated>> {
18068        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
18069    }
18070
18071    pub fn go_to_type_definition(
18072        &mut self,
18073        _: &GoToTypeDefinition,
18074        window: &mut Window,
18075        cx: &mut Context<Self>,
18076    ) -> Task<Result<Navigated>> {
18077        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
18078    }
18079
18080    pub fn go_to_definition_split(
18081        &mut self,
18082        _: &GoToDefinitionSplit,
18083        window: &mut Window,
18084        cx: &mut Context<Self>,
18085    ) -> Task<Result<Navigated>> {
18086        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18087    }
18088
18089    pub fn go_to_type_definition_split(
18090        &mut self,
18091        _: &GoToTypeDefinitionSplit,
18092        window: &mut Window,
18093        cx: &mut Context<Self>,
18094    ) -> Task<Result<Navigated>> {
18095        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18096    }
18097
18098    fn go_to_definition_of_kind(
18099        &mut self,
18100        kind: GotoDefinitionKind,
18101        split: bool,
18102        window: &mut Window,
18103        cx: &mut Context<Self>,
18104    ) -> Task<Result<Navigated>> {
18105        let Some(provider) = self.semantics_provider.clone() else {
18106            return Task::ready(Ok(Navigated::No));
18107        };
18108        let head = self
18109            .selections
18110            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18111            .head();
18112        let buffer = self.buffer.read(cx);
18113        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18114            return Task::ready(Ok(Navigated::No));
18115        };
18116        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18117            return Task::ready(Ok(Navigated::No));
18118        };
18119
18120        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18121
18122        cx.spawn_in(window, async move |editor, cx| {
18123            let Some(definitions) = definitions.await? else {
18124                return Ok(Navigated::No);
18125            };
18126            let navigated = editor
18127                .update_in(cx, |editor, window, cx| {
18128                    editor.navigate_to_hover_links(
18129                        Some(kind),
18130                        definitions
18131                            .into_iter()
18132                            .filter(|location| {
18133                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18134                            })
18135                            .map(HoverLink::Text)
18136                            .collect::<Vec<_>>(),
18137                        nav_entry,
18138                        split,
18139                        window,
18140                        cx,
18141                    )
18142                })?
18143                .await?;
18144            anyhow::Ok(navigated)
18145        })
18146    }
18147
18148    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18149        let selection = self.selections.newest_anchor();
18150        let head = selection.head();
18151        let tail = selection.tail();
18152
18153        let Some((buffer, start_position)) =
18154            self.buffer.read(cx).text_anchor_for_position(head, cx)
18155        else {
18156            return;
18157        };
18158
18159        let end_position = if head != tail {
18160            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18161                return;
18162            };
18163            Some(pos)
18164        } else {
18165            None
18166        };
18167
18168        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18169            let url = if let Some(end_pos) = end_position {
18170                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18171            } else {
18172                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18173            };
18174
18175            if let Some(url) = url {
18176                cx.update(|window, cx| {
18177                    if parse_zed_link(&url, cx).is_some() {
18178                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18179                    } else {
18180                        cx.open_url(&url);
18181                    }
18182                })?;
18183            }
18184
18185            anyhow::Ok(())
18186        });
18187
18188        url_finder.detach();
18189    }
18190
18191    pub fn open_selected_filename(
18192        &mut self,
18193        _: &OpenSelectedFilename,
18194        window: &mut Window,
18195        cx: &mut Context<Self>,
18196    ) {
18197        let Some(workspace) = self.workspace() else {
18198            return;
18199        };
18200
18201        let position = self.selections.newest_anchor().head();
18202
18203        let Some((buffer, buffer_position)) =
18204            self.buffer.read(cx).text_anchor_for_position(position, cx)
18205        else {
18206            return;
18207        };
18208
18209        let project = self.project.clone();
18210
18211        cx.spawn_in(window, async move |_, cx| {
18212            let result = find_file(&buffer, project, buffer_position, cx).await;
18213
18214            if let Some((_, path)) = result {
18215                workspace
18216                    .update_in(cx, |workspace, window, cx| {
18217                        workspace.open_resolved_path(path, window, cx)
18218                    })?
18219                    .await?;
18220            }
18221            anyhow::Ok(())
18222        })
18223        .detach();
18224    }
18225
18226    pub(crate) fn navigate_to_hover_links(
18227        &mut self,
18228        kind: Option<GotoDefinitionKind>,
18229        definitions: Vec<HoverLink>,
18230        origin: Option<NavigationEntry>,
18231        split: bool,
18232        window: &mut Window,
18233        cx: &mut Context<Editor>,
18234    ) -> Task<Result<Navigated>> {
18235        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18236        let mut first_url_or_file = None;
18237        let definitions: Vec<_> = definitions
18238            .into_iter()
18239            .filter_map(|def| match def {
18240                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18241                HoverLink::InlayHint(lsp_location, server_id) => {
18242                    let computation =
18243                        self.compute_target_location(lsp_location, server_id, window, cx);
18244                    Some(cx.background_spawn(computation))
18245                }
18246                HoverLink::Url(url) => {
18247                    first_url_or_file = Some(Either::Left(url));
18248                    None
18249                }
18250                HoverLink::File(path) => {
18251                    first_url_or_file = Some(Either::Right(path));
18252                    None
18253                }
18254            })
18255            .collect();
18256
18257        let workspace = self.workspace();
18258
18259        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18260        cx.spawn_in(window, async move |editor, cx| {
18261            let locations: Vec<Location> = future::join_all(definitions)
18262                .await
18263                .into_iter()
18264                .filter_map(|location| location.transpose())
18265                .collect::<Result<_>>()
18266                .context("location tasks")?;
18267            let mut locations = cx.update(|_, cx| {
18268                locations
18269                    .into_iter()
18270                    .map(|location| {
18271                        let buffer = location.buffer.read(cx);
18272                        (location.buffer, location.range.to_point(buffer))
18273                    })
18274                    .into_group_map()
18275            })?;
18276            let mut num_locations = 0;
18277            for ranges in locations.values_mut() {
18278                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18279                ranges.dedup();
18280                // Merge overlapping or contained ranges. After sorting by
18281                // (start, Reverse(end)), we can merge in a single pass:
18282                // if the next range starts before the current one ends,
18283                // extend the current range's end if needed.
18284                let mut i = 0;
18285                while i + 1 < ranges.len() {
18286                    if ranges[i + 1].start <= ranges[i].end {
18287                        let merged_end = ranges[i].end.max(ranges[i + 1].end);
18288                        ranges[i].end = merged_end;
18289                        ranges.remove(i + 1);
18290                    } else {
18291                        i += 1;
18292                    }
18293                }
18294                let fits_in_one_excerpt = ranges
18295                    .iter()
18296                    .tuple_windows()
18297                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18298                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18299            }
18300
18301            if num_locations > 1 {
18302                let tab_kind = match kind {
18303                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18304                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18305                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18306                    Some(GotoDefinitionKind::Type) => "Types",
18307                };
18308                let title = editor
18309                    .update_in(cx, |_, _, cx| {
18310                        let target = locations
18311                            .iter()
18312                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18313                            .map(|(buffer, location)| {
18314                                buffer
18315                                    .read(cx)
18316                                    .text_for_range(location.clone())
18317                                    .collect::<String>()
18318                            })
18319                            .filter(|text| !text.contains('\n'))
18320                            .unique()
18321                            .take(3)
18322                            .join(", ");
18323                        if target.is_empty() {
18324                            tab_kind.to_owned()
18325                        } else {
18326                            format!("{tab_kind} for {target}")
18327                        }
18328                    })
18329                    .context("buffer title")?;
18330
18331                let Some(workspace) = workspace else {
18332                    return Ok(Navigated::No);
18333                };
18334
18335                let opened = workspace
18336                    .update_in(cx, |workspace, window, cx| {
18337                        let allow_preview = PreviewTabsSettings::get_global(cx)
18338                            .enable_preview_multibuffer_from_code_navigation;
18339                        if let Some((target_editor, target_pane)) =
18340                            Self::open_locations_in_multibuffer(
18341                                workspace,
18342                                locations,
18343                                title,
18344                                split,
18345                                allow_preview,
18346                                MultibufferSelectionMode::First,
18347                                window,
18348                                cx,
18349                            )
18350                        {
18351                            // We create our own nav history instead of using
18352                            // `target_editor.nav_history` because `nav_history`
18353                            // seems to be populated asynchronously when an item
18354                            // is added to a pane
18355                            let mut nav_history = target_pane
18356                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18357                            target_editor.update(cx, |editor, cx| {
18358                                let nav_data = editor
18359                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18360                                let target =
18361                                    Some(nav_history.navigation_entry(Some(
18362                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18363                                    )));
18364                                nav_history.push_tag(origin, target);
18365                            })
18366                        }
18367                    })
18368                    .is_ok();
18369
18370                anyhow::Ok(Navigated::from_bool(opened))
18371            } else if num_locations == 0 {
18372                // If there is one url or file, open it directly
18373                match first_url_or_file {
18374                    Some(Either::Left(url)) => {
18375                        cx.update(|window, cx| {
18376                            if parse_zed_link(&url, cx).is_some() {
18377                                window
18378                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18379                            } else {
18380                                cx.open_url(&url);
18381                            }
18382                        })?;
18383                        Ok(Navigated::Yes)
18384                    }
18385                    Some(Either::Right(path)) => {
18386                        // TODO(andrew): respect preview tab settings
18387                        //               `enable_keep_preview_on_code_navigation` and
18388                        //               `enable_preview_file_from_code_navigation`
18389                        let Some(workspace) = workspace else {
18390                            return Ok(Navigated::No);
18391                        };
18392                        workspace
18393                            .update_in(cx, |workspace, window, cx| {
18394                                workspace.open_resolved_path(path, window, cx)
18395                            })?
18396                            .await?;
18397                        Ok(Navigated::Yes)
18398                    }
18399                    None => Ok(Navigated::No),
18400                }
18401            } else {
18402                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18403
18404                editor.update_in(cx, |editor, window, cx| {
18405                    let target_ranges = target_ranges
18406                        .into_iter()
18407                        .map(|r| editor.range_for_match(&r))
18408                        .map(collapse_multiline_range)
18409                        .collect::<Vec<_>>();
18410                    if !split
18411                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18412                    {
18413                        let multibuffer = editor.buffer.read(cx);
18414                        let target_ranges = target_ranges
18415                            .into_iter()
18416                            .filter_map(|r| {
18417                                let start = multibuffer.buffer_point_to_anchor(
18418                                    &target_buffer,
18419                                    r.start,
18420                                    cx,
18421                                )?;
18422                                let end = multibuffer.buffer_point_to_anchor(
18423                                    &target_buffer,
18424                                    r.end,
18425                                    cx,
18426                                )?;
18427                                Some(start..end)
18428                            })
18429                            .collect::<Vec<_>>();
18430                        if target_ranges.is_empty() {
18431                            return Navigated::No;
18432                        }
18433
18434                        editor.change_selections(
18435                            SelectionEffects::default().nav_history(true),
18436                            window,
18437                            cx,
18438                            |s| s.select_anchor_ranges(target_ranges),
18439                        );
18440
18441                        let target =
18442                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18443                        if let Some(mut nav_history) = editor.nav_history.clone() {
18444                            nav_history.push_tag(origin, target);
18445                        }
18446                    } else {
18447                        let Some(workspace) = workspace else {
18448                            return Navigated::No;
18449                        };
18450                        let pane = workspace.read(cx).active_pane().clone();
18451                        window.defer(cx, move |window, cx| {
18452                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18453                                workspace.update(cx, |workspace, cx| {
18454                                    let pane = if split {
18455                                        workspace.adjacent_pane(window, cx)
18456                                    } else {
18457                                        workspace.active_pane().clone()
18458                                    };
18459
18460                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18461                                    let keep_old_preview = preview_tabs_settings
18462                                        .enable_keep_preview_on_code_navigation;
18463                                    let allow_new_preview = preview_tabs_settings
18464                                        .enable_preview_file_from_code_navigation;
18465
18466                                    let editor = workspace.open_project_item(
18467                                        pane.clone(),
18468                                        target_buffer.clone(),
18469                                        true,
18470                                        true,
18471                                        keep_old_preview,
18472                                        allow_new_preview,
18473                                        window,
18474                                        cx,
18475                                    );
18476                                    (editor, pane)
18477                                });
18478                            // We create our own nav history instead of using
18479                            // `target_editor.nav_history` because `nav_history`
18480                            // seems to be populated asynchronously when an item
18481                            // is added to a pane
18482                            let mut nav_history = target_pane
18483                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18484                            target_editor.update(cx, |target_editor, cx| {
18485                                // When selecting a definition in a different buffer, disable the nav history
18486                                // to avoid creating a history entry at the previous cursor location.
18487                                pane.update(cx, |pane, _| pane.disable_history());
18488
18489                                let multibuffer = target_editor.buffer.read(cx);
18490                                let Some(target_buffer) = multibuffer.as_singleton() else {
18491                                    return Navigated::No;
18492                                };
18493                                let target_ranges = target_ranges
18494                                    .into_iter()
18495                                    .filter_map(|r| {
18496                                        let start = multibuffer.buffer_point_to_anchor(
18497                                            &target_buffer,
18498                                            r.start,
18499                                            cx,
18500                                        )?;
18501                                        let end = multibuffer.buffer_point_to_anchor(
18502                                            &target_buffer,
18503                                            r.end,
18504                                            cx,
18505                                        )?;
18506                                        Some(start..end)
18507                                    })
18508                                    .collect::<Vec<_>>();
18509                                if target_ranges.is_empty() {
18510                                    return Navigated::No;
18511                                }
18512
18513                                target_editor.change_selections(
18514                                    SelectionEffects::default().nav_history(true),
18515                                    window,
18516                                    cx,
18517                                    |s| s.select_anchor_ranges(target_ranges),
18518                                );
18519
18520                                let nav_data = target_editor.navigation_data(
18521                                    target_editor.selections.newest_anchor().head(),
18522                                    cx,
18523                                );
18524                                let target =
18525                                    Some(nav_history.navigation_entry(Some(
18526                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18527                                    )));
18528                                nav_history.push_tag(origin, target);
18529                                pane.update(cx, |pane, _| pane.enable_history());
18530                                Navigated::Yes
18531                            });
18532                        });
18533                    }
18534                    Navigated::Yes
18535                })
18536            }
18537        })
18538    }
18539
18540    fn compute_target_location(
18541        &self,
18542        lsp_location: lsp::Location,
18543        server_id: LanguageServerId,
18544        window: &mut Window,
18545        cx: &mut Context<Self>,
18546    ) -> Task<anyhow::Result<Option<Location>>> {
18547        let Some(project) = self.project.clone() else {
18548            return Task::ready(Ok(None));
18549        };
18550
18551        cx.spawn_in(window, async move |editor, cx| {
18552            let location_task = editor.update(cx, |_, cx| {
18553                project.update(cx, |project, cx| {
18554                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18555                })
18556            })?;
18557            let location = Some({
18558                let target_buffer_handle = location_task.await.context("open local buffer")?;
18559                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18560                    let target_start = target_buffer
18561                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18562                    let target_end = target_buffer
18563                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18564                    target_buffer.anchor_after(target_start)
18565                        ..target_buffer.anchor_before(target_end)
18566                });
18567                Location {
18568                    buffer: target_buffer_handle,
18569                    range,
18570                }
18571            });
18572            Ok(location)
18573        })
18574    }
18575
18576    fn go_to_next_reference(
18577        &mut self,
18578        _: &GoToNextReference,
18579        window: &mut Window,
18580        cx: &mut Context<Self>,
18581    ) {
18582        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18583        if let Some(task) = task {
18584            task.detach();
18585        };
18586    }
18587
18588    fn go_to_prev_reference(
18589        &mut self,
18590        _: &GoToPreviousReference,
18591        window: &mut Window,
18592        cx: &mut Context<Self>,
18593    ) {
18594        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18595        if let Some(task) = task {
18596            task.detach();
18597        };
18598    }
18599
18600    fn go_to_symbol_by_offset(
18601        &mut self,
18602        window: &mut Window,
18603        cx: &mut Context<Self>,
18604        offset: i8,
18605    ) -> Task<Result<()>> {
18606        let editor_snapshot = self.snapshot(window, cx);
18607
18608        // We don't care about multi-buffer symbols
18609        if !editor_snapshot.is_singleton() {
18610            return Task::ready(Ok(()));
18611        }
18612
18613        let cursor_offset = self
18614            .selections
18615            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18616            .head();
18617
18618        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18619            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18620                let buffer = ed.buffer.read(cx).as_singleton()?;
18621                Some(buffer.read(cx).remote_id())
18622            }) else {
18623                return Ok(());
18624            };
18625
18626            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18627            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18628
18629            let multi_snapshot = editor_snapshot.buffer();
18630            let buffer_range = |range: &Range<_>| {
18631                Some(
18632                    multi_snapshot
18633                        .buffer_anchor_range_to_anchor_range(range.clone())?
18634                        .to_offset(multi_snapshot),
18635                )
18636            };
18637
18638            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18639                let current_idx = outline_items
18640                    .iter()
18641                    .enumerate()
18642                    .filter_map(|(idx, item)| {
18643                        // Find the closest outline item by distance between outline text and cursor location
18644                        let source_range = buffer_range(&item.source_range_for_text)?;
18645                        let distance_to_closest_endpoint = cmp::min(
18646                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18647                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18648                        );
18649
18650                        let item_towards_offset =
18651                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18652                                == (offset as isize).signum();
18653
18654                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18655
18656                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18657                        // we should not already be within the outline's source range. We then pick the closest outline
18658                        // item.
18659                        (item_towards_offset && !source_range_contains_cursor)
18660                            .then_some((distance_to_closest_endpoint, idx))
18661                    })
18662                    .min()
18663                    .map(|(_, idx)| idx);
18664
18665                let Some(idx) = current_idx else {
18666                    return;
18667                };
18668
18669                let Some(range) = buffer_range(&outline_items[idx].source_range_for_text) else {
18670                    return;
18671                };
18672                let selection = [range.start..range.start];
18673
18674                let _ = editor
18675                    .update(acx, |editor, ecx| {
18676                        editor.change_selections(
18677                            SelectionEffects::scroll(Autoscroll::newest()),
18678                            window,
18679                            ecx,
18680                            |s| s.select_ranges(selection),
18681                        );
18682                    })
18683                    .ok();
18684            })?;
18685
18686            Ok(())
18687        })
18688    }
18689
18690    fn go_to_next_symbol(
18691        &mut self,
18692        _: &GoToNextSymbol,
18693        window: &mut Window,
18694        cx: &mut Context<Self>,
18695    ) {
18696        self.go_to_symbol_by_offset(window, cx, 1).detach();
18697    }
18698
18699    fn go_to_previous_symbol(
18700        &mut self,
18701        _: &GoToPreviousSymbol,
18702        window: &mut Window,
18703        cx: &mut Context<Self>,
18704    ) {
18705        self.go_to_symbol_by_offset(window, cx, -1).detach();
18706    }
18707
18708    pub fn go_to_reference_before_or_after_position(
18709        &mut self,
18710        direction: Direction,
18711        count: usize,
18712        window: &mut Window,
18713        cx: &mut Context<Self>,
18714    ) -> Option<Task<Result<()>>> {
18715        let selection = self.selections.newest_anchor();
18716        let head = selection.head();
18717
18718        let multi_buffer = self.buffer.read(cx);
18719
18720        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18721        let workspace = self.workspace()?;
18722        let project = workspace.read(cx).project().clone();
18723        let references =
18724            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18725        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18726            let Some(locations) = references.await? else {
18727                return Ok(());
18728            };
18729
18730            if locations.is_empty() {
18731                // totally normal - the cursor may be on something which is not
18732                // a symbol (e.g. a keyword)
18733                log::info!("no references found under cursor");
18734                return Ok(());
18735            }
18736
18737            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18738
18739            let (locations, current_location_index) =
18740                multi_buffer.update(cx, |multi_buffer, cx| {
18741                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18742                    let mut locations = locations
18743                        .into_iter()
18744                        .filter_map(|loc| {
18745                            let start = multi_buffer_snapshot.anchor_in_excerpt(loc.range.start)?;
18746                            let end = multi_buffer_snapshot.anchor_in_excerpt(loc.range.end)?;
18747                            Some(start..end)
18748                        })
18749                        .collect::<Vec<_>>();
18750                    // There is an O(n) implementation, but given this list will be
18751                    // small (usually <100 items), the extra O(log(n)) factor isn't
18752                    // worth the (surprisingly large amount of) extra complexity.
18753                    locations
18754                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18755
18756                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18757
18758                    let current_location_index = locations.iter().position(|loc| {
18759                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18760                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18761                    });
18762
18763                    (locations, current_location_index)
18764                });
18765
18766            let Some(current_location_index) = current_location_index else {
18767                // This indicates something has gone wrong, because we already
18768                // handle the "no references" case above
18769                log::error!(
18770                    "failed to find current reference under cursor. Total references: {}",
18771                    locations.len()
18772                );
18773                return Ok(());
18774            };
18775
18776            let destination_location_index = match direction {
18777                Direction::Next => (current_location_index + count) % locations.len(),
18778                Direction::Prev => {
18779                    (current_location_index + locations.len() - count % locations.len())
18780                        % locations.len()
18781                }
18782            };
18783
18784            // TODO(cameron): is this needed?
18785            // the thinking is to avoid "jumping to the current location" (avoid
18786            // polluting "jumplist" in vim terms)
18787            if current_location_index == destination_location_index {
18788                return Ok(());
18789            }
18790
18791            let Range { start, end } = locations[destination_location_index];
18792
18793            editor.update_in(cx, |editor, window, cx| {
18794                let effects = SelectionEffects::default();
18795
18796                editor.unfold_ranges(&[start..end], false, false, cx);
18797                editor.change_selections(effects, window, cx, |s| {
18798                    s.select_ranges([start..start]);
18799                });
18800            })?;
18801
18802            Ok(())
18803        }))
18804    }
18805
18806    pub fn find_all_references(
18807        &mut self,
18808        action: &FindAllReferences,
18809        window: &mut Window,
18810        cx: &mut Context<Self>,
18811    ) -> Option<Task<Result<Navigated>>> {
18812        let always_open_multibuffer = action.always_open_multibuffer;
18813        let selection = self.selections.newest_anchor();
18814        let multi_buffer = self.buffer.read(cx);
18815        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18816        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18817        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18818        let head = selection_offset.head();
18819
18820        let head_anchor = multi_buffer_snapshot.anchor_at(
18821            head,
18822            if head < selection_offset.tail() {
18823                Bias::Right
18824            } else {
18825                Bias::Left
18826            },
18827        );
18828
18829        match self
18830            .find_all_references_task_sources
18831            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18832        {
18833            Ok(_) => {
18834                log::info!(
18835                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18836                );
18837                return None;
18838            }
18839            Err(i) => {
18840                self.find_all_references_task_sources.insert(i, head_anchor);
18841            }
18842        }
18843
18844        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18845        let workspace = self.workspace()?;
18846        let project = workspace.read(cx).project().clone();
18847        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18848        Some(cx.spawn_in(window, async move |editor, cx| {
18849            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18850                if let Ok(i) = editor
18851                    .find_all_references_task_sources
18852                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18853                {
18854                    editor.find_all_references_task_sources.remove(i);
18855                }
18856            });
18857
18858            let Some(locations) = references.await? else {
18859                return anyhow::Ok(Navigated::No);
18860            };
18861            let mut locations = cx.update(|_, cx| {
18862                locations
18863                    .into_iter()
18864                    .map(|location| {
18865                        let buffer = location.buffer.read(cx);
18866                        (location.buffer, location.range.to_point(buffer))
18867                    })
18868                    // if special-casing the single-match case, remove ranges
18869                    // that intersect current selection
18870                    .filter(|(location_buffer, location)| {
18871                        if always_open_multibuffer || &buffer != location_buffer {
18872                            return true;
18873                        }
18874
18875                        !location.contains_inclusive(&selection_point.range())
18876                    })
18877                    .into_group_map()
18878            })?;
18879            if locations.is_empty() {
18880                return anyhow::Ok(Navigated::No);
18881            }
18882            for ranges in locations.values_mut() {
18883                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18884                ranges.dedup();
18885            }
18886            let mut num_locations = 0;
18887            for ranges in locations.values_mut() {
18888                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18889                ranges.dedup();
18890                num_locations += ranges.len();
18891            }
18892
18893            if num_locations == 1 && !always_open_multibuffer {
18894                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18895                let target_range = target_ranges.first().unwrap().clone();
18896
18897                return editor.update_in(cx, |editor, window, cx| {
18898                    let range = target_range.to_point(target_buffer.read(cx));
18899                    let range = editor.range_for_match(&range);
18900                    let range = range.start..range.start;
18901
18902                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18903                        editor.go_to_singleton_buffer_range(range, window, cx);
18904                    } else {
18905                        let pane = workspace.read(cx).active_pane().clone();
18906                        window.defer(cx, move |window, cx| {
18907                            let target_editor: Entity<Self> =
18908                                workspace.update(cx, |workspace, cx| {
18909                                    let pane = workspace.active_pane().clone();
18910
18911                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18912                                    let keep_old_preview = preview_tabs_settings
18913                                        .enable_keep_preview_on_code_navigation;
18914                                    let allow_new_preview = preview_tabs_settings
18915                                        .enable_preview_file_from_code_navigation;
18916
18917                                    workspace.open_project_item(
18918                                        pane,
18919                                        target_buffer.clone(),
18920                                        true,
18921                                        true,
18922                                        keep_old_preview,
18923                                        allow_new_preview,
18924                                        window,
18925                                        cx,
18926                                    )
18927                                });
18928                            target_editor.update(cx, |target_editor, cx| {
18929                                // When selecting a definition in a different buffer, disable the nav history
18930                                // to avoid creating a history entry at the previous cursor location.
18931                                pane.update(cx, |pane, _| pane.disable_history());
18932                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18933                                pane.update(cx, |pane, _| pane.enable_history());
18934                            });
18935                        });
18936                    }
18937                    Navigated::No
18938                });
18939            }
18940
18941            workspace.update_in(cx, |workspace, window, cx| {
18942                let target = locations
18943                    .iter()
18944                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18945                    .map(|(buffer, location)| {
18946                        buffer
18947                            .read(cx)
18948                            .text_for_range(location.clone())
18949                            .collect::<String>()
18950                    })
18951                    .filter(|text| !text.contains('\n'))
18952                    .unique()
18953                    .take(3)
18954                    .join(", ");
18955                let title = if target.is_empty() {
18956                    "References".to_owned()
18957                } else {
18958                    format!("References to {target}")
18959                };
18960                let allow_preview = PreviewTabsSettings::get_global(cx)
18961                    .enable_preview_multibuffer_from_code_navigation;
18962                Self::open_locations_in_multibuffer(
18963                    workspace,
18964                    locations,
18965                    title,
18966                    false,
18967                    allow_preview,
18968                    MultibufferSelectionMode::First,
18969                    window,
18970                    cx,
18971                );
18972                Navigated::Yes
18973            })
18974        }))
18975    }
18976
18977    /// Opens a multibuffer with the given project locations in it.
18978    pub fn open_locations_in_multibuffer(
18979        workspace: &mut Workspace,
18980        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18981        title: String,
18982        split: bool,
18983        allow_preview: bool,
18984        multibuffer_selection_mode: MultibufferSelectionMode,
18985        window: &mut Window,
18986        cx: &mut Context<Workspace>,
18987    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18988        if locations.is_empty() {
18989            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18990            return None;
18991        }
18992
18993        let capability = workspace.project().read(cx).capability();
18994        let mut ranges = <Vec<Range<Anchor>>>::new();
18995
18996        // a key to find existing multibuffer editors with the same set of locations
18997        // to prevent us from opening more and more multibuffer tabs for searches and the like
18998        let mut key = (title.clone(), vec![]);
18999        let excerpt_buffer = cx.new(|cx| {
19000            let key = &mut key.1;
19001            let mut multibuffer = MultiBuffer::new(capability);
19002            for (buffer, mut ranges_for_buffer) in locations {
19003                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
19004                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
19005                multibuffer.set_excerpts_for_path(
19006                    PathKey::for_buffer(&buffer, cx),
19007                    buffer.clone(),
19008                    ranges_for_buffer.clone(),
19009                    multibuffer_context_lines(cx),
19010                    cx,
19011                );
19012                let snapshot = multibuffer.snapshot(cx);
19013                let buffer_snapshot = buffer.read(cx).snapshot();
19014                ranges.extend(ranges_for_buffer.into_iter().filter_map(|range| {
19015                    let text_range = buffer_snapshot.anchor_range_inside(range);
19016                    let start = snapshot.anchor_in_buffer(text_range.start)?;
19017                    let end = snapshot.anchor_in_buffer(text_range.end)?;
19018                    Some(start..end)
19019                }))
19020            }
19021
19022            multibuffer.with_title(title)
19023        });
19024        let existing = workspace.active_pane().update(cx, |pane, cx| {
19025            pane.items()
19026                .filter_map(|item| item.downcast::<Editor>())
19027                .find(|editor| {
19028                    editor
19029                        .read(cx)
19030                        .lookup_key
19031                        .as_ref()
19032                        .and_then(|it| {
19033                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
19034                        })
19035                        .is_some_and(|it| *it == key)
19036                })
19037        });
19038        let was_existing = existing.is_some();
19039        let editor = existing.unwrap_or_else(|| {
19040            cx.new(|cx| {
19041                let mut editor = Editor::for_multibuffer(
19042                    excerpt_buffer,
19043                    Some(workspace.project().clone()),
19044                    window,
19045                    cx,
19046                );
19047                editor.lookup_key = Some(Box::new(key));
19048                editor
19049            })
19050        });
19051        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
19052            MultibufferSelectionMode::First => {
19053                if let Some(first_range) = ranges.first() {
19054                    editor.change_selections(
19055                        SelectionEffects::no_scroll(),
19056                        window,
19057                        cx,
19058                        |selections| {
19059                            selections.clear_disjoint();
19060                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
19061                        },
19062                    );
19063                }
19064                editor.highlight_background(
19065                    HighlightKey::Editor,
19066                    &ranges,
19067                    |_, theme| theme.colors().editor_highlighted_line_background,
19068                    cx,
19069                );
19070            }
19071            MultibufferSelectionMode::All => {
19072                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
19073                    selections.clear_disjoint();
19074                    selections.select_anchor_ranges(ranges);
19075                });
19076            }
19077        });
19078
19079        let item = Box::new(editor.clone());
19080
19081        let pane = if split {
19082            workspace.adjacent_pane(window, cx)
19083        } else {
19084            workspace.active_pane().clone()
19085        };
19086        let activate_pane = split;
19087
19088        let mut destination_index = None;
19089        pane.update(cx, |pane, cx| {
19090            if allow_preview && !was_existing {
19091                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
19092            }
19093            if was_existing && !allow_preview {
19094                pane.unpreview_item_if_preview(item.item_id());
19095            }
19096            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19097        });
19098
19099        Some((editor, pane))
19100    }
19101
19102    pub fn rename(
19103        &mut self,
19104        _: &Rename,
19105        window: &mut Window,
19106        cx: &mut Context<Self>,
19107    ) -> Option<Task<Result<()>>> {
19108        use language::ToOffset as _;
19109
19110        let provider = self.semantics_provider.clone()?;
19111        let selection = self.selections.newest_anchor().clone();
19112        let (cursor_buffer, cursor_buffer_position) = self
19113            .buffer
19114            .read(cx)
19115            .text_anchor_for_position(selection.head(), cx)?;
19116        let (tail_buffer, cursor_buffer_position_end) = self
19117            .buffer
19118            .read(cx)
19119            .text_anchor_for_position(selection.tail(), cx)?;
19120        if tail_buffer != cursor_buffer {
19121            return None;
19122        }
19123
19124        let snapshot = cursor_buffer.read(cx).snapshot();
19125        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19126        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19127        let prepare_rename = provider.range_for_rename(&cursor_buffer, cursor_buffer_position, cx);
19128        drop(snapshot);
19129
19130        Some(cx.spawn_in(window, async move |this, cx| {
19131            let rename_range = prepare_rename.await?;
19132            if let Some(rename_range) = rename_range {
19133                this.update_in(cx, |this, window, cx| {
19134                    let snapshot = cursor_buffer.read(cx).snapshot();
19135                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19136                    let cursor_offset_in_rename_range =
19137                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19138                    let cursor_offset_in_rename_range_end =
19139                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19140
19141                    this.take_rename(false, window, cx);
19142                    let buffer = this.buffer.read(cx).read(cx);
19143                    let cursor_offset = selection.head().to_offset(&buffer);
19144                    let rename_start =
19145                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19146                    let rename_end = rename_start + rename_buffer_range.len();
19147                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19148                    let mut old_highlight_id = None;
19149                    let old_name: Arc<str> = buffer
19150                        .chunks(rename_start..rename_end, true)
19151                        .map(|chunk| {
19152                            if old_highlight_id.is_none() {
19153                                old_highlight_id = chunk.syntax_highlight_id;
19154                            }
19155                            chunk.text
19156                        })
19157                        .collect::<String>()
19158                        .into();
19159
19160                    drop(buffer);
19161
19162                    // Position the selection in the rename editor so that it matches the current selection.
19163                    this.show_local_selections = false;
19164                    let rename_editor = cx.new(|cx| {
19165                        let mut editor = Editor::single_line(window, cx);
19166                        editor.buffer.update(cx, |buffer, cx| {
19167                            buffer.edit(
19168                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19169                                None,
19170                                cx,
19171                            )
19172                        });
19173                        let cursor_offset_in_rename_range =
19174                            MultiBufferOffset(cursor_offset_in_rename_range);
19175                        let cursor_offset_in_rename_range_end =
19176                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19177                        let rename_selection_range = match cursor_offset_in_rename_range
19178                            .cmp(&cursor_offset_in_rename_range_end)
19179                        {
19180                            Ordering::Equal => {
19181                                editor.select_all(&SelectAll, window, cx);
19182                                return editor;
19183                            }
19184                            Ordering::Less => {
19185                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19186                            }
19187                            Ordering::Greater => {
19188                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19189                            }
19190                        };
19191                        if rename_selection_range.end.0 > old_name.len() {
19192                            editor.select_all(&SelectAll, window, cx);
19193                        } else {
19194                            editor.change_selections(Default::default(), window, cx, |s| {
19195                                s.select_ranges([rename_selection_range]);
19196                            });
19197                        }
19198                        editor
19199                    });
19200                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19201                        if e == &EditorEvent::Focused {
19202                            cx.emit(EditorEvent::FocusedIn)
19203                        }
19204                    })
19205                    .detach();
19206
19207                    let write_highlights =
19208                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19209                    let read_highlights =
19210                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19211                    let ranges = write_highlights
19212                        .iter()
19213                        .flat_map(|(_, ranges)| ranges.iter())
19214                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19215                        .cloned()
19216                        .collect();
19217
19218                    this.highlight_text(
19219                        HighlightKey::Rename,
19220                        ranges,
19221                        HighlightStyle {
19222                            fade_out: Some(0.6),
19223                            ..Default::default()
19224                        },
19225                        cx,
19226                    );
19227                    let rename_focus_handle = rename_editor.focus_handle(cx);
19228                    window.focus(&rename_focus_handle, cx);
19229                    let block_id = this.insert_blocks(
19230                        [BlockProperties {
19231                            style: BlockStyle::Flex,
19232                            placement: BlockPlacement::Below(range.start),
19233                            height: Some(1),
19234                            render: Arc::new({
19235                                let rename_editor = rename_editor.clone();
19236                                move |cx: &mut BlockContext| {
19237                                    let mut text_style = cx.editor_style.text.clone();
19238                                    if let Some(highlight_style) = old_highlight_id
19239                                        .and_then(|h| cx.editor_style.syntax.get(h).cloned())
19240                                    {
19241                                        text_style = text_style.highlight(highlight_style);
19242                                    }
19243                                    div()
19244                                        .block_mouse_except_scroll()
19245                                        .pl(cx.anchor_x)
19246                                        .child(EditorElement::new(
19247                                            &rename_editor,
19248                                            EditorStyle {
19249                                                background: cx.theme().system().transparent,
19250                                                local_player: cx.editor_style.local_player,
19251                                                text: text_style,
19252                                                scrollbar_width: cx.editor_style.scrollbar_width,
19253                                                syntax: cx.editor_style.syntax.clone(),
19254                                                status: cx.editor_style.status.clone(),
19255                                                inlay_hints_style: HighlightStyle {
19256                                                    font_weight: Some(FontWeight::BOLD),
19257                                                    ..make_inlay_hints_style(cx.app)
19258                                                },
19259                                                edit_prediction_styles: make_suggestion_styles(
19260                                                    cx.app,
19261                                                ),
19262                                                ..EditorStyle::default()
19263                                            },
19264                                        ))
19265                                        .into_any_element()
19266                                }
19267                            }),
19268                            priority: 0,
19269                        }],
19270                        Some(Autoscroll::fit()),
19271                        cx,
19272                    )[0];
19273                    this.pending_rename = Some(RenameState {
19274                        range,
19275                        old_name,
19276                        editor: rename_editor,
19277                        block_id,
19278                    });
19279                })?;
19280            }
19281
19282            Ok(())
19283        }))
19284    }
19285
19286    pub fn confirm_rename(
19287        &mut self,
19288        _: &ConfirmRename,
19289        window: &mut Window,
19290        cx: &mut Context<Self>,
19291    ) -> Option<Task<Result<()>>> {
19292        let rename = self.take_rename(false, window, cx)?;
19293        let workspace = self.workspace()?.downgrade();
19294        let (buffer, start) = self
19295            .buffer
19296            .read(cx)
19297            .text_anchor_for_position(rename.range.start, cx)?;
19298        let (end_buffer, _) = self
19299            .buffer
19300            .read(cx)
19301            .text_anchor_for_position(rename.range.end, cx)?;
19302        if buffer != end_buffer {
19303            return None;
19304        }
19305
19306        let old_name = rename.old_name;
19307        let new_name = rename.editor.read(cx).text(cx);
19308
19309        let rename = self.semantics_provider.as_ref()?.perform_rename(
19310            &buffer,
19311            start,
19312            new_name.clone(),
19313            cx,
19314        )?;
19315
19316        Some(cx.spawn_in(window, async move |editor, cx| {
19317            let project_transaction = rename.await?;
19318            Self::open_project_transaction(
19319                &editor,
19320                workspace,
19321                project_transaction,
19322                format!("Rename: {}{}", old_name, new_name),
19323                cx,
19324            )
19325            .await?;
19326
19327            editor.update(cx, |editor, cx| {
19328                editor.refresh_document_highlights(cx);
19329            })?;
19330            Ok(())
19331        }))
19332    }
19333
19334    fn take_rename(
19335        &mut self,
19336        moving_cursor: bool,
19337        window: &mut Window,
19338        cx: &mut Context<Self>,
19339    ) -> Option<RenameState> {
19340        let rename = self.pending_rename.take()?;
19341        if rename.editor.focus_handle(cx).is_focused(window) {
19342            window.focus(&self.focus_handle, cx);
19343        }
19344
19345        self.remove_blocks(
19346            [rename.block_id].into_iter().collect(),
19347            Some(Autoscroll::fit()),
19348            cx,
19349        );
19350        self.clear_highlights(HighlightKey::Rename, cx);
19351        self.show_local_selections = true;
19352
19353        if moving_cursor {
19354            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19355                editor
19356                    .selections
19357                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19358                    .head()
19359            });
19360
19361            // Update the selection to match the position of the selection inside
19362            // the rename editor.
19363            let snapshot = self.buffer.read(cx).read(cx);
19364            let rename_range = rename.range.to_offset(&snapshot);
19365            let cursor_in_editor = snapshot
19366                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19367                .min(rename_range.end);
19368            drop(snapshot);
19369
19370            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19371                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19372            });
19373        } else {
19374            self.refresh_document_highlights(cx);
19375        }
19376
19377        Some(rename)
19378    }
19379
19380    pub fn pending_rename(&self) -> Option<&RenameState> {
19381        self.pending_rename.as_ref()
19382    }
19383
19384    fn format(
19385        &mut self,
19386        _: &Format,
19387        window: &mut Window,
19388        cx: &mut Context<Self>,
19389    ) -> Option<Task<Result<()>>> {
19390        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19391
19392        let project = match &self.project {
19393            Some(project) => project.clone(),
19394            None => return None,
19395        };
19396
19397        Some(self.perform_format(
19398            project,
19399            FormatTrigger::Manual,
19400            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19401            window,
19402            cx,
19403        ))
19404    }
19405
19406    fn format_selections(
19407        &mut self,
19408        _: &FormatSelections,
19409        window: &mut Window,
19410        cx: &mut Context<Self>,
19411    ) -> Option<Task<Result<()>>> {
19412        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19413
19414        let project = match &self.project {
19415            Some(project) => project.clone(),
19416            None => return None,
19417        };
19418
19419        let ranges = self
19420            .selections
19421            .all_adjusted(&self.display_snapshot(cx))
19422            .into_iter()
19423            .map(|selection| selection.range())
19424            .collect_vec();
19425
19426        Some(self.perform_format(
19427            project,
19428            FormatTrigger::Manual,
19429            FormatTarget::Ranges(ranges),
19430            window,
19431            cx,
19432        ))
19433    }
19434
19435    fn perform_format(
19436        &mut self,
19437        project: Entity<Project>,
19438        trigger: FormatTrigger,
19439        target: FormatTarget,
19440        window: &mut Window,
19441        cx: &mut Context<Self>,
19442    ) -> Task<Result<()>> {
19443        let buffer = self.buffer.clone();
19444        let (buffers, target) = match target {
19445            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19446            FormatTarget::Ranges(selection_ranges) => {
19447                let multi_buffer = buffer.read(cx);
19448                let snapshot = multi_buffer.read(cx);
19449                let mut buffers = HashSet::default();
19450                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19451                    BTreeMap::new();
19452                for selection_range in selection_ranges {
19453                    for (buffer_snapshot, buffer_range, _) in
19454                        snapshot.range_to_buffer_ranges(selection_range.start..selection_range.end)
19455                    {
19456                        let buffer_id = buffer_snapshot.remote_id();
19457                        let start = buffer_snapshot.anchor_before(buffer_range.start);
19458                        let end = buffer_snapshot.anchor_after(buffer_range.end);
19459                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19460                        buffer_id_to_ranges
19461                            .entry(buffer_id)
19462                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19463                            .or_insert_with(|| vec![start..end]);
19464                    }
19465                }
19466                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19467            }
19468        };
19469
19470        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19471        let selections_prev = transaction_id_prev
19472            .and_then(|transaction_id_prev| {
19473                // default to selections as they were after the last edit, if we have them,
19474                // instead of how they are now.
19475                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19476                // will take you back to where you made the last edit, instead of staying where you scrolled
19477                self.selection_history
19478                    .transaction(transaction_id_prev)
19479                    .map(|t| t.0.clone())
19480            })
19481            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19482
19483        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19484        let format = project.update(cx, |project, cx| {
19485            project.format(buffers, target, true, trigger, cx)
19486        });
19487
19488        cx.spawn_in(window, async move |editor, cx| {
19489            let transaction = futures::select_biased! {
19490                transaction = format.log_err().fuse() => transaction,
19491                () = timeout => {
19492                    log::warn!("timed out waiting for formatting");
19493                    None
19494                }
19495            };
19496
19497            buffer.update(cx, |buffer, cx| {
19498                if let Some(transaction) = transaction
19499                    && !buffer.is_singleton()
19500                {
19501                    buffer.push_transaction(&transaction.0, cx);
19502                }
19503                cx.notify();
19504            });
19505
19506            if let Some(transaction_id_now) =
19507                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19508            {
19509                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19510                if has_new_transaction {
19511                    editor
19512                        .update(cx, |editor, _| {
19513                            editor
19514                                .selection_history
19515                                .insert_transaction(transaction_id_now, selections_prev);
19516                        })
19517                        .ok();
19518                }
19519            }
19520
19521            Ok(())
19522        })
19523    }
19524
19525    fn organize_imports(
19526        &mut self,
19527        _: &OrganizeImports,
19528        window: &mut Window,
19529        cx: &mut Context<Self>,
19530    ) -> Option<Task<Result<()>>> {
19531        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19532        let project = match &self.project {
19533            Some(project) => project.clone(),
19534            None => return None,
19535        };
19536        Some(self.perform_code_action_kind(
19537            project,
19538            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19539            window,
19540            cx,
19541        ))
19542    }
19543
19544    fn perform_code_action_kind(
19545        &mut self,
19546        project: Entity<Project>,
19547        kind: CodeActionKind,
19548        window: &mut Window,
19549        cx: &mut Context<Self>,
19550    ) -> Task<Result<()>> {
19551        let buffer = self.buffer.clone();
19552        let buffers = buffer.read(cx).all_buffers();
19553        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19554        let apply_action = project.update(cx, |project, cx| {
19555            project.apply_code_action_kind(buffers, kind, true, cx)
19556        });
19557        cx.spawn_in(window, async move |_, cx| {
19558            let transaction = futures::select_biased! {
19559                () = timeout => {
19560                    log::warn!("timed out waiting for executing code action");
19561                    None
19562                }
19563                transaction = apply_action.log_err().fuse() => transaction,
19564            };
19565            buffer.update(cx, |buffer, cx| {
19566                // check if we need this
19567                if let Some(transaction) = transaction
19568                    && !buffer.is_singleton()
19569                {
19570                    buffer.push_transaction(&transaction.0, cx);
19571                }
19572                cx.notify();
19573            });
19574            Ok(())
19575        })
19576    }
19577
19578    pub fn restart_language_server(
19579        &mut self,
19580        _: &RestartLanguageServer,
19581        _: &mut Window,
19582        cx: &mut Context<Self>,
19583    ) {
19584        if let Some(project) = self.project.clone() {
19585            self.buffer.update(cx, |multi_buffer, cx| {
19586                project.update(cx, |project, cx| {
19587                    project.restart_language_servers_for_buffers(
19588                        multi_buffer.all_buffers().into_iter().collect(),
19589                        HashSet::default(),
19590                        cx,
19591                    );
19592                });
19593            })
19594        }
19595    }
19596
19597    pub fn stop_language_server(
19598        &mut self,
19599        _: &StopLanguageServer,
19600        _: &mut Window,
19601        cx: &mut Context<Self>,
19602    ) {
19603        if let Some(project) = self.project.clone() {
19604            self.buffer.update(cx, |multi_buffer, cx| {
19605                project.update(cx, |project, cx| {
19606                    project.stop_language_servers_for_buffers(
19607                        multi_buffer.all_buffers().into_iter().collect(),
19608                        HashSet::default(),
19609                        cx,
19610                    );
19611                });
19612            });
19613        }
19614    }
19615
19616    fn cancel_language_server_work(
19617        workspace: &mut Workspace,
19618        _: &actions::CancelLanguageServerWork,
19619        _: &mut Window,
19620        cx: &mut Context<Workspace>,
19621    ) {
19622        let project = workspace.project();
19623        let buffers = workspace
19624            .active_item(cx)
19625            .and_then(|item| item.act_as::<Editor>(cx))
19626            .map_or(HashSet::default(), |editor| {
19627                editor.read(cx).buffer.read(cx).all_buffers()
19628            });
19629        project.update(cx, |project, cx| {
19630            project.cancel_language_server_work_for_buffers(buffers, cx);
19631        });
19632    }
19633
19634    fn show_character_palette(
19635        &mut self,
19636        _: &ShowCharacterPalette,
19637        window: &mut Window,
19638        _: &mut Context<Self>,
19639    ) {
19640        window.show_character_palette();
19641    }
19642
19643    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19644        if !self.diagnostics_enabled() {
19645            return;
19646        }
19647
19648        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19649            let buffer = self.buffer.read(cx).snapshot(cx);
19650            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19651            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19652            let is_valid = buffer
19653                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19654                .any(|entry| {
19655                    entry.diagnostic.is_primary
19656                        && !entry.range.is_empty()
19657                        && entry.range.start == primary_range_start
19658                        && entry.diagnostic.message == active_diagnostics.active_message
19659                });
19660
19661            if !is_valid {
19662                self.dismiss_diagnostics(cx);
19663            }
19664        }
19665    }
19666
19667    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19668        match &self.active_diagnostics {
19669            ActiveDiagnostic::Group(group) => Some(group),
19670            _ => None,
19671        }
19672    }
19673
19674    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19675        if !self.diagnostics_enabled() {
19676            return;
19677        }
19678        self.dismiss_diagnostics(cx);
19679        self.active_diagnostics = ActiveDiagnostic::All;
19680    }
19681
19682    fn activate_diagnostics(
19683        &mut self,
19684        buffer_id: BufferId,
19685        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19686        window: &mut Window,
19687        cx: &mut Context<Self>,
19688    ) {
19689        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19690            return;
19691        }
19692        self.dismiss_diagnostics(cx);
19693        let snapshot = self.snapshot(window, cx);
19694        let buffer = self.buffer.read(cx).snapshot(cx);
19695        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19696            return;
19697        };
19698
19699        let diagnostic_group = buffer
19700            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19701            .collect::<Vec<_>>();
19702
19703        let language_registry = self
19704            .project()
19705            .map(|project| project.read(cx).languages().clone());
19706
19707        let blocks = renderer.render_group(
19708            diagnostic_group,
19709            buffer_id,
19710            snapshot,
19711            cx.weak_entity(),
19712            language_registry,
19713            cx,
19714        );
19715
19716        let blocks = self.display_map.update(cx, |display_map, cx| {
19717            display_map.insert_blocks(blocks, cx).into_iter().collect()
19718        });
19719        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19720            active_range: buffer.anchor_before(diagnostic.range.start)
19721                ..buffer.anchor_after(diagnostic.range.end),
19722            active_message: diagnostic.diagnostic.message.clone(),
19723            group_id: diagnostic.diagnostic.group_id,
19724            blocks,
19725        });
19726        cx.notify();
19727    }
19728
19729    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19730        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19731            return;
19732        };
19733
19734        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19735        if let ActiveDiagnostic::Group(group) = prev {
19736            self.display_map.update(cx, |display_map, cx| {
19737                display_map.remove_blocks(group.blocks, cx);
19738            });
19739            cx.notify();
19740        }
19741    }
19742
19743    /// Disable inline diagnostics rendering for this editor.
19744    pub fn disable_inline_diagnostics(&mut self) {
19745        self.inline_diagnostics_enabled = false;
19746        self.inline_diagnostics_update = Task::ready(());
19747        self.inline_diagnostics.clear();
19748    }
19749
19750    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19751        self.diagnostics_enabled = false;
19752        self.dismiss_diagnostics(cx);
19753        self.inline_diagnostics_update = Task::ready(());
19754        self.inline_diagnostics.clear();
19755    }
19756
19757    pub fn disable_word_completions(&mut self) {
19758        self.word_completions_enabled = false;
19759    }
19760
19761    pub fn diagnostics_enabled(&self) -> bool {
19762        self.diagnostics_enabled && self.lsp_data_enabled()
19763    }
19764
19765    pub fn inline_diagnostics_enabled(&self) -> bool {
19766        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19767    }
19768
19769    pub fn show_inline_diagnostics(&self) -> bool {
19770        self.show_inline_diagnostics
19771    }
19772
19773    pub fn toggle_inline_diagnostics(
19774        &mut self,
19775        _: &ToggleInlineDiagnostics,
19776        window: &mut Window,
19777        cx: &mut Context<Editor>,
19778    ) {
19779        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19780        self.refresh_inline_diagnostics(false, window, cx);
19781    }
19782
19783    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19784        self.diagnostics_max_severity = severity;
19785        self.display_map.update(cx, |display_map, _| {
19786            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19787        });
19788    }
19789
19790    pub fn toggle_diagnostics(
19791        &mut self,
19792        _: &ToggleDiagnostics,
19793        window: &mut Window,
19794        cx: &mut Context<Editor>,
19795    ) {
19796        if !self.diagnostics_enabled() {
19797            return;
19798        }
19799
19800        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19801            EditorSettings::get_global(cx)
19802                .diagnostics_max_severity
19803                .filter(|severity| severity != &DiagnosticSeverity::Off)
19804                .unwrap_or(DiagnosticSeverity::Hint)
19805        } else {
19806            DiagnosticSeverity::Off
19807        };
19808        self.set_max_diagnostics_severity(new_severity, cx);
19809        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19810            self.active_diagnostics = ActiveDiagnostic::None;
19811            self.inline_diagnostics_update = Task::ready(());
19812            self.inline_diagnostics.clear();
19813        } else {
19814            self.refresh_inline_diagnostics(false, window, cx);
19815        }
19816
19817        cx.notify();
19818    }
19819
19820    pub fn toggle_minimap(
19821        &mut self,
19822        _: &ToggleMinimap,
19823        window: &mut Window,
19824        cx: &mut Context<Editor>,
19825    ) {
19826        if self.supports_minimap(cx) {
19827            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19828        }
19829    }
19830
19831    fn refresh_inline_diagnostics(
19832        &mut self,
19833        debounce: bool,
19834        window: &mut Window,
19835        cx: &mut Context<Self>,
19836    ) {
19837        let max_severity = ProjectSettings::get_global(cx)
19838            .diagnostics
19839            .inline
19840            .max_severity
19841            .unwrap_or(self.diagnostics_max_severity);
19842
19843        if !self.inline_diagnostics_enabled()
19844            || !self.diagnostics_enabled()
19845            || !self.show_inline_diagnostics
19846            || max_severity == DiagnosticSeverity::Off
19847        {
19848            self.inline_diagnostics_update = Task::ready(());
19849            self.inline_diagnostics.clear();
19850            return;
19851        }
19852
19853        let debounce_ms = ProjectSettings::get_global(cx)
19854            .diagnostics
19855            .inline
19856            .update_debounce_ms;
19857        let debounce = if debounce && debounce_ms > 0 {
19858            Some(Duration::from_millis(debounce_ms))
19859        } else {
19860            None
19861        };
19862        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19863            if let Some(debounce) = debounce {
19864                cx.background_executor().timer(debounce).await;
19865            }
19866            let Some(snapshot) = editor.upgrade().map(|editor| {
19867                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19868            }) else {
19869                return;
19870            };
19871
19872            let new_inline_diagnostics = cx
19873                .background_spawn(async move {
19874                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19875                    for diagnostic_entry in
19876                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19877                    {
19878                        let message = diagnostic_entry
19879                            .diagnostic
19880                            .message
19881                            .split_once('\n')
19882                            .map(|(line, _)| line)
19883                            .map(SharedString::new)
19884                            .unwrap_or_else(|| {
19885                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19886                            });
19887                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19888                        let (Ok(i) | Err(i)) = inline_diagnostics
19889                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19890                        inline_diagnostics.insert(
19891                            i,
19892                            (
19893                                start_anchor,
19894                                InlineDiagnostic {
19895                                    message,
19896                                    group_id: diagnostic_entry.diagnostic.group_id,
19897                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19898                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19899                                    severity: diagnostic_entry.diagnostic.severity,
19900                                },
19901                            ),
19902                        );
19903                    }
19904                    inline_diagnostics
19905                })
19906                .await;
19907
19908            editor
19909                .update(cx, |editor, cx| {
19910                    editor.inline_diagnostics = new_inline_diagnostics;
19911                    cx.notify();
19912                })
19913                .ok();
19914        });
19915    }
19916
19917    fn pull_diagnostics(
19918        &mut self,
19919        buffer_id: BufferId,
19920        _window: &Window,
19921        cx: &mut Context<Self>,
19922    ) -> Option<()> {
19923        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19924        // skip any LSP updates for it.
19925
19926        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19927            return None;
19928        }
19929        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19930            .diagnostics
19931            .lsp_pull_diagnostics;
19932        if !pull_diagnostics_settings.enabled {
19933            return None;
19934        }
19935        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19936        let project = self.project()?.downgrade();
19937        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19938
19939        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19940            cx.background_executor().timer(debounce).await;
19941            if let Ok(task) = project.update(cx, |project, cx| {
19942                project.lsp_store().update(cx, |lsp_store, cx| {
19943                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19944                })
19945            }) {
19946                task.await.log_err();
19947            }
19948            project
19949                .update(cx, |project, cx| {
19950                    project.lsp_store().update(cx, |lsp_store, cx| {
19951                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19952                    })
19953                })
19954                .log_err();
19955        });
19956
19957        Some(())
19958    }
19959
19960    pub fn set_selections_from_remote(
19961        &mut self,
19962        selections: Vec<Selection<Anchor>>,
19963        pending_selection: Option<Selection<Anchor>>,
19964        window: &mut Window,
19965        cx: &mut Context<Self>,
19966    ) {
19967        let old_cursor_position = self.selections.newest_anchor().head();
19968        self.selections
19969            .change_with(&self.display_snapshot(cx), |s| {
19970                s.select_anchors(selections);
19971                if let Some(pending_selection) = pending_selection {
19972                    s.set_pending(pending_selection, SelectMode::Character);
19973                } else {
19974                    s.clear_pending();
19975                }
19976            });
19977        self.selections_did_change(
19978            false,
19979            &old_cursor_position,
19980            SelectionEffects::default(),
19981            window,
19982            cx,
19983        );
19984    }
19985
19986    pub fn transact(
19987        &mut self,
19988        window: &mut Window,
19989        cx: &mut Context<Self>,
19990        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19991    ) -> Option<TransactionId> {
19992        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19993            this.start_transaction_at(Instant::now(), window, cx);
19994            update(this, window, cx);
19995            this.end_transaction_at(Instant::now(), cx)
19996        })
19997    }
19998
19999    pub fn start_transaction_at(
20000        &mut self,
20001        now: Instant,
20002        window: &mut Window,
20003        cx: &mut Context<Self>,
20004    ) -> Option<TransactionId> {
20005        self.end_selection(window, cx);
20006        if let Some(tx_id) = self
20007            .buffer
20008            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
20009        {
20010            self.selection_history
20011                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
20012            cx.emit(EditorEvent::TransactionBegun {
20013                transaction_id: tx_id,
20014            });
20015            Some(tx_id)
20016        } else {
20017            None
20018        }
20019    }
20020
20021    pub fn end_transaction_at(
20022        &mut self,
20023        now: Instant,
20024        cx: &mut Context<Self>,
20025    ) -> Option<TransactionId> {
20026        if let Some(transaction_id) = self
20027            .buffer
20028            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
20029        {
20030            if let Some((_, end_selections)) =
20031                self.selection_history.transaction_mut(transaction_id)
20032            {
20033                *end_selections = Some(self.selections.disjoint_anchors_arc());
20034            } else {
20035                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
20036            }
20037
20038            cx.emit(EditorEvent::Edited { transaction_id });
20039            Some(transaction_id)
20040        } else {
20041            None
20042        }
20043    }
20044
20045    pub fn modify_transaction_selection_history(
20046        &mut self,
20047        transaction_id: TransactionId,
20048        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
20049    ) -> bool {
20050        self.selection_history
20051            .transaction_mut(transaction_id)
20052            .map(modify)
20053            .is_some()
20054    }
20055
20056    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
20057        if self.selection_mark_mode {
20058            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20059                s.move_with(&mut |_, sel| {
20060                    sel.collapse_to(sel.head(), SelectionGoal::None);
20061                });
20062            })
20063        }
20064        self.selection_mark_mode = true;
20065        cx.notify();
20066    }
20067
20068    pub fn swap_selection_ends(
20069        &mut self,
20070        _: &actions::SwapSelectionEnds,
20071        window: &mut Window,
20072        cx: &mut Context<Self>,
20073    ) {
20074        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20075            s.move_with(&mut |_, sel| {
20076                if sel.start != sel.end {
20077                    sel.reversed = !sel.reversed
20078                }
20079            });
20080        });
20081        self.request_autoscroll(Autoscroll::newest(), cx);
20082        cx.notify();
20083    }
20084
20085    pub fn toggle_focus(
20086        workspace: &mut Workspace,
20087        _: &actions::ToggleFocus,
20088        window: &mut Window,
20089        cx: &mut Context<Workspace>,
20090    ) {
20091        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20092            return;
20093        };
20094        workspace.activate_item(&item, true, true, window, cx);
20095    }
20096
20097    pub fn toggle_fold(
20098        &mut self,
20099        _: &actions::ToggleFold,
20100        window: &mut Window,
20101        cx: &mut Context<Self>,
20102    ) {
20103        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20104            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20105            let selection = self.selections.newest::<Point>(&display_map);
20106
20107            let range = if selection.is_empty() {
20108                let point = selection.head().to_display_point(&display_map);
20109                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20110                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20111                    .to_point(&display_map);
20112                start..end
20113            } else {
20114                selection.range()
20115            };
20116            if display_map.folds_in_range(range).next().is_some() {
20117                self.unfold_lines(&Default::default(), window, cx)
20118            } else {
20119                self.fold(&Default::default(), window, cx)
20120            }
20121        } else {
20122            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20123            let buffer_ids: HashSet<_> = self
20124                .selections
20125                .disjoint_anchor_ranges()
20126                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20127                .collect();
20128
20129            let should_unfold = buffer_ids
20130                .iter()
20131                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20132
20133            for buffer_id in buffer_ids {
20134                if should_unfold {
20135                    self.unfold_buffer(buffer_id, cx);
20136                } else {
20137                    self.fold_buffer(buffer_id, cx);
20138                }
20139            }
20140        }
20141    }
20142
20143    pub fn toggle_fold_recursive(
20144        &mut self,
20145        _: &actions::ToggleFoldRecursive,
20146        window: &mut Window,
20147        cx: &mut Context<Self>,
20148    ) {
20149        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20150
20151        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20152        let range = if selection.is_empty() {
20153            let point = selection.head().to_display_point(&display_map);
20154            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20155            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20156                .to_point(&display_map);
20157            start..end
20158        } else {
20159            selection.range()
20160        };
20161        if display_map.folds_in_range(range).next().is_some() {
20162            self.unfold_recursive(&Default::default(), window, cx)
20163        } else {
20164            self.fold_recursive(&Default::default(), window, cx)
20165        }
20166    }
20167
20168    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20169        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20170            let mut to_fold = Vec::new();
20171            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20172            let selections = self.selections.all_adjusted(&display_map);
20173
20174            for selection in selections {
20175                let range = selection.range().sorted();
20176                let buffer_start_row = range.start.row;
20177
20178                if range.start.row != range.end.row {
20179                    let mut found = false;
20180                    let mut row = range.start.row;
20181                    while row <= range.end.row {
20182                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20183                        {
20184                            found = true;
20185                            row = crease.range().end.row + 1;
20186                            to_fold.push(crease);
20187                        } else {
20188                            row += 1
20189                        }
20190                    }
20191                    if found {
20192                        continue;
20193                    }
20194                }
20195
20196                for row in (0..=range.start.row).rev() {
20197                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20198                        && crease.range().end.row >= buffer_start_row
20199                    {
20200                        to_fold.push(crease);
20201                        if row <= range.start.row {
20202                            break;
20203                        }
20204                    }
20205                }
20206            }
20207
20208            self.fold_creases(to_fold, true, window, cx);
20209        } else {
20210            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20211            let buffer_ids = self
20212                .selections
20213                .disjoint_anchor_ranges()
20214                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20215                .collect::<HashSet<_>>();
20216            for buffer_id in buffer_ids {
20217                self.fold_buffer(buffer_id, cx);
20218            }
20219        }
20220    }
20221
20222    pub fn toggle_fold_all(
20223        &mut self,
20224        _: &actions::ToggleFoldAll,
20225        window: &mut Window,
20226        cx: &mut Context<Self>,
20227    ) {
20228        let has_folds = if self.buffer.read(cx).is_singleton() {
20229            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20230            let has_folds = display_map
20231                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20232                .next()
20233                .is_some();
20234            has_folds
20235        } else {
20236            let snapshot = self.buffer.read(cx).snapshot(cx);
20237            let has_folds = snapshot
20238                .all_buffer_ids()
20239                .any(|buffer_id| self.is_buffer_folded(buffer_id, cx));
20240            has_folds
20241        };
20242
20243        if has_folds {
20244            self.unfold_all(&actions::UnfoldAll, window, cx);
20245        } else {
20246            self.fold_all(&actions::FoldAll, window, cx);
20247        }
20248    }
20249
20250    fn fold_at_level(
20251        &mut self,
20252        fold_at: &FoldAtLevel,
20253        window: &mut Window,
20254        cx: &mut Context<Self>,
20255    ) {
20256        if !self.buffer.read(cx).is_singleton() {
20257            return;
20258        }
20259
20260        let fold_at_level = fold_at.0;
20261        let snapshot = self.buffer.read(cx).snapshot(cx);
20262        let mut to_fold = Vec::new();
20263        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20264
20265        let row_ranges_to_keep: Vec<Range<u32>> = self
20266            .selections
20267            .all::<Point>(&self.display_snapshot(cx))
20268            .into_iter()
20269            .map(|sel| sel.start.row..sel.end.row)
20270            .collect();
20271
20272        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20273            while start_row < end_row {
20274                match self
20275                    .snapshot(window, cx)
20276                    .crease_for_buffer_row(MultiBufferRow(start_row))
20277                {
20278                    Some(crease) => {
20279                        let nested_start_row = crease.range().start.row + 1;
20280                        let nested_end_row = crease.range().end.row;
20281
20282                        if current_level < fold_at_level {
20283                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20284                        } else if current_level == fold_at_level {
20285                            // Fold iff there is no selection completely contained within the fold region
20286                            if !row_ranges_to_keep.iter().any(|selection| {
20287                                selection.end >= nested_start_row
20288                                    && selection.start <= nested_end_row
20289                            }) {
20290                                to_fold.push(crease);
20291                            }
20292                        }
20293
20294                        start_row = nested_end_row + 1;
20295                    }
20296                    None => start_row += 1,
20297                }
20298            }
20299        }
20300
20301        self.fold_creases(to_fold, true, window, cx);
20302    }
20303
20304    pub fn fold_at_level_1(
20305        &mut self,
20306        _: &actions::FoldAtLevel1,
20307        window: &mut Window,
20308        cx: &mut Context<Self>,
20309    ) {
20310        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20311    }
20312
20313    pub fn fold_at_level_2(
20314        &mut self,
20315        _: &actions::FoldAtLevel2,
20316        window: &mut Window,
20317        cx: &mut Context<Self>,
20318    ) {
20319        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20320    }
20321
20322    pub fn fold_at_level_3(
20323        &mut self,
20324        _: &actions::FoldAtLevel3,
20325        window: &mut Window,
20326        cx: &mut Context<Self>,
20327    ) {
20328        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20329    }
20330
20331    pub fn fold_at_level_4(
20332        &mut self,
20333        _: &actions::FoldAtLevel4,
20334        window: &mut Window,
20335        cx: &mut Context<Self>,
20336    ) {
20337        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20338    }
20339
20340    pub fn fold_at_level_5(
20341        &mut self,
20342        _: &actions::FoldAtLevel5,
20343        window: &mut Window,
20344        cx: &mut Context<Self>,
20345    ) {
20346        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20347    }
20348
20349    pub fn fold_at_level_6(
20350        &mut self,
20351        _: &actions::FoldAtLevel6,
20352        window: &mut Window,
20353        cx: &mut Context<Self>,
20354    ) {
20355        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20356    }
20357
20358    pub fn fold_at_level_7(
20359        &mut self,
20360        _: &actions::FoldAtLevel7,
20361        window: &mut Window,
20362        cx: &mut Context<Self>,
20363    ) {
20364        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20365    }
20366
20367    pub fn fold_at_level_8(
20368        &mut self,
20369        _: &actions::FoldAtLevel8,
20370        window: &mut Window,
20371        cx: &mut Context<Self>,
20372    ) {
20373        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20374    }
20375
20376    pub fn fold_at_level_9(
20377        &mut self,
20378        _: &actions::FoldAtLevel9,
20379        window: &mut Window,
20380        cx: &mut Context<Self>,
20381    ) {
20382        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20383    }
20384
20385    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20386        if self.buffer.read(cx).is_singleton() {
20387            let mut fold_ranges = Vec::new();
20388            let snapshot = self.buffer.read(cx).snapshot(cx);
20389
20390            for row in 0..snapshot.max_row().0 {
20391                if let Some(foldable_range) = self
20392                    .snapshot(window, cx)
20393                    .crease_for_buffer_row(MultiBufferRow(row))
20394                {
20395                    fold_ranges.push(foldable_range);
20396                }
20397            }
20398
20399            self.fold_creases(fold_ranges, true, window, cx);
20400        } else {
20401            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20402                editor
20403                    .update_in(cx, |editor, _, cx| {
20404                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20405                        for buffer_id in snapshot.all_buffer_ids() {
20406                            editor.fold_buffer(buffer_id, cx);
20407                        }
20408                    })
20409                    .ok();
20410            });
20411        }
20412    }
20413
20414    pub fn fold_function_bodies(
20415        &mut self,
20416        _: &actions::FoldFunctionBodies,
20417        window: &mut Window,
20418        cx: &mut Context<Self>,
20419    ) {
20420        let snapshot = self.buffer.read(cx).snapshot(cx);
20421
20422        let ranges = snapshot
20423            .text_object_ranges(
20424                MultiBufferOffset(0)..snapshot.len(),
20425                TreeSitterOptions::default(),
20426            )
20427            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20428            .collect::<Vec<_>>();
20429
20430        let creases = ranges
20431            .into_iter()
20432            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20433            .collect();
20434
20435        self.fold_creases(creases, true, window, cx);
20436    }
20437
20438    pub fn fold_recursive(
20439        &mut self,
20440        _: &actions::FoldRecursive,
20441        window: &mut Window,
20442        cx: &mut Context<Self>,
20443    ) {
20444        let mut to_fold = Vec::new();
20445        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20446        let selections = self.selections.all_adjusted(&display_map);
20447
20448        for selection in selections {
20449            let range = selection.range().sorted();
20450            let buffer_start_row = range.start.row;
20451
20452            if range.start.row != range.end.row {
20453                let mut found = false;
20454                for row in range.start.row..=range.end.row {
20455                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20456                        found = true;
20457                        to_fold.push(crease);
20458                    }
20459                }
20460                if found {
20461                    continue;
20462                }
20463            }
20464
20465            for row in (0..=range.start.row).rev() {
20466                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20467                    if crease.range().end.row >= buffer_start_row {
20468                        to_fold.push(crease);
20469                    } else {
20470                        break;
20471                    }
20472                }
20473            }
20474        }
20475
20476        self.fold_creases(to_fold, true, window, cx);
20477    }
20478
20479    pub fn fold_at(
20480        &mut self,
20481        buffer_row: MultiBufferRow,
20482        window: &mut Window,
20483        cx: &mut Context<Self>,
20484    ) {
20485        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20486
20487        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20488            let autoscroll = self
20489                .selections
20490                .all::<Point>(&display_map)
20491                .iter()
20492                .any(|selection| crease.range().overlaps(&selection.range()));
20493
20494            self.fold_creases(vec![crease], autoscroll, window, cx);
20495        }
20496    }
20497
20498    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20499        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20500            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20501            let buffer = display_map.buffer_snapshot();
20502            let selections = self.selections.all::<Point>(&display_map);
20503            let ranges = selections
20504                .iter()
20505                .map(|s| {
20506                    let range = s.display_range(&display_map).sorted();
20507                    let mut start = range.start.to_point(&display_map);
20508                    let mut end = range.end.to_point(&display_map);
20509                    start.column = 0;
20510                    end.column = buffer.line_len(MultiBufferRow(end.row));
20511                    start..end
20512                })
20513                .collect::<Vec<_>>();
20514
20515            self.unfold_ranges(&ranges, true, true, cx);
20516        } else {
20517            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20518            let buffer_ids = self
20519                .selections
20520                .disjoint_anchor_ranges()
20521                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20522                .collect::<HashSet<_>>();
20523            for buffer_id in buffer_ids {
20524                self.unfold_buffer(buffer_id, cx);
20525            }
20526        }
20527    }
20528
20529    pub fn unfold_recursive(
20530        &mut self,
20531        _: &UnfoldRecursive,
20532        _window: &mut Window,
20533        cx: &mut Context<Self>,
20534    ) {
20535        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20536        let selections = self.selections.all::<Point>(&display_map);
20537        let ranges = selections
20538            .iter()
20539            .map(|s| {
20540                let mut range = s.display_range(&display_map).sorted();
20541                *range.start.column_mut() = 0;
20542                *range.end.column_mut() = display_map.line_len(range.end.row());
20543                let start = range.start.to_point(&display_map);
20544                let end = range.end.to_point(&display_map);
20545                start..end
20546            })
20547            .collect::<Vec<_>>();
20548
20549        self.unfold_ranges(&ranges, true, true, cx);
20550    }
20551
20552    pub fn unfold_at(
20553        &mut self,
20554        buffer_row: MultiBufferRow,
20555        _window: &mut Window,
20556        cx: &mut Context<Self>,
20557    ) {
20558        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20559
20560        let intersection_range = Point::new(buffer_row.0, 0)
20561            ..Point::new(
20562                buffer_row.0,
20563                display_map.buffer_snapshot().line_len(buffer_row),
20564            );
20565
20566        let autoscroll = self
20567            .selections
20568            .all::<Point>(&display_map)
20569            .iter()
20570            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20571
20572        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20573    }
20574
20575    pub fn unfold_all(
20576        &mut self,
20577        _: &actions::UnfoldAll,
20578        _window: &mut Window,
20579        cx: &mut Context<Self>,
20580    ) {
20581        if self.buffer.read(cx).is_singleton() {
20582            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20583            self.unfold_ranges(
20584                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20585                true,
20586                true,
20587                cx,
20588            );
20589        } else {
20590            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20591                editor
20592                    .update(cx, |editor, cx| {
20593                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20594                        for buffer_id in snapshot.all_buffer_ids() {
20595                            editor.unfold_buffer(buffer_id, cx);
20596                        }
20597                    })
20598                    .ok();
20599            });
20600        }
20601    }
20602
20603    pub fn fold_selected_ranges(
20604        &mut self,
20605        _: &FoldSelectedRanges,
20606        window: &mut Window,
20607        cx: &mut Context<Self>,
20608    ) {
20609        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20610        let selections = self.selections.all_adjusted(&display_map);
20611        let ranges = selections
20612            .into_iter()
20613            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20614            .collect::<Vec<_>>();
20615        self.fold_creases(ranges, true, window, cx);
20616    }
20617
20618    pub fn fold_ranges<T: ToOffset + Clone>(
20619        &mut self,
20620        ranges: Vec<Range<T>>,
20621        auto_scroll: bool,
20622        window: &mut Window,
20623        cx: &mut Context<Self>,
20624    ) {
20625        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20626        let ranges = ranges
20627            .into_iter()
20628            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20629            .collect::<Vec<_>>();
20630        self.fold_creases(ranges, auto_scroll, window, cx);
20631    }
20632
20633    pub fn fold_creases<T: ToOffset + Clone>(
20634        &mut self,
20635        creases: Vec<Crease<T>>,
20636        auto_scroll: bool,
20637        window: &mut Window,
20638        cx: &mut Context<Self>,
20639    ) {
20640        if creases.is_empty() {
20641            return;
20642        }
20643
20644        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20645
20646        if auto_scroll {
20647            self.request_autoscroll(Autoscroll::fit(), cx);
20648        }
20649
20650        cx.notify();
20651
20652        self.scrollbar_marker_state.dirty = true;
20653        self.update_data_on_scroll(window, cx);
20654        self.folds_did_change(cx);
20655    }
20656
20657    /// Removes any folds whose ranges intersect any of the given ranges.
20658    pub fn unfold_ranges<T: ToOffset + Clone>(
20659        &mut self,
20660        ranges: &[Range<T>],
20661        inclusive: bool,
20662        auto_scroll: bool,
20663        cx: &mut Context<Self>,
20664    ) {
20665        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20666            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20667        });
20668        self.folds_did_change(cx);
20669    }
20670
20671    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20672        self.fold_buffers([buffer_id], cx);
20673    }
20674
20675    pub fn fold_buffers(
20676        &mut self,
20677        buffer_ids: impl IntoIterator<Item = BufferId>,
20678        cx: &mut Context<Self>,
20679    ) {
20680        if self.buffer().read(cx).is_singleton() {
20681            return;
20682        }
20683
20684        let ids_to_fold: Vec<BufferId> = buffer_ids
20685            .into_iter()
20686            .filter(|id| !self.is_buffer_folded(*id, cx))
20687            .collect();
20688
20689        if ids_to_fold.is_empty() {
20690            return;
20691        }
20692
20693        self.display_map.update(cx, |display_map, cx| {
20694            display_map.fold_buffers(ids_to_fold.clone(), cx)
20695        });
20696
20697        let snapshot = self.display_snapshot(cx);
20698        self.selections.change_with(&snapshot, |selections| {
20699            for buffer_id in ids_to_fold.iter().copied() {
20700                selections.remove_selections_from_buffer(buffer_id);
20701            }
20702        });
20703
20704        cx.emit(EditorEvent::BufferFoldToggled {
20705            ids: ids_to_fold,
20706            folded: true,
20707        });
20708        cx.notify();
20709    }
20710
20711    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20712        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20713            return;
20714        }
20715        self.display_map.update(cx, |display_map, cx| {
20716            display_map.unfold_buffers([buffer_id], cx);
20717        });
20718        cx.emit(EditorEvent::BufferFoldToggled {
20719            ids: vec![buffer_id],
20720            folded: false,
20721        });
20722        cx.notify();
20723    }
20724
20725    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20726        self.display_map.read(cx).is_buffer_folded(buffer)
20727    }
20728
20729    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20730        if self.buffer().read(cx).is_singleton() {
20731            return false;
20732        }
20733        !self.folded_buffers(cx).is_empty()
20734    }
20735
20736    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20737        self.display_map.read(cx).folded_buffers()
20738    }
20739
20740    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20741        self.display_map.update(cx, |display_map, cx| {
20742            display_map.disable_header_for_buffer(buffer_id, cx);
20743        });
20744        cx.notify();
20745    }
20746
20747    /// Removes any folds with the given ranges.
20748    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20749        &mut self,
20750        ranges: &[Range<T>],
20751        type_id: TypeId,
20752        auto_scroll: bool,
20753        cx: &mut Context<Self>,
20754    ) {
20755        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20756            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20757        });
20758        self.folds_did_change(cx);
20759    }
20760
20761    fn remove_folds_with<T: ToOffset + Clone>(
20762        &mut self,
20763        ranges: &[Range<T>],
20764        auto_scroll: bool,
20765        cx: &mut Context<Self>,
20766        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20767    ) {
20768        if ranges.is_empty() {
20769            return;
20770        }
20771
20772        self.display_map.update(cx, update);
20773
20774        if auto_scroll {
20775            self.request_autoscroll(Autoscroll::fit(), cx);
20776        }
20777
20778        cx.notify();
20779        self.scrollbar_marker_state.dirty = true;
20780        self.active_indent_guides_state.dirty = true;
20781    }
20782
20783    pub fn update_renderer_widths(
20784        &mut self,
20785        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20786        cx: &mut Context<Self>,
20787    ) -> bool {
20788        self.display_map
20789            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20790    }
20791
20792    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20793        self.display_map.read(cx).fold_placeholder.clone()
20794    }
20795
20796    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20797        self.buffer.update(cx, |buffer, cx| {
20798            buffer.set_all_diff_hunks_expanded(cx);
20799        });
20800    }
20801
20802    pub fn expand_all_diff_hunks(
20803        &mut self,
20804        _: &ExpandAllDiffHunks,
20805        _window: &mut Window,
20806        cx: &mut Context<Self>,
20807    ) {
20808        self.buffer.update(cx, |buffer, cx| {
20809            buffer.expand_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20810        });
20811    }
20812
20813    pub fn collapse_all_diff_hunks(
20814        &mut self,
20815        _: &CollapseAllDiffHunks,
20816        _window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        self.buffer.update(cx, |buffer, cx| {
20820            buffer.collapse_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
20821        });
20822    }
20823
20824    pub fn toggle_selected_diff_hunks(
20825        &mut self,
20826        _: &ToggleSelectedDiffHunks,
20827        _window: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        let ranges: Vec<_> = self
20831            .selections
20832            .disjoint_anchors()
20833            .iter()
20834            .map(|s| s.range())
20835            .collect();
20836        self.toggle_diff_hunks_in_ranges(ranges, cx);
20837    }
20838
20839    pub fn diff_hunks_in_ranges<'a>(
20840        &'a self,
20841        ranges: &'a [Range<Anchor>],
20842        buffer: &'a MultiBufferSnapshot,
20843    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20844        ranges.iter().flat_map(move |range| {
20845            let end_excerpt = buffer.excerpt_containing(range.end..range.end);
20846            let range = range.to_point(buffer);
20847            let mut peek_end = range.end;
20848            if range.end.row < buffer.max_row().0 {
20849                peek_end = Point::new(range.end.row + 1, 0);
20850            }
20851            buffer
20852                .diff_hunks_in_range(range.start..peek_end)
20853                .filter(move |hunk| {
20854                    if let Some((_, excerpt_range)) = &end_excerpt
20855                        && let Some(end_anchor) =
20856                            buffer.anchor_in_excerpt(excerpt_range.context.end)
20857                        && let Some(hunk_end_anchor) =
20858                            buffer.anchor_in_excerpt(hunk.excerpt_range.context.end)
20859                        && hunk_end_anchor.cmp(&end_anchor, buffer).is_gt()
20860                    {
20861                        false
20862                    } else {
20863                        true
20864                    }
20865                })
20866        })
20867    }
20868
20869    pub fn has_stageable_diff_hunks_in_ranges(
20870        &self,
20871        ranges: &[Range<Anchor>],
20872        snapshot: &MultiBufferSnapshot,
20873    ) -> bool {
20874        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20875        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20876    }
20877
20878    pub fn toggle_staged_selected_diff_hunks(
20879        &mut self,
20880        _: &::git::ToggleStaged,
20881        _: &mut Window,
20882        cx: &mut Context<Self>,
20883    ) {
20884        let snapshot = self.buffer.read(cx).snapshot(cx);
20885        let ranges: Vec<_> = self
20886            .selections
20887            .disjoint_anchors()
20888            .iter()
20889            .map(|s| s.range())
20890            .collect();
20891        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20892        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20893    }
20894
20895    pub fn set_render_diff_hunk_controls(
20896        &mut self,
20897        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20898        cx: &mut Context<Self>,
20899    ) {
20900        self.render_diff_hunk_controls = render_diff_hunk_controls;
20901        cx.notify();
20902    }
20903
20904    pub fn stage_and_next(
20905        &mut self,
20906        _: &::git::StageAndNext,
20907        window: &mut Window,
20908        cx: &mut Context<Self>,
20909    ) {
20910        self.do_stage_or_unstage_and_next(true, window, cx);
20911    }
20912
20913    pub fn unstage_and_next(
20914        &mut self,
20915        _: &::git::UnstageAndNext,
20916        window: &mut Window,
20917        cx: &mut Context<Self>,
20918    ) {
20919        self.do_stage_or_unstage_and_next(false, window, cx);
20920    }
20921
20922    pub fn stage_or_unstage_diff_hunks(
20923        &mut self,
20924        stage: bool,
20925        ranges: Vec<Range<Anchor>>,
20926        cx: &mut Context<Self>,
20927    ) {
20928        if self.delegate_stage_and_restore {
20929            let snapshot = self.buffer.read(cx).snapshot(cx);
20930            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20931            if !hunks.is_empty() {
20932                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20933            }
20934            return;
20935        }
20936        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20937        cx.spawn(async move |this, cx| {
20938            task.await?;
20939            this.update(cx, |this, cx| {
20940                let snapshot = this.buffer.read(cx).snapshot(cx);
20941                let chunk_by = this
20942                    .diff_hunks_in_ranges(&ranges, &snapshot)
20943                    .chunk_by(|hunk| hunk.buffer_id);
20944                for (buffer_id, hunks) in &chunk_by {
20945                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20946                }
20947            })
20948        })
20949        .detach_and_log_err(cx);
20950    }
20951
20952    fn save_buffers_for_ranges_if_needed(
20953        &mut self,
20954        ranges: &[Range<Anchor>],
20955        cx: &mut Context<Editor>,
20956    ) -> Task<Result<()>> {
20957        let multibuffer = self.buffer.read(cx);
20958        let snapshot = multibuffer.read(cx);
20959        let buffer_ids: HashSet<_> = ranges
20960            .iter()
20961            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20962            .collect();
20963        drop(snapshot);
20964
20965        let mut buffers = HashSet::default();
20966        for buffer_id in buffer_ids {
20967            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20968                let buffer = buffer_entity.read(cx);
20969                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20970                {
20971                    buffers.insert(buffer_entity);
20972                }
20973            }
20974        }
20975
20976        if let Some(project) = &self.project {
20977            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20978        } else {
20979            Task::ready(Ok(()))
20980        }
20981    }
20982
20983    fn do_stage_or_unstage_and_next(
20984        &mut self,
20985        stage: bool,
20986        window: &mut Window,
20987        cx: &mut Context<Self>,
20988    ) {
20989        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20990
20991        if ranges.iter().any(|range| range.start != range.end) {
20992            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20993            return;
20994        }
20995
20996        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20997
20998        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20999        let wrap_around = !all_diff_hunks_expanded;
21000        let snapshot = self.snapshot(window, cx);
21001        let position = self
21002            .selections
21003            .newest::<Point>(&snapshot.display_snapshot)
21004            .head();
21005
21006        self.go_to_hunk_before_or_after_position(
21007            &snapshot,
21008            position,
21009            Direction::Next,
21010            wrap_around,
21011            window,
21012            cx,
21013        );
21014    }
21015
21016    pub(crate) fn do_stage_or_unstage(
21017        &self,
21018        stage: bool,
21019        buffer_id: BufferId,
21020        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
21021        cx: &mut App,
21022    ) -> Option<()> {
21023        let project = self.project()?;
21024        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
21025        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
21026        let buffer_snapshot = buffer.read(cx).snapshot();
21027        let file_exists = buffer_snapshot
21028            .file()
21029            .is_some_and(|file| file.disk_state().exists());
21030        diff.update(cx, |diff, cx| {
21031            diff.stage_or_unstage_hunks(
21032                stage,
21033                &hunks
21034                    .map(|hunk| buffer_diff::DiffHunk {
21035                        buffer_range: hunk.buffer_range,
21036                        // We don't need to pass in word diffs here because they're only used for rendering and
21037                        // this function changes internal state
21038                        base_word_diffs: Vec::default(),
21039                        buffer_word_diffs: Vec::default(),
21040                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
21041                            ..hunk.diff_base_byte_range.end.0,
21042                        secondary_status: hunk.status.secondary,
21043                        range: Point::zero()..Point::zero(), // unused
21044                    })
21045                    .collect::<Vec<_>>(),
21046                &buffer_snapshot,
21047                file_exists,
21048                cx,
21049            )
21050        });
21051        None
21052    }
21053
21054    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
21055        let ranges: Vec<_> = self
21056            .selections
21057            .disjoint_anchors()
21058            .iter()
21059            .map(|s| s.range())
21060            .collect();
21061        self.buffer
21062            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
21063    }
21064
21065    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
21066        self.buffer.update(cx, |buffer, cx| {
21067            let ranges = vec![Anchor::Min..Anchor::Max];
21068            if !buffer.all_diff_hunks_expanded()
21069                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
21070            {
21071                buffer.collapse_diff_hunks(ranges, cx);
21072                true
21073            } else {
21074                false
21075            }
21076        })
21077    }
21078
21079    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21080        if self.buffer.read(cx).all_diff_hunks_expanded() {
21081            return true;
21082        }
21083        let ranges = vec![Anchor::Min..Anchor::Max];
21084        self.buffer
21085            .read(cx)
21086            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21087    }
21088
21089    fn toggle_diff_hunks_in_ranges(
21090        &mut self,
21091        ranges: Vec<Range<Anchor>>,
21092        cx: &mut Context<Editor>,
21093    ) {
21094        self.buffer.update(cx, |buffer, cx| {
21095            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21096            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21097        })
21098    }
21099
21100    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21101        self.buffer.update(cx, |buffer, cx| {
21102            buffer.toggle_single_diff_hunk(range, cx);
21103        })
21104    }
21105
21106    pub(crate) fn apply_all_diff_hunks(
21107        &mut self,
21108        _: &ApplyAllDiffHunks,
21109        window: &mut Window,
21110        cx: &mut Context<Self>,
21111    ) {
21112        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21113
21114        let buffers = self.buffer.read(cx).all_buffers();
21115        for branch_buffer in buffers {
21116            branch_buffer.update(cx, |branch_buffer, cx| {
21117                branch_buffer.merge_into_base(Vec::new(), cx);
21118            });
21119        }
21120
21121        if let Some(project) = self.project.clone() {
21122            self.save(
21123                SaveOptions {
21124                    format: true,
21125                    autosave: false,
21126                },
21127                project,
21128                window,
21129                cx,
21130            )
21131            .detach_and_log_err(cx);
21132        }
21133    }
21134
21135    pub(crate) fn apply_selected_diff_hunks(
21136        &mut self,
21137        _: &ApplyDiffHunk,
21138        window: &mut Window,
21139        cx: &mut Context<Self>,
21140    ) {
21141        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21142        let snapshot = self.snapshot(window, cx);
21143        let hunks = snapshot.hunks_for_ranges(
21144            self.selections
21145                .all(&snapshot.display_snapshot)
21146                .into_iter()
21147                .map(|selection| selection.range()),
21148        );
21149        let mut ranges_by_buffer = HashMap::default();
21150        self.transact(window, cx, |editor, _window, cx| {
21151            for hunk in hunks {
21152                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21153                    ranges_by_buffer
21154                        .entry(buffer.clone())
21155                        .or_insert_with(Vec::new)
21156                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21157                }
21158            }
21159
21160            for (buffer, ranges) in ranges_by_buffer {
21161                buffer.update(cx, |buffer, cx| {
21162                    buffer.merge_into_base(ranges, cx);
21163                });
21164            }
21165        });
21166
21167        if let Some(project) = self.project.clone() {
21168            self.save(
21169                SaveOptions {
21170                    format: true,
21171                    autosave: false,
21172                },
21173                project,
21174                window,
21175                cx,
21176            )
21177            .detach_and_log_err(cx);
21178        }
21179    }
21180
21181    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21182        if hovered != self.gutter_hovered {
21183            self.gutter_hovered = hovered;
21184            cx.notify();
21185        }
21186    }
21187
21188    pub fn insert_blocks(
21189        &mut self,
21190        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21191        autoscroll: Option<Autoscroll>,
21192        cx: &mut Context<Self>,
21193    ) -> Vec<CustomBlockId> {
21194        let blocks = self
21195            .display_map
21196            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21197        if let Some(autoscroll) = autoscroll {
21198            self.request_autoscroll(autoscroll, cx);
21199        }
21200        cx.notify();
21201        blocks
21202    }
21203
21204    pub fn resize_blocks(
21205        &mut self,
21206        heights: HashMap<CustomBlockId, u32>,
21207        autoscroll: Option<Autoscroll>,
21208        cx: &mut Context<Self>,
21209    ) {
21210        self.display_map
21211            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21212        if let Some(autoscroll) = autoscroll {
21213            self.request_autoscroll(autoscroll, cx);
21214        }
21215        cx.notify();
21216    }
21217
21218    pub fn replace_blocks(
21219        &mut self,
21220        renderers: HashMap<CustomBlockId, RenderBlock>,
21221        autoscroll: Option<Autoscroll>,
21222        cx: &mut Context<Self>,
21223    ) {
21224        self.display_map
21225            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21226        if let Some(autoscroll) = autoscroll {
21227            self.request_autoscroll(autoscroll, cx);
21228        }
21229        cx.notify();
21230    }
21231
21232    pub fn remove_blocks(
21233        &mut self,
21234        block_ids: HashSet<CustomBlockId>,
21235        autoscroll: Option<Autoscroll>,
21236        cx: &mut Context<Self>,
21237    ) {
21238        self.display_map.update(cx, |display_map, cx| {
21239            display_map.remove_blocks(block_ids, cx)
21240        });
21241        if let Some(autoscroll) = autoscroll {
21242            self.request_autoscroll(autoscroll, cx);
21243        }
21244        cx.notify();
21245    }
21246
21247    pub fn row_for_block(
21248        &self,
21249        block_id: CustomBlockId,
21250        cx: &mut Context<Self>,
21251    ) -> Option<DisplayRow> {
21252        self.display_map
21253            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21254    }
21255
21256    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21257        self.focused_block = Some(focused_block);
21258    }
21259
21260    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21261        self.focused_block.take()
21262    }
21263
21264    pub fn insert_creases(
21265        &mut self,
21266        creases: impl IntoIterator<Item = Crease<Anchor>>,
21267        cx: &mut Context<Self>,
21268    ) -> Vec<CreaseId> {
21269        self.display_map
21270            .update(cx, |map, cx| map.insert_creases(creases, cx))
21271    }
21272
21273    pub fn remove_creases(
21274        &mut self,
21275        ids: impl IntoIterator<Item = CreaseId>,
21276        cx: &mut Context<Self>,
21277    ) -> Vec<(CreaseId, Range<Anchor>)> {
21278        self.display_map
21279            .update(cx, |map, cx| map.remove_creases(ids, cx))
21280    }
21281
21282    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21283        self.display_map
21284            .update(cx, |map, cx| map.snapshot(cx))
21285            .longest_row()
21286    }
21287
21288    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21289        self.display_map
21290            .update(cx, |map, cx| map.snapshot(cx))
21291            .max_point()
21292    }
21293
21294    pub fn text(&self, cx: &App) -> String {
21295        self.buffer.read(cx).read(cx).text()
21296    }
21297
21298    pub fn is_empty(&self, cx: &App) -> bool {
21299        self.buffer.read(cx).read(cx).is_empty()
21300    }
21301
21302    pub fn text_option(&self, cx: &App) -> Option<String> {
21303        let text = self.text(cx);
21304        let text = text.trim();
21305
21306        if text.is_empty() {
21307            return None;
21308        }
21309
21310        Some(text.to_string())
21311    }
21312
21313    pub fn set_text(
21314        &mut self,
21315        text: impl Into<Arc<str>>,
21316        window: &mut Window,
21317        cx: &mut Context<Self>,
21318    ) {
21319        self.transact(window, cx, |this, _, cx| {
21320            this.buffer
21321                .read(cx)
21322                .as_singleton()
21323                .expect("you can only call set_text on editors for singleton buffers")
21324                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21325        });
21326    }
21327
21328    pub fn display_text(&self, cx: &mut App) -> String {
21329        self.display_map
21330            .update(cx, |map, cx| map.snapshot(cx))
21331            .text()
21332    }
21333
21334    fn create_minimap(
21335        &self,
21336        minimap_settings: MinimapSettings,
21337        window: &mut Window,
21338        cx: &mut Context<Self>,
21339    ) -> Option<Entity<Self>> {
21340        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21341            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21342    }
21343
21344    fn initialize_new_minimap(
21345        &self,
21346        minimap_settings: MinimapSettings,
21347        window: &mut Window,
21348        cx: &mut Context<Self>,
21349    ) -> Entity<Self> {
21350        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21351        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21352
21353        let mut minimap = Editor::new_internal(
21354            EditorMode::Minimap {
21355                parent: cx.weak_entity(),
21356            },
21357            self.buffer.clone(),
21358            None,
21359            Some(self.display_map.clone()),
21360            window,
21361            cx,
21362        );
21363        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21364        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21365        minimap.scroll_manager.clone_state(
21366            &self.scroll_manager,
21367            &my_snapshot,
21368            &minimap_snapshot,
21369            cx,
21370        );
21371        minimap.set_text_style_refinement(TextStyleRefinement {
21372            font_size: Some(MINIMAP_FONT_SIZE),
21373            font_weight: Some(MINIMAP_FONT_WEIGHT),
21374            font_family: Some(MINIMAP_FONT_FAMILY),
21375            ..Default::default()
21376        });
21377        minimap.update_minimap_configuration(minimap_settings, cx);
21378        cx.new(|_| minimap)
21379    }
21380
21381    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21382        let current_line_highlight = minimap_settings
21383            .current_line_highlight
21384            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21385        self.set_current_line_highlight(Some(current_line_highlight));
21386    }
21387
21388    pub fn minimap(&self) -> Option<&Entity<Self>> {
21389        self.minimap
21390            .as_ref()
21391            .filter(|_| self.minimap_visibility.visible())
21392    }
21393
21394    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21395        let mut wrap_guides = smallvec![];
21396
21397        if self.show_wrap_guides == Some(false) {
21398            return wrap_guides;
21399        }
21400
21401        let settings = self.buffer.read(cx).language_settings(cx);
21402        if settings.show_wrap_guides {
21403            match self.soft_wrap_mode(cx) {
21404                SoftWrap::Column(soft_wrap) => {
21405                    wrap_guides.push((soft_wrap as usize, true));
21406                }
21407                SoftWrap::Bounded(soft_wrap) => {
21408                    wrap_guides.push((soft_wrap as usize, true));
21409                }
21410                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21411            }
21412            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21413        }
21414
21415        wrap_guides
21416    }
21417
21418    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21419        let settings = self.buffer.read(cx).language_settings(cx);
21420        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21421        match mode {
21422            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21423                SoftWrap::None
21424            }
21425            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21426            language_settings::SoftWrap::PreferredLineLength => {
21427                SoftWrap::Column(settings.preferred_line_length)
21428            }
21429            language_settings::SoftWrap::Bounded => {
21430                SoftWrap::Bounded(settings.preferred_line_length)
21431            }
21432        }
21433    }
21434
21435    pub fn set_soft_wrap_mode(
21436        &mut self,
21437        mode: language_settings::SoftWrap,
21438        cx: &mut Context<Self>,
21439    ) {
21440        self.soft_wrap_mode_override = Some(mode);
21441        cx.notify();
21442    }
21443
21444    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21445        self.hard_wrap = hard_wrap;
21446        cx.notify();
21447    }
21448
21449    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21450        self.text_style_refinement = Some(style);
21451    }
21452
21453    /// called by the Element so we know what style we were most recently rendered with.
21454    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21455        // We intentionally do not inform the display map about the minimap style
21456        // so that wrapping is not recalculated and stays consistent for the editor
21457        // and its linked minimap.
21458        if !self.mode.is_minimap() {
21459            let font = style.text.font();
21460            let font_size = style.text.font_size.to_pixels(window.rem_size());
21461            let display_map = self
21462                .placeholder_display_map
21463                .as_ref()
21464                .filter(|_| self.is_empty(cx))
21465                .unwrap_or(&self.display_map);
21466
21467            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21468        }
21469        self.style = Some(style);
21470    }
21471
21472    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21473        if self.style.is_none() {
21474            self.style = Some(self.create_style(cx));
21475        }
21476        self.style.as_ref().unwrap()
21477    }
21478
21479    // Called by the element. This method is not designed to be called outside of the editor
21480    // element's layout code because it does not notify when rewrapping is computed synchronously.
21481    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21482        if self.is_empty(cx) {
21483            self.placeholder_display_map
21484                .as_ref()
21485                .map_or(false, |display_map| {
21486                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21487                })
21488        } else {
21489            self.display_map
21490                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21491        }
21492    }
21493
21494    pub fn set_soft_wrap(&mut self) {
21495        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21496    }
21497
21498    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21499        if self.soft_wrap_mode_override.is_some() {
21500            self.soft_wrap_mode_override.take();
21501        } else {
21502            let soft_wrap = match self.soft_wrap_mode(cx) {
21503                SoftWrap::GitDiff => return,
21504                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21505                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21506                    language_settings::SoftWrap::None
21507                }
21508            };
21509            self.soft_wrap_mode_override = Some(soft_wrap);
21510        }
21511        cx.notify();
21512    }
21513
21514    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21515        let Some(workspace) = self.workspace() else {
21516            return;
21517        };
21518        let fs = workspace.read(cx).app_state().fs.clone();
21519        let current_show = TabBarSettings::get_global(cx).show;
21520        update_settings_file(fs, cx, move |setting, _| {
21521            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21522        });
21523    }
21524
21525    pub fn toggle_indent_guides(
21526        &mut self,
21527        _: &ToggleIndentGuides,
21528        _: &mut Window,
21529        cx: &mut Context<Self>,
21530    ) {
21531        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21532            self.buffer
21533                .read(cx)
21534                .language_settings(cx)
21535                .indent_guides
21536                .enabled
21537        });
21538        self.show_indent_guides = Some(!currently_enabled);
21539        cx.notify();
21540    }
21541
21542    fn should_show_indent_guides(&self) -> Option<bool> {
21543        self.show_indent_guides
21544    }
21545
21546    pub fn disable_indent_guides_for_buffer(
21547        &mut self,
21548        buffer_id: BufferId,
21549        cx: &mut Context<Self>,
21550    ) {
21551        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21552        cx.notify();
21553    }
21554
21555    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21556        self.buffers_with_disabled_indent_guides
21557            .contains(&buffer_id)
21558    }
21559
21560    pub fn toggle_line_numbers(
21561        &mut self,
21562        _: &ToggleLineNumbers,
21563        _: &mut Window,
21564        cx: &mut Context<Self>,
21565    ) {
21566        let mut editor_settings = EditorSettings::get_global(cx).clone();
21567        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21568        EditorSettings::override_global(editor_settings, cx);
21569    }
21570
21571    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21572        if let Some(show_line_numbers) = self.show_line_numbers {
21573            return show_line_numbers;
21574        }
21575        EditorSettings::get_global(cx).gutter.line_numbers
21576    }
21577
21578    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21579        match (
21580            self.use_relative_line_numbers,
21581            EditorSettings::get_global(cx).relative_line_numbers,
21582        ) {
21583            (None, setting) => setting,
21584            (Some(false), _) => RelativeLineNumbers::Disabled,
21585            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21586            (Some(true), _) => RelativeLineNumbers::Enabled,
21587        }
21588    }
21589
21590    pub fn toggle_relative_line_numbers(
21591        &mut self,
21592        _: &ToggleRelativeLineNumbers,
21593        _: &mut Window,
21594        cx: &mut Context<Self>,
21595    ) {
21596        let is_relative = self.relative_line_numbers(cx);
21597        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21598    }
21599
21600    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21601        self.use_relative_line_numbers = is_relative;
21602        cx.notify();
21603    }
21604
21605    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21606        self.show_gutter = show_gutter;
21607        cx.notify();
21608    }
21609
21610    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21611        self.show_scrollbars = ScrollbarAxes {
21612            horizontal: show,
21613            vertical: show,
21614        };
21615        cx.notify();
21616    }
21617
21618    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21619        self.show_scrollbars.vertical = show;
21620        cx.notify();
21621    }
21622
21623    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21624        self.show_scrollbars.horizontal = show;
21625        cx.notify();
21626    }
21627
21628    pub fn set_minimap_visibility(
21629        &mut self,
21630        minimap_visibility: MinimapVisibility,
21631        window: &mut Window,
21632        cx: &mut Context<Self>,
21633    ) {
21634        if self.minimap_visibility != minimap_visibility {
21635            if minimap_visibility.visible() && self.minimap.is_none() {
21636                let minimap_settings = EditorSettings::get_global(cx).minimap;
21637                self.minimap =
21638                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21639            }
21640            self.minimap_visibility = minimap_visibility;
21641            cx.notify();
21642        }
21643    }
21644
21645    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21646        self.set_show_scrollbars(false, cx);
21647        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21648    }
21649
21650    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21651        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21652    }
21653
21654    /// Normally the text in full mode and auto height editors is padded on the
21655    /// left side by roughly half a character width for improved hit testing.
21656    ///
21657    /// Use this method to disable this for cases where this is not wanted (e.g.
21658    /// if you want to align the editor text with some other text above or below)
21659    /// or if you want to add this padding to single-line editors.
21660    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21661        self.offset_content = offset_content;
21662        cx.notify();
21663    }
21664
21665    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21666        self.show_line_numbers = Some(show_line_numbers);
21667        cx.notify();
21668    }
21669
21670    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21671        self.disable_expand_excerpt_buttons = true;
21672        cx.notify();
21673    }
21674
21675    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21676        self.number_deleted_lines = number;
21677        cx.notify();
21678    }
21679
21680    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21681        self.delegate_expand_excerpts = delegate;
21682    }
21683
21684    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21685        self.delegate_stage_and_restore = delegate;
21686    }
21687
21688    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21689        self.delegate_open_excerpts = delegate;
21690    }
21691
21692    pub fn set_on_local_selections_changed(
21693        &mut self,
21694        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21695    ) {
21696        self.on_local_selections_changed = callback;
21697    }
21698
21699    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21700        self.suppress_selection_callback = suppress;
21701    }
21702
21703    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21704        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21705        cx.notify();
21706    }
21707
21708    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21709        self.show_code_actions = Some(show_code_actions);
21710        cx.notify();
21711    }
21712
21713    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21714        self.show_runnables = Some(show_runnables);
21715        cx.notify();
21716    }
21717
21718    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21719        self.show_breakpoints = Some(show_breakpoints);
21720        cx.notify();
21721    }
21722
21723    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21724        self.show_diff_review_button = show;
21725        cx.notify();
21726    }
21727
21728    pub fn show_diff_review_button(&self) -> bool {
21729        self.show_diff_review_button
21730    }
21731
21732    pub fn render_diff_review_button(
21733        &self,
21734        display_row: DisplayRow,
21735        width: Pixels,
21736        cx: &mut Context<Self>,
21737    ) -> impl IntoElement {
21738        let text_color = cx.theme().colors().text;
21739        let icon_color = cx.theme().colors().icon_accent;
21740
21741        h_flex()
21742            .id("diff_review_button")
21743            .cursor_pointer()
21744            .w(width - px(1.))
21745            .h(relative(0.9))
21746            .justify_center()
21747            .rounded_sm()
21748            .border_1()
21749            .border_color(text_color.opacity(0.1))
21750            .bg(text_color.opacity(0.15))
21751            .hover(|s| {
21752                s.bg(icon_color.opacity(0.4))
21753                    .border_color(icon_color.opacity(0.5))
21754            })
21755            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21756            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21757            .on_mouse_down(
21758                gpui::MouseButton::Left,
21759                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21760                    editor.start_diff_review_drag(display_row, window, cx);
21761                }),
21762            )
21763    }
21764
21765    pub fn start_diff_review_drag(
21766        &mut self,
21767        display_row: DisplayRow,
21768        window: &mut Window,
21769        cx: &mut Context<Self>,
21770    ) {
21771        let snapshot = self.snapshot(window, cx);
21772        let point = snapshot
21773            .display_snapshot
21774            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21775        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21776        self.diff_review_drag_state = Some(DiffReviewDragState {
21777            start_anchor: anchor,
21778            current_anchor: anchor,
21779        });
21780        cx.notify();
21781    }
21782
21783    pub fn update_diff_review_drag(
21784        &mut self,
21785        display_row: DisplayRow,
21786        window: &mut Window,
21787        cx: &mut Context<Self>,
21788    ) {
21789        if self.diff_review_drag_state.is_none() {
21790            return;
21791        }
21792        let snapshot = self.snapshot(window, cx);
21793        let point = snapshot
21794            .display_snapshot
21795            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21796        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21797        if let Some(drag_state) = &mut self.diff_review_drag_state {
21798            drag_state.current_anchor = anchor;
21799            cx.notify();
21800        }
21801    }
21802
21803    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21804        if let Some(drag_state) = self.diff_review_drag_state.take() {
21805            let snapshot = self.snapshot(window, cx);
21806            let range = drag_state.row_range(&snapshot.display_snapshot);
21807            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21808        }
21809        cx.notify();
21810    }
21811
21812    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21813        self.diff_review_drag_state = None;
21814        cx.notify();
21815    }
21816
21817    /// Calculates the appropriate block height for the diff review overlay.
21818    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21819    /// and 2 lines per comment when expanded.
21820    fn calculate_overlay_height(
21821        &self,
21822        hunk_key: &DiffHunkKey,
21823        comments_expanded: bool,
21824        snapshot: &MultiBufferSnapshot,
21825    ) -> u32 {
21826        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21827        let base_height: u32 = 2; // Input row with avatar and buttons
21828
21829        if comment_count == 0 {
21830            base_height
21831        } else if comments_expanded {
21832            // Header (1 line) + 2 lines per comment
21833            base_height + 1 + (comment_count as u32 * 2)
21834        } else {
21835            // Just header when collapsed
21836            base_height + 1
21837        }
21838    }
21839
21840    pub fn show_diff_review_overlay(
21841        &mut self,
21842        display_range: Range<DisplayRow>,
21843        window: &mut Window,
21844        cx: &mut Context<Self>,
21845    ) {
21846        let Range { start, end } = display_range.sorted();
21847
21848        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21849        let editor_snapshot = self.snapshot(window, cx);
21850
21851        // Convert display rows to multibuffer points
21852        let start_point = editor_snapshot
21853            .display_snapshot
21854            .display_point_to_point(start.as_display_point(), Bias::Left);
21855        let end_point = editor_snapshot
21856            .display_snapshot
21857            .display_point_to_point(end.as_display_point(), Bias::Left);
21858        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21859
21860        // Create anchor range for the selected lines (start of first line to end of last line)
21861        let line_end = Point::new(
21862            end_point.row,
21863            buffer_snapshot.line_len(end_multi_buffer_row),
21864        );
21865        let anchor_range =
21866            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21867
21868        // Compute the hunk key for this display row
21869        let file_path = buffer_snapshot
21870            .file_at(start_point)
21871            .map(|file: &Arc<dyn language::File>| file.path().clone())
21872            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21873        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21874        let new_hunk_key = DiffHunkKey {
21875            file_path,
21876            hunk_start_anchor,
21877        };
21878
21879        // Check if we already have an overlay for this hunk
21880        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21881            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21882        }) {
21883            // Just focus the existing overlay's prompt editor
21884            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21885            window.focus(&focus_handle, cx);
21886            return;
21887        }
21888
21889        // Dismiss overlays that have no comments for their hunks
21890        self.dismiss_overlays_without_comments(cx);
21891
21892        // Get the current user's avatar URI from the project's user_store
21893        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21894            let user_store = project.read(cx).user_store();
21895            user_store
21896                .read(cx)
21897                .current_user()
21898                .map(|user| user.avatar_uri.clone())
21899        });
21900
21901        // Create anchor at the end of the last row so the block appears immediately below it
21902        // Use multibuffer coordinates for anchor creation
21903        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21904        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21905
21906        // Use the hunk key we already computed
21907        let hunk_key = new_hunk_key;
21908
21909        // Create the prompt editor for the review input
21910        let prompt_editor = cx.new(|cx| {
21911            let mut editor = Editor::single_line(window, cx);
21912            editor.set_placeholder_text("Add a review comment...", window, cx);
21913            editor
21914        });
21915
21916        // Register the Newline action on the prompt editor to submit the review
21917        let parent_editor = cx.entity().downgrade();
21918        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21919            prompt_editor.register_action({
21920                let parent_editor = parent_editor.clone();
21921                move |_: &crate::actions::Newline, window, cx| {
21922                    if let Some(editor) = parent_editor.upgrade() {
21923                        editor.update(cx, |editor, cx| {
21924                            editor.submit_diff_review_comment(window, cx);
21925                        });
21926                    }
21927                }
21928            })
21929        });
21930
21931        // Calculate initial height based on existing comments for this hunk
21932        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21933
21934        // Create the overlay block
21935        let prompt_editor_for_render = prompt_editor.clone();
21936        let hunk_key_for_render = hunk_key.clone();
21937        let editor_handle = cx.entity().downgrade();
21938        let block = BlockProperties {
21939            style: BlockStyle::Sticky,
21940            placement: BlockPlacement::Below(anchor),
21941            height: Some(initial_height),
21942            render: Arc::new(move |cx| {
21943                Self::render_diff_review_overlay(
21944                    &prompt_editor_for_render,
21945                    &hunk_key_for_render,
21946                    &editor_handle,
21947                    cx,
21948                )
21949            }),
21950            priority: 0,
21951        };
21952
21953        let block_ids = self.insert_blocks([block], None, cx);
21954        let Some(block_id) = block_ids.into_iter().next() else {
21955            log::error!("Failed to insert diff review overlay block");
21956            return;
21957        };
21958
21959        self.diff_review_overlays.push(DiffReviewOverlay {
21960            anchor_range,
21961            block_id,
21962            prompt_editor: prompt_editor.clone(),
21963            hunk_key,
21964            comments_expanded: true,
21965            inline_edit_editors: HashMap::default(),
21966            inline_edit_subscriptions: HashMap::default(),
21967            user_avatar_uri,
21968            _subscription: subscription,
21969        });
21970
21971        // Focus the prompt editor
21972        let focus_handle = prompt_editor.focus_handle(cx);
21973        window.focus(&focus_handle, cx);
21974
21975        cx.notify();
21976    }
21977
21978    /// Dismisses all diff review overlays.
21979    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21980        if self.diff_review_overlays.is_empty() {
21981            return;
21982        }
21983        let block_ids: HashSet<_> = self
21984            .diff_review_overlays
21985            .drain(..)
21986            .map(|overlay| overlay.block_id)
21987            .collect();
21988        self.remove_blocks(block_ids, None, cx);
21989        cx.notify();
21990    }
21991
21992    /// Dismisses overlays that have no comments stored for their hunks.
21993    /// Keeps overlays that have at least one comment.
21994    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21995        let snapshot = self.buffer.read(cx).snapshot(cx);
21996
21997        // First, compute which overlays have comments (to avoid borrow issues with retain)
21998        let overlays_with_comments: Vec<bool> = self
21999            .diff_review_overlays
22000            .iter()
22001            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
22002            .collect();
22003
22004        // Now collect block IDs to remove and retain overlays
22005        let mut block_ids_to_remove = HashSet::default();
22006        let mut index = 0;
22007        self.diff_review_overlays.retain(|overlay| {
22008            let has_comments = overlays_with_comments[index];
22009            index += 1;
22010            if !has_comments {
22011                block_ids_to_remove.insert(overlay.block_id);
22012            }
22013            has_comments
22014        });
22015
22016        if !block_ids_to_remove.is_empty() {
22017            self.remove_blocks(block_ids_to_remove, None, cx);
22018            cx.notify();
22019        }
22020    }
22021
22022    /// Refreshes the diff review overlay block to update its height and render function.
22023    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
22024    fn refresh_diff_review_overlay_height(
22025        &mut self,
22026        hunk_key: &DiffHunkKey,
22027        _window: &mut Window,
22028        cx: &mut Context<Self>,
22029    ) {
22030        // Extract all needed data from overlay first to avoid borrow conflicts
22031        let snapshot = self.buffer.read(cx).snapshot(cx);
22032        let (comments_expanded, block_id, prompt_editor) = {
22033            let Some(overlay) = self
22034                .diff_review_overlays
22035                .iter()
22036                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22037            else {
22038                return;
22039            };
22040
22041            (
22042                overlay.comments_expanded,
22043                overlay.block_id,
22044                overlay.prompt_editor.clone(),
22045            )
22046        };
22047
22048        // Calculate new height
22049        let snapshot = self.buffer.read(cx).snapshot(cx);
22050        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
22051
22052        // Update the block height using resize_blocks (avoids flicker)
22053        let mut heights = HashMap::default();
22054        heights.insert(block_id, new_height);
22055        self.resize_blocks(heights, None, cx);
22056
22057        // Update the render function using replace_blocks (avoids flicker)
22058        let hunk_key_for_render = hunk_key.clone();
22059        let editor_handle = cx.entity().downgrade();
22060        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
22061            Arc::new(move |cx| {
22062                Self::render_diff_review_overlay(
22063                    &prompt_editor,
22064                    &hunk_key_for_render,
22065                    &editor_handle,
22066                    cx,
22067                )
22068            });
22069
22070        let mut renderers = HashMap::default();
22071        renderers.insert(block_id, render);
22072        self.replace_blocks(renderers, None, cx);
22073    }
22074
22075    /// Action handler for SubmitDiffReviewComment.
22076    pub fn submit_diff_review_comment_action(
22077        &mut self,
22078        _: &SubmitDiffReviewComment,
22079        window: &mut Window,
22080        cx: &mut Context<Self>,
22081    ) {
22082        self.submit_diff_review_comment(window, cx);
22083    }
22084
22085    /// Stores the diff review comment locally.
22086    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22087    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22088        // Find the overlay that currently has focus
22089        let overlay_index = self
22090            .diff_review_overlays
22091            .iter()
22092            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22093        let Some(overlay_index) = overlay_index else {
22094            return;
22095        };
22096        let overlay = &self.diff_review_overlays[overlay_index];
22097
22098        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22099        if comment_text.is_empty() {
22100            return;
22101        }
22102
22103        let anchor_range = overlay.anchor_range.clone();
22104        let hunk_key = overlay.hunk_key.clone();
22105
22106        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22107
22108        // Clear the prompt editor but keep the overlay open
22109        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22110            overlay.prompt_editor.update(cx, |editor, cx| {
22111                editor.clear(window, cx);
22112            });
22113        }
22114
22115        // Refresh the overlay to update the block height for the new comment
22116        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22117
22118        cx.notify();
22119    }
22120
22121    /// Returns the prompt editor for the diff review overlay, if one is active.
22122    /// This is primarily used for testing.
22123    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22124        self.diff_review_overlays
22125            .first()
22126            .map(|overlay| &overlay.prompt_editor)
22127    }
22128
22129    /// Returns the line range for the first diff review overlay, if one is active.
22130    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22131    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22132        let overlay = self.diff_review_overlays.first()?;
22133        let snapshot = self.buffer.read(cx).snapshot(cx);
22134        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22135        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22136        let start_row = snapshot
22137            .point_to_buffer_point(start_point)
22138            .map(|(_, p)| p.row)
22139            .unwrap_or(start_point.row);
22140        let end_row = snapshot
22141            .point_to_buffer_point(end_point)
22142            .map(|(_, p)| p.row)
22143            .unwrap_or(end_point.row);
22144        Some((start_row, end_row))
22145    }
22146
22147    /// Sets whether the comments section is expanded in the diff review overlay.
22148    /// This is primarily used for testing.
22149    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22150        for overlay in &mut self.diff_review_overlays {
22151            overlay.comments_expanded = expanded;
22152        }
22153        cx.notify();
22154    }
22155
22156    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22157    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22158        a.file_path == b.file_path
22159            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22160    }
22161
22162    /// Returns comments for a specific hunk, ordered by creation time.
22163    pub fn comments_for_hunk<'a>(
22164        &'a self,
22165        key: &DiffHunkKey,
22166        snapshot: &MultiBufferSnapshot,
22167    ) -> &'a [StoredReviewComment] {
22168        let key_point = key.hunk_start_anchor.to_point(snapshot);
22169        self.stored_review_comments
22170            .iter()
22171            .find(|(k, _)| {
22172                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22173            })
22174            .map(|(_, comments)| comments.as_slice())
22175            .unwrap_or(&[])
22176    }
22177
22178    /// Returns the total count of stored review comments across all hunks.
22179    pub fn total_review_comment_count(&self) -> usize {
22180        self.stored_review_comments
22181            .iter()
22182            .map(|(_, v)| v.len())
22183            .sum()
22184    }
22185
22186    /// Returns the count of comments for a specific hunk.
22187    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22188        let key_point = key.hunk_start_anchor.to_point(snapshot);
22189        self.stored_review_comments
22190            .iter()
22191            .find(|(k, _)| {
22192                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22193            })
22194            .map(|(_, v)| v.len())
22195            .unwrap_or(0)
22196    }
22197
22198    /// Adds a new review comment to a specific hunk.
22199    pub fn add_review_comment(
22200        &mut self,
22201        hunk_key: DiffHunkKey,
22202        comment: String,
22203        anchor_range: Range<Anchor>,
22204        cx: &mut Context<Self>,
22205    ) -> usize {
22206        let id = self.next_review_comment_id;
22207        self.next_review_comment_id += 1;
22208
22209        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22210
22211        let snapshot = self.buffer.read(cx).snapshot(cx);
22212        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22213
22214        // Find existing entry for this hunk or add a new one
22215        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22216            k.file_path == hunk_key.file_path
22217                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22218        }) {
22219            comments.push(stored_comment);
22220        } else {
22221            self.stored_review_comments
22222                .push((hunk_key, vec![stored_comment]));
22223        }
22224
22225        cx.emit(EditorEvent::ReviewCommentsChanged {
22226            total_count: self.total_review_comment_count(),
22227        });
22228        cx.notify();
22229        id
22230    }
22231
22232    /// Removes a review comment by ID from any hunk.
22233    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22234        for (_, comments) in self.stored_review_comments.iter_mut() {
22235            if let Some(index) = comments.iter().position(|c| c.id == id) {
22236                comments.remove(index);
22237                cx.emit(EditorEvent::ReviewCommentsChanged {
22238                    total_count: self.total_review_comment_count(),
22239                });
22240                cx.notify();
22241                return true;
22242            }
22243        }
22244        false
22245    }
22246
22247    /// Updates a review comment's text by ID.
22248    pub fn update_review_comment(
22249        &mut self,
22250        id: usize,
22251        new_comment: String,
22252        cx: &mut Context<Self>,
22253    ) -> bool {
22254        for (_, comments) in self.stored_review_comments.iter_mut() {
22255            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22256                comment.comment = new_comment;
22257                comment.is_editing = false;
22258                cx.emit(EditorEvent::ReviewCommentsChanged {
22259                    total_count: self.total_review_comment_count(),
22260                });
22261                cx.notify();
22262                return true;
22263            }
22264        }
22265        false
22266    }
22267
22268    /// Sets a comment's editing state.
22269    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22270        for (_, comments) in self.stored_review_comments.iter_mut() {
22271            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22272                comment.is_editing = is_editing;
22273                cx.notify();
22274                return;
22275            }
22276        }
22277    }
22278
22279    /// Takes all stored comments from all hunks, clearing the storage.
22280    /// Returns a Vec of (hunk_key, comments) pairs.
22281    pub fn take_all_review_comments(
22282        &mut self,
22283        cx: &mut Context<Self>,
22284    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22285        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22286        self.dismiss_all_diff_review_overlays(cx);
22287        let comments = std::mem::take(&mut self.stored_review_comments);
22288        // Reset the ID counter since all comments have been taken
22289        self.next_review_comment_id = 0;
22290        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22291        cx.notify();
22292        comments
22293    }
22294
22295    /// Removes review comments whose anchors are no longer valid or whose
22296    /// associated diff hunks no longer exist.
22297    ///
22298    /// This should be called when the buffer changes to prevent orphaned comments
22299    /// from accumulating.
22300    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22301        let snapshot = self.buffer.read(cx).snapshot(cx);
22302        let original_count = self.total_review_comment_count();
22303
22304        // Remove comments with invalid hunk anchors
22305        self.stored_review_comments
22306            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22307
22308        // Also clean up individual comments with invalid anchor ranges
22309        for (_, comments) in &mut self.stored_review_comments {
22310            comments.retain(|comment| {
22311                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22312            });
22313        }
22314
22315        // Remove empty hunk entries
22316        self.stored_review_comments
22317            .retain(|(_, comments)| !comments.is_empty());
22318
22319        let new_count = self.total_review_comment_count();
22320        if new_count != original_count {
22321            cx.emit(EditorEvent::ReviewCommentsChanged {
22322                total_count: new_count,
22323            });
22324            cx.notify();
22325        }
22326    }
22327
22328    /// Toggles the expanded state of the comments section in the overlay.
22329    pub fn toggle_review_comments_expanded(
22330        &mut self,
22331        _: &ToggleReviewCommentsExpanded,
22332        window: &mut Window,
22333        cx: &mut Context<Self>,
22334    ) {
22335        // Find the overlay that currently has focus, or use the first one
22336        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22337            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22338                overlay.comments_expanded = !overlay.comments_expanded;
22339                Some(overlay.hunk_key.clone())
22340            } else {
22341                None
22342            }
22343        });
22344
22345        // If no focused overlay found, toggle the first one
22346        let hunk_key = overlay_info.or_else(|| {
22347            self.diff_review_overlays.first_mut().map(|overlay| {
22348                overlay.comments_expanded = !overlay.comments_expanded;
22349                overlay.hunk_key.clone()
22350            })
22351        });
22352
22353        if let Some(hunk_key) = hunk_key {
22354            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22355            cx.notify();
22356        }
22357    }
22358
22359    /// Handles the EditReviewComment action - sets a comment into editing mode.
22360    pub fn edit_review_comment(
22361        &mut self,
22362        action: &EditReviewComment,
22363        window: &mut Window,
22364        cx: &mut Context<Self>,
22365    ) {
22366        let comment_id = action.id;
22367
22368        // Set the comment to editing mode
22369        self.set_comment_editing(comment_id, true, cx);
22370
22371        // Find the overlay that contains this comment and create an inline editor if needed
22372        // First, find which hunk this comment belongs to
22373        let hunk_key = self
22374            .stored_review_comments
22375            .iter()
22376            .find_map(|(key, comments)| {
22377                if comments.iter().any(|c| c.id == comment_id) {
22378                    Some(key.clone())
22379                } else {
22380                    None
22381                }
22382            });
22383
22384        let snapshot = self.buffer.read(cx).snapshot(cx);
22385        if let Some(hunk_key) = hunk_key {
22386            if let Some(overlay) = self
22387                .diff_review_overlays
22388                .iter_mut()
22389                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22390            {
22391                if let std::collections::hash_map::Entry::Vacant(entry) =
22392                    overlay.inline_edit_editors.entry(comment_id)
22393                {
22394                    // Find the comment text
22395                    let comment_text = self
22396                        .stored_review_comments
22397                        .iter()
22398                        .flat_map(|(_, comments)| comments)
22399                        .find(|c| c.id == comment_id)
22400                        .map(|c| c.comment.clone())
22401                        .unwrap_or_default();
22402
22403                    // Create inline editor
22404                    let parent_editor = cx.entity().downgrade();
22405                    let inline_editor = cx.new(|cx| {
22406                        let mut editor = Editor::single_line(window, cx);
22407                        editor.set_text(&*comment_text, window, cx);
22408                        // Select all text for easy replacement
22409                        editor.select_all(&crate::actions::SelectAll, window, cx);
22410                        editor
22411                    });
22412
22413                    // Register the Newline action to confirm the edit
22414                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22415                        inline_editor.register_action({
22416                            let parent_editor = parent_editor.clone();
22417                            move |_: &crate::actions::Newline, window, cx| {
22418                                if let Some(editor) = parent_editor.upgrade() {
22419                                    editor.update(cx, |editor, cx| {
22420                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22421                                    });
22422                                }
22423                            }
22424                        })
22425                    });
22426
22427                    // Store the subscription to keep the action handler alive
22428                    overlay
22429                        .inline_edit_subscriptions
22430                        .insert(comment_id, subscription);
22431
22432                    // Focus the inline editor
22433                    let focus_handle = inline_editor.focus_handle(cx);
22434                    window.focus(&focus_handle, cx);
22435
22436                    entry.insert(inline_editor);
22437                }
22438            }
22439        }
22440
22441        cx.notify();
22442    }
22443
22444    /// Confirms an inline edit of a review comment.
22445    pub fn confirm_edit_review_comment(
22446        &mut self,
22447        comment_id: usize,
22448        _window: &mut Window,
22449        cx: &mut Context<Self>,
22450    ) {
22451        // Get the new text from the inline editor
22452        // Find the overlay containing this comment's inline editor
22453        let snapshot = self.buffer.read(cx).snapshot(cx);
22454        let hunk_key = self
22455            .stored_review_comments
22456            .iter()
22457            .find_map(|(key, comments)| {
22458                if comments.iter().any(|c| c.id == comment_id) {
22459                    Some(key.clone())
22460                } else {
22461                    None
22462                }
22463            });
22464
22465        let new_text = hunk_key
22466            .as_ref()
22467            .and_then(|hunk_key| {
22468                self.diff_review_overlays
22469                    .iter()
22470                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22471            })
22472            .as_ref()
22473            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22474            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22475
22476        if let Some(new_text) = new_text {
22477            if !new_text.is_empty() {
22478                self.update_review_comment(comment_id, new_text, cx);
22479            }
22480        }
22481
22482        // Remove the inline editor and its subscription
22483        if let Some(hunk_key) = hunk_key {
22484            if let Some(overlay) = self
22485                .diff_review_overlays
22486                .iter_mut()
22487                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22488            {
22489                overlay.inline_edit_editors.remove(&comment_id);
22490                overlay.inline_edit_subscriptions.remove(&comment_id);
22491            }
22492        }
22493
22494        // Clear editing state
22495        self.set_comment_editing(comment_id, false, cx);
22496    }
22497
22498    /// Cancels an inline edit of a review comment.
22499    pub fn cancel_edit_review_comment(
22500        &mut self,
22501        comment_id: usize,
22502        _window: &mut Window,
22503        cx: &mut Context<Self>,
22504    ) {
22505        // Find which hunk this comment belongs to
22506        let hunk_key = self
22507            .stored_review_comments
22508            .iter()
22509            .find_map(|(key, comments)| {
22510                if comments.iter().any(|c| c.id == comment_id) {
22511                    Some(key.clone())
22512                } else {
22513                    None
22514                }
22515            });
22516
22517        // Remove the inline editor and its subscription
22518        if let Some(hunk_key) = hunk_key {
22519            let snapshot = self.buffer.read(cx).snapshot(cx);
22520            if let Some(overlay) = self
22521                .diff_review_overlays
22522                .iter_mut()
22523                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22524            {
22525                overlay.inline_edit_editors.remove(&comment_id);
22526                overlay.inline_edit_subscriptions.remove(&comment_id);
22527            }
22528        }
22529
22530        // Clear editing state
22531        self.set_comment_editing(comment_id, false, cx);
22532    }
22533
22534    /// Action handler for ConfirmEditReviewComment.
22535    pub fn confirm_edit_review_comment_action(
22536        &mut self,
22537        action: &ConfirmEditReviewComment,
22538        window: &mut Window,
22539        cx: &mut Context<Self>,
22540    ) {
22541        self.confirm_edit_review_comment(action.id, window, cx);
22542    }
22543
22544    /// Action handler for CancelEditReviewComment.
22545    pub fn cancel_edit_review_comment_action(
22546        &mut self,
22547        action: &CancelEditReviewComment,
22548        window: &mut Window,
22549        cx: &mut Context<Self>,
22550    ) {
22551        self.cancel_edit_review_comment(action.id, window, cx);
22552    }
22553
22554    /// Handles the DeleteReviewComment action - removes a comment.
22555    pub fn delete_review_comment(
22556        &mut self,
22557        action: &DeleteReviewComment,
22558        window: &mut Window,
22559        cx: &mut Context<Self>,
22560    ) {
22561        // Get the hunk key before removing the comment
22562        // Find the hunk key from the comment itself
22563        let comment_id = action.id;
22564        let hunk_key = self
22565            .stored_review_comments
22566            .iter()
22567            .find_map(|(key, comments)| {
22568                if comments.iter().any(|c| c.id == comment_id) {
22569                    Some(key.clone())
22570                } else {
22571                    None
22572                }
22573            });
22574
22575        // Also get it from the overlay for refresh purposes
22576        let overlay_hunk_key = self
22577            .diff_review_overlays
22578            .first()
22579            .map(|o| o.hunk_key.clone());
22580
22581        self.remove_review_comment(action.id, cx);
22582
22583        // Refresh the overlay height after removing a comment
22584        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22585            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22586        }
22587    }
22588
22589    fn render_diff_review_overlay(
22590        prompt_editor: &Entity<Editor>,
22591        hunk_key: &DiffHunkKey,
22592        editor_handle: &WeakEntity<Editor>,
22593        cx: &mut BlockContext,
22594    ) -> AnyElement {
22595        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22596            if ranges.is_empty() {
22597                return None;
22598            }
22599            let formatted: Vec<String> = ranges
22600                .iter()
22601                .map(|(start, end)| {
22602                    let start_line = start + 1;
22603                    let end_line = end + 1;
22604                    if start_line == end_line {
22605                        format!("Line {start_line}")
22606                    } else {
22607                        format!("Lines {start_line}-{end_line}")
22608                    }
22609                })
22610                .collect();
22611            // Don't show label for single line in single excerpt
22612            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22613                return None;
22614            }
22615            Some(formatted.join(""))
22616        }
22617
22618        let theme = cx.theme();
22619        let colors = theme.colors();
22620
22621        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22622            editor_handle
22623                .upgrade()
22624                .map(|editor| {
22625                    let editor = editor.read(cx);
22626                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22627                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22628                    let (expanded, editors, avatar_uri, line_ranges) = editor
22629                        .diff_review_overlays
22630                        .iter()
22631                        .find(|overlay| {
22632                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22633                        })
22634                        .map(|o| {
22635                            let start_point = o.anchor_range.start.to_point(&snapshot);
22636                            let end_point = o.anchor_range.end.to_point(&snapshot);
22637                            // Get line ranges per excerpt to detect discontinuities
22638                            let buffer_ranges =
22639                                snapshot.range_to_buffer_ranges(start_point..end_point);
22640                            let ranges: Vec<(u32, u32)> = buffer_ranges
22641                                .iter()
22642                                .map(|(buffer_snapshot, range, _)| {
22643                                    let start = buffer_snapshot.offset_to_point(range.start.0).row;
22644                                    let end = buffer_snapshot.offset_to_point(range.end.0).row;
22645                                    (start, end)
22646                                })
22647                                .collect();
22648                            (
22649                                o.comments_expanded,
22650                                o.inline_edit_editors.clone(),
22651                                o.user_avatar_uri.clone(),
22652                                if ranges.is_empty() {
22653                                    None
22654                                } else {
22655                                    Some(ranges)
22656                                },
22657                            )
22658                        })
22659                        .unwrap_or((true, HashMap::default(), None, None));
22660                    (comments, expanded, editors, avatar_uri, line_ranges)
22661                })
22662                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22663
22664        let comment_count = comments.len();
22665        let avatar_size = px(20.);
22666        let action_icon_size = IconSize::XSmall;
22667
22668        v_flex()
22669            .w_full()
22670            .bg(colors.editor_background)
22671            .border_b_1()
22672            .border_color(colors.border)
22673            .px_2()
22674            .pb_2()
22675            .gap_2()
22676            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22677            .when_some(line_ranges, |el, ranges| {
22678                let label = format_line_ranges(&ranges);
22679                if let Some(label) = label {
22680                    el.child(
22681                        h_flex()
22682                            .w_full()
22683                            .px_2()
22684                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22685                    )
22686                } else {
22687                    el
22688                }
22689            })
22690            // Top row: editable input with user's avatar
22691            .child(
22692                h_flex()
22693                    .w_full()
22694                    .items_center()
22695                    .gap_2()
22696                    .px_2()
22697                    .py_1p5()
22698                    .rounded_md()
22699                    .bg(colors.surface_background)
22700                    .child(
22701                        div()
22702                            .size(avatar_size)
22703                            .flex_shrink_0()
22704                            .rounded_full()
22705                            .overflow_hidden()
22706                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22707                                Avatar::new(avatar_uri.clone())
22708                                    .size(avatar_size)
22709                                    .into_any_element()
22710                            } else {
22711                                Icon::new(IconName::Person)
22712                                    .size(IconSize::Small)
22713                                    .color(ui::Color::Muted)
22714                                    .into_any_element()
22715                            }),
22716                    )
22717                    .child(
22718                        div()
22719                            .flex_1()
22720                            .border_1()
22721                            .border_color(colors.border)
22722                            .rounded_md()
22723                            .bg(colors.editor_background)
22724                            .px_2()
22725                            .py_1()
22726                            .child(prompt_editor.clone()),
22727                    )
22728                    .child(
22729                        h_flex()
22730                            .flex_shrink_0()
22731                            .gap_1()
22732                            .child(
22733                                IconButton::new("diff-review-close", IconName::Close)
22734                                    .icon_color(ui::Color::Muted)
22735                                    .icon_size(action_icon_size)
22736                                    .tooltip(Tooltip::text("Close"))
22737                                    .on_click(|_, window, cx| {
22738                                        window
22739                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22740                                    }),
22741                            )
22742                            .child(
22743                                IconButton::new("diff-review-add", IconName::Return)
22744                                    .icon_color(ui::Color::Muted)
22745                                    .icon_size(action_icon_size)
22746                                    .tooltip(Tooltip::text("Add comment"))
22747                                    .on_click(|_, window, cx| {
22748                                        window.dispatch_action(
22749                                            Box::new(crate::actions::SubmitDiffReviewComment),
22750                                            cx,
22751                                        );
22752                                    }),
22753                            ),
22754                    ),
22755            )
22756            // Expandable comments section (only shown when there are comments)
22757            .when(comment_count > 0, |el| {
22758                el.child(Self::render_comments_section(
22759                    comments,
22760                    comments_expanded,
22761                    inline_editors,
22762                    user_avatar_uri,
22763                    avatar_size,
22764                    action_icon_size,
22765                    colors,
22766                ))
22767            })
22768            .into_any_element()
22769    }
22770
22771    fn render_comments_section(
22772        comments: Vec<StoredReviewComment>,
22773        expanded: bool,
22774        inline_editors: HashMap<usize, Entity<Editor>>,
22775        user_avatar_uri: Option<SharedUri>,
22776        avatar_size: Pixels,
22777        action_icon_size: IconSize,
22778        colors: &theme::ThemeColors,
22779    ) -> impl IntoElement {
22780        let comment_count = comments.len();
22781
22782        v_flex()
22783            .w_full()
22784            .gap_1()
22785            // Header with expand/collapse toggle
22786            .child(
22787                h_flex()
22788                    .id("review-comments-header")
22789                    .w_full()
22790                    .items_center()
22791                    .gap_1()
22792                    .px_2()
22793                    .py_1()
22794                    .cursor_pointer()
22795                    .rounded_md()
22796                    .hover(|style| style.bg(colors.ghost_element_hover))
22797                    .on_click(|_, window: &mut Window, cx| {
22798                        window.dispatch_action(
22799                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22800                            cx,
22801                        );
22802                    })
22803                    .child(
22804                        Icon::new(if expanded {
22805                            IconName::ChevronDown
22806                        } else {
22807                            IconName::ChevronRight
22808                        })
22809                        .size(IconSize::Small)
22810                        .color(ui::Color::Muted),
22811                    )
22812                    .child(
22813                        Label::new(format!(
22814                            "{} Comment{}",
22815                            comment_count,
22816                            if comment_count == 1 { "" } else { "s" }
22817                        ))
22818                        .size(LabelSize::Small)
22819                        .color(Color::Muted),
22820                    ),
22821            )
22822            // Comments list (when expanded)
22823            .when(expanded, |el| {
22824                el.children(comments.into_iter().map(|comment| {
22825                    let inline_editor = inline_editors.get(&comment.id).cloned();
22826                    Self::render_comment_row(
22827                        comment,
22828                        inline_editor,
22829                        user_avatar_uri.clone(),
22830                        avatar_size,
22831                        action_icon_size,
22832                        colors,
22833                    )
22834                }))
22835            })
22836    }
22837
22838    fn render_comment_row(
22839        comment: StoredReviewComment,
22840        inline_editor: Option<Entity<Editor>>,
22841        user_avatar_uri: Option<SharedUri>,
22842        avatar_size: Pixels,
22843        action_icon_size: IconSize,
22844        colors: &theme::ThemeColors,
22845    ) -> impl IntoElement {
22846        let comment_id = comment.id;
22847        let is_editing = inline_editor.is_some();
22848
22849        h_flex()
22850            .w_full()
22851            .items_center()
22852            .gap_2()
22853            .px_2()
22854            .py_1p5()
22855            .rounded_md()
22856            .bg(colors.surface_background)
22857            .child(
22858                div()
22859                    .size(avatar_size)
22860                    .flex_shrink_0()
22861                    .rounded_full()
22862                    .overflow_hidden()
22863                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22864                        Avatar::new(avatar_uri.clone())
22865                            .size(avatar_size)
22866                            .into_any_element()
22867                    } else {
22868                        Icon::new(IconName::Person)
22869                            .size(IconSize::Small)
22870                            .color(ui::Color::Muted)
22871                            .into_any_element()
22872                    }),
22873            )
22874            .child(if let Some(editor) = inline_editor {
22875                // Inline edit mode: show an editable text field
22876                div()
22877                    .flex_1()
22878                    .border_1()
22879                    .border_color(colors.border)
22880                    .rounded_md()
22881                    .bg(colors.editor_background)
22882                    .px_2()
22883                    .py_1()
22884                    .child(editor)
22885                    .into_any_element()
22886            } else {
22887                // Display mode: show the comment text
22888                div()
22889                    .flex_1()
22890                    .text_sm()
22891                    .text_color(colors.text)
22892                    .child(comment.comment)
22893                    .into_any_element()
22894            })
22895            .child(if is_editing {
22896                // Editing mode: show close and confirm buttons
22897                h_flex()
22898                    .gap_1()
22899                    .child(
22900                        IconButton::new(
22901                            format!("diff-review-cancel-edit-{comment_id}"),
22902                            IconName::Close,
22903                        )
22904                        .icon_color(ui::Color::Muted)
22905                        .icon_size(action_icon_size)
22906                        .tooltip(Tooltip::text("Cancel"))
22907                        .on_click(move |_, window, cx| {
22908                            window.dispatch_action(
22909                                Box::new(crate::actions::CancelEditReviewComment {
22910                                    id: comment_id,
22911                                }),
22912                                cx,
22913                            );
22914                        }),
22915                    )
22916                    .child(
22917                        IconButton::new(
22918                            format!("diff-review-confirm-edit-{comment_id}"),
22919                            IconName::Return,
22920                        )
22921                        .icon_color(ui::Color::Muted)
22922                        .icon_size(action_icon_size)
22923                        .tooltip(Tooltip::text("Confirm"))
22924                        .on_click(move |_, window, cx| {
22925                            window.dispatch_action(
22926                                Box::new(crate::actions::ConfirmEditReviewComment {
22927                                    id: comment_id,
22928                                }),
22929                                cx,
22930                            );
22931                        }),
22932                    )
22933                    .into_any_element()
22934            } else {
22935                // Display mode: no action buttons for now (edit/delete not yet implemented)
22936                gpui::Empty.into_any_element()
22937            })
22938    }
22939
22940    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22941        if self.display_map.read(cx).masked != masked {
22942            self.display_map.update(cx, |map, _| map.masked = masked);
22943        }
22944        cx.notify()
22945    }
22946
22947    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22948        self.show_wrap_guides = Some(show_wrap_guides);
22949        cx.notify();
22950    }
22951
22952    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22953        self.show_indent_guides = Some(show_indent_guides);
22954        cx.notify();
22955    }
22956
22957    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22958        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22959            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22960                && let Some(dir) = file.abs_path(cx).parent()
22961            {
22962                return Some(dir.to_owned());
22963            }
22964        }
22965
22966        None
22967    }
22968
22969    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22970        self.active_buffer(cx)?
22971            .read(cx)
22972            .file()
22973            .and_then(|f| f.as_local())
22974    }
22975
22976    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22977        self.active_buffer(cx).and_then(|buffer| {
22978            let buffer = buffer.read(cx);
22979            if let Some(project_path) = buffer.project_path(cx) {
22980                let project = self.project()?.read(cx);
22981                project.absolute_path(&project_path, cx)
22982            } else {
22983                buffer
22984                    .file()
22985                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22986            }
22987        })
22988    }
22989
22990    pub fn reveal_in_finder(
22991        &mut self,
22992        _: &RevealInFileManager,
22993        _window: &mut Window,
22994        cx: &mut Context<Self>,
22995    ) {
22996        if let Some(path) = self.target_file_abs_path(cx) {
22997            if let Some(project) = self.project() {
22998                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22999            } else {
23000                cx.reveal_path(&path);
23001            }
23002        }
23003    }
23004
23005    pub fn copy_path(
23006        &mut self,
23007        _: &zed_actions::workspace::CopyPath,
23008        _window: &mut Window,
23009        cx: &mut Context<Self>,
23010    ) {
23011        if let Some(path) = self.target_file_abs_path(cx)
23012            && let Some(path) = path.to_str()
23013        {
23014            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23015        } else {
23016            cx.propagate();
23017        }
23018    }
23019
23020    pub fn copy_relative_path(
23021        &mut self,
23022        _: &zed_actions::workspace::CopyRelativePath,
23023        _window: &mut Window,
23024        cx: &mut Context<Self>,
23025    ) {
23026        if let Some(path) = self.active_buffer(cx).and_then(|buffer| {
23027            let project = self.project()?.read(cx);
23028            let path = buffer.read(cx).file()?.path();
23029            let path = path.display(project.path_style(cx));
23030            Some(path)
23031        }) {
23032            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23033        } else {
23034            cx.propagate();
23035        }
23036    }
23037
23038    /// Returns the project path for the editor's buffer, if any buffer is
23039    /// opened in the editor.
23040    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
23041        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
23042            buffer.read(cx).project_path(cx)
23043        } else {
23044            None
23045        }
23046    }
23047
23048    // Returns true if the editor handled a go-to-line request
23049    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
23050        maybe!({
23051            let breakpoint_store = self.breakpoint_store.as_ref()?;
23052
23053            let (active_stack_frame, debug_line_pane_id) = {
23054                let store = breakpoint_store.read(cx);
23055                let active_stack_frame = store.active_position().cloned();
23056                let debug_line_pane_id = store.active_debug_line_pane_id();
23057                (active_stack_frame, debug_line_pane_id)
23058            };
23059
23060            let Some(active_stack_frame) = active_stack_frame else {
23061                self.clear_row_highlights::<ActiveDebugLine>();
23062                return None;
23063            };
23064
23065            if let Some(debug_line_pane_id) = debug_line_pane_id {
23066                if let Some(workspace) = self
23067                    .workspace
23068                    .as_ref()
23069                    .and_then(|(workspace, _)| workspace.upgrade())
23070                {
23071                    let editor_pane_id = workspace
23072                        .read(cx)
23073                        .pane_for_item_id(cx.entity_id())
23074                        .map(|pane| pane.entity_id());
23075
23076                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
23077                        self.clear_row_highlights::<ActiveDebugLine>();
23078                        return None;
23079                    }
23080                }
23081            }
23082
23083            let position = active_stack_frame.position;
23084
23085            let snapshot = self.buffer.read(cx).snapshot(cx);
23086            let multibuffer_anchor = snapshot.anchor_in_excerpt(position)?;
23087
23088            self.clear_row_highlights::<ActiveDebugLine>();
23089
23090            self.go_to_line::<ActiveDebugLine>(
23091                multibuffer_anchor,
23092                Some(cx.theme().colors().editor_debugger_active_line_background),
23093                window,
23094                cx,
23095            );
23096
23097            cx.notify();
23098
23099            Some(())
23100        })
23101        .is_some()
23102    }
23103
23104    pub fn copy_file_name_without_extension(
23105        &mut self,
23106        _: &CopyFileNameWithoutExtension,
23107        _: &mut Window,
23108        cx: &mut Context<Self>,
23109    ) {
23110        if let Some(file_stem) = self.active_buffer(cx).and_then(|buffer| {
23111            let file = buffer.read(cx).file()?;
23112            file.path().file_stem()
23113        }) {
23114            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23115        }
23116    }
23117
23118    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23119        if let Some(file_name) = self.active_buffer(cx).and_then(|buffer| {
23120            let file = buffer.read(cx).file()?;
23121            Some(file.file_name(cx))
23122        }) {
23123            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23124        }
23125    }
23126
23127    pub fn toggle_git_blame(
23128        &mut self,
23129        _: &::git::Blame,
23130        window: &mut Window,
23131        cx: &mut Context<Self>,
23132    ) {
23133        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23134
23135        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23136            self.start_git_blame(true, window, cx);
23137        }
23138
23139        cx.notify();
23140    }
23141
23142    pub fn toggle_git_blame_inline(
23143        &mut self,
23144        _: &ToggleGitBlameInline,
23145        window: &mut Window,
23146        cx: &mut Context<Self>,
23147    ) {
23148        self.toggle_git_blame_inline_internal(true, window, cx);
23149        cx.notify();
23150    }
23151
23152    pub fn open_git_blame_commit(
23153        &mut self,
23154        _: &OpenGitBlameCommit,
23155        window: &mut Window,
23156        cx: &mut Context<Self>,
23157    ) {
23158        self.open_git_blame_commit_internal(window, cx);
23159    }
23160
23161    fn open_git_blame_commit_internal(
23162        &mut self,
23163        window: &mut Window,
23164        cx: &mut Context<Self>,
23165    ) -> Option<()> {
23166        let blame = self.blame.as_ref()?;
23167        let snapshot = self.snapshot(window, cx);
23168        let cursor = self
23169            .selections
23170            .newest::<Point>(&snapshot.display_snapshot)
23171            .head();
23172        let (buffer, point) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23173        let (_, blame_entry) = blame
23174            .update(cx, |blame, cx| {
23175                blame
23176                    .blame_for_rows(
23177                        &[RowInfo {
23178                            buffer_id: Some(buffer.remote_id()),
23179                            buffer_row: Some(point.row),
23180                            ..Default::default()
23181                        }],
23182                        cx,
23183                    )
23184                    .next()
23185            })
23186            .flatten()?;
23187        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23188        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23189        let workspace = self.workspace()?.downgrade();
23190        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23191        None
23192    }
23193
23194    pub fn git_blame_inline_enabled(&self) -> bool {
23195        self.git_blame_inline_enabled
23196    }
23197
23198    pub fn toggle_selection_menu(
23199        &mut self,
23200        _: &ToggleSelectionMenu,
23201        _: &mut Window,
23202        cx: &mut Context<Self>,
23203    ) {
23204        self.show_selection_menu = self
23205            .show_selection_menu
23206            .map(|show_selections_menu| !show_selections_menu)
23207            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23208
23209        cx.notify();
23210    }
23211
23212    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23213        self.show_selection_menu
23214            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23215    }
23216
23217    fn start_git_blame(
23218        &mut self,
23219        user_triggered: bool,
23220        window: &mut Window,
23221        cx: &mut Context<Self>,
23222    ) {
23223        if let Some(project) = self.project() {
23224            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23225                && buffer.read(cx).file().is_none()
23226            {
23227                return;
23228            }
23229
23230            let focused = self.focus_handle(cx).contains_focused(window, cx);
23231
23232            let project = project.clone();
23233            let blame = cx
23234                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23235            self.blame_subscription =
23236                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23237            self.blame = Some(blame);
23238        }
23239    }
23240
23241    fn toggle_git_blame_inline_internal(
23242        &mut self,
23243        user_triggered: bool,
23244        window: &mut Window,
23245        cx: &mut Context<Self>,
23246    ) {
23247        if self.git_blame_inline_enabled {
23248            self.git_blame_inline_enabled = false;
23249            self.show_git_blame_inline = false;
23250            self.show_git_blame_inline_delay_task.take();
23251        } else {
23252            self.git_blame_inline_enabled = true;
23253            self.start_git_blame_inline(user_triggered, window, cx);
23254        }
23255
23256        cx.notify();
23257    }
23258
23259    fn start_git_blame_inline(
23260        &mut self,
23261        user_triggered: bool,
23262        window: &mut Window,
23263        cx: &mut Context<Self>,
23264    ) {
23265        self.start_git_blame(user_triggered, window, cx);
23266
23267        if ProjectSettings::get_global(cx)
23268            .git
23269            .inline_blame_delay()
23270            .is_some()
23271        {
23272            self.start_inline_blame_timer(window, cx);
23273        } else {
23274            self.show_git_blame_inline = true
23275        }
23276    }
23277
23278    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23279        self.blame.as_ref()
23280    }
23281
23282    pub fn show_git_blame_gutter(&self) -> bool {
23283        self.show_git_blame_gutter
23284    }
23285
23286    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23287        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23288    }
23289
23290    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23291        self.show_git_blame_inline
23292            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23293            && !self.newest_selection_head_on_empty_line(cx)
23294            && self.has_blame_entries(cx)
23295    }
23296
23297    fn has_blame_entries(&self, cx: &App) -> bool {
23298        self.blame()
23299            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23300    }
23301
23302    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23303        let cursor_anchor = self.selections.newest_anchor().head();
23304
23305        let snapshot = self.buffer.read(cx).snapshot(cx);
23306        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23307
23308        snapshot.line_len(buffer_row) == 0
23309    }
23310
23311    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23312        let buffer_and_selection = maybe!({
23313            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23314            let selection_range = selection.range();
23315
23316            let multi_buffer = self.buffer().read(cx);
23317            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23318            let buffer_ranges = multi_buffer_snapshot
23319                .range_to_buffer_ranges(selection_range.start..selection_range.end);
23320
23321            let (buffer_snapshot, range, _) = if selection.reversed {
23322                buffer_ranges.first()
23323            } else {
23324                buffer_ranges.last()
23325            }?;
23326
23327            let buffer_range = range.to_point(buffer_snapshot);
23328            let buffer = multi_buffer.buffer(buffer_snapshot.remote_id()).unwrap();
23329
23330            let Some(buffer_diff) = multi_buffer.diff_for(buffer_snapshot.remote_id()) else {
23331                return Some((buffer, buffer_range.start.row..buffer_range.end.row));
23332            };
23333
23334            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23335            let start = buffer_diff_snapshot
23336                .buffer_point_to_base_text_point(buffer_range.start, &buffer_snapshot);
23337            let end = buffer_diff_snapshot
23338                .buffer_point_to_base_text_point(buffer_range.end, &buffer_snapshot);
23339
23340            Some((buffer, start.row..end.row))
23341        });
23342
23343        let Some((buffer, selection)) = buffer_and_selection else {
23344            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23345        };
23346
23347        let Some(project) = self.project() else {
23348            return Task::ready(Err(anyhow!("editor does not have project")));
23349        };
23350
23351        project.update(cx, |project, cx| {
23352            project.get_permalink_to_line(&buffer, selection, cx)
23353        })
23354    }
23355
23356    pub fn copy_permalink_to_line(
23357        &mut self,
23358        _: &CopyPermalinkToLine,
23359        window: &mut Window,
23360        cx: &mut Context<Self>,
23361    ) {
23362        let permalink_task = self.get_permalink_to_line(cx);
23363        let workspace = self.workspace();
23364
23365        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23366            Ok(permalink) => {
23367                cx.update(|_, cx| {
23368                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23369                })
23370                .ok();
23371            }
23372            Err(err) => {
23373                let message = format!("Failed to copy permalink: {err}");
23374
23375                anyhow::Result::<()>::Err(err).log_err();
23376
23377                if let Some(workspace) = workspace {
23378                    workspace
23379                        .update_in(cx, |workspace, _, cx| {
23380                            struct CopyPermalinkToLine;
23381
23382                            workspace.show_toast(
23383                                Toast::new(
23384                                    NotificationId::unique::<CopyPermalinkToLine>(),
23385                                    message,
23386                                ),
23387                                cx,
23388                            )
23389                        })
23390                        .ok();
23391                }
23392            }
23393        })
23394        .detach();
23395    }
23396
23397    pub fn copy_file_location(
23398        &mut self,
23399        _: &CopyFileLocation,
23400        _: &mut Window,
23401        cx: &mut Context<Self>,
23402    ) {
23403        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23404
23405        let start_line = selection.start.row + 1;
23406        let end_line = selection.end.row + 1;
23407
23408        let end_line = if selection.end.column == 0 && end_line > start_line {
23409            end_line - 1
23410        } else {
23411            end_line
23412        };
23413
23414        if let Some(file_location) = self.active_buffer(cx).and_then(|buffer| {
23415            let project = self.project()?.read(cx);
23416            let file = buffer.read(cx).file()?;
23417            let path = file.path().display(project.path_style(cx));
23418
23419            let location = if start_line == end_line {
23420                format!("{path}:{start_line}")
23421            } else {
23422                format!("{path}:{start_line}-{end_line}")
23423            };
23424            Some(location)
23425        }) {
23426            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23427        }
23428    }
23429
23430    pub fn open_permalink_to_line(
23431        &mut self,
23432        _: &OpenPermalinkToLine,
23433        window: &mut Window,
23434        cx: &mut Context<Self>,
23435    ) {
23436        let permalink_task = self.get_permalink_to_line(cx);
23437        let workspace = self.workspace();
23438
23439        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23440            Ok(permalink) => {
23441                cx.update(|_, cx| {
23442                    cx.open_url(permalink.as_ref());
23443                })
23444                .ok();
23445            }
23446            Err(err) => {
23447                let message = format!("Failed to open permalink: {err}");
23448
23449                anyhow::Result::<()>::Err(err).log_err();
23450
23451                if let Some(workspace) = workspace {
23452                    workspace.update(cx, |workspace, cx| {
23453                        struct OpenPermalinkToLine;
23454
23455                        workspace.show_toast(
23456                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23457                            cx,
23458                        )
23459                    });
23460                }
23461            }
23462        })
23463        .detach();
23464    }
23465
23466    pub fn insert_uuid_v4(
23467        &mut self,
23468        _: &InsertUuidV4,
23469        window: &mut Window,
23470        cx: &mut Context<Self>,
23471    ) {
23472        self.insert_uuid(UuidVersion::V4, window, cx);
23473    }
23474
23475    pub fn insert_uuid_v7(
23476        &mut self,
23477        _: &InsertUuidV7,
23478        window: &mut Window,
23479        cx: &mut Context<Self>,
23480    ) {
23481        self.insert_uuid(UuidVersion::V7, window, cx);
23482    }
23483
23484    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23485        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23486        self.transact(window, cx, |this, window, cx| {
23487            let edits = this
23488                .selections
23489                .all::<Point>(&this.display_snapshot(cx))
23490                .into_iter()
23491                .map(|selection| {
23492                    let uuid = match version {
23493                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23494                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23495                    };
23496
23497                    (selection.range(), uuid.to_string())
23498                });
23499            this.edit(edits, cx);
23500            this.refresh_edit_prediction(true, false, window, cx);
23501        });
23502    }
23503
23504    pub fn open_selections_in_multibuffer(
23505        &mut self,
23506        _: &OpenSelectionsInMultibuffer,
23507        window: &mut Window,
23508        cx: &mut Context<Self>,
23509    ) {
23510        let multibuffer = self.buffer.read(cx);
23511
23512        let Some(buffer) = multibuffer.as_singleton() else {
23513            return;
23514        };
23515        let buffer_snapshot = buffer.read(cx).snapshot();
23516
23517        let Some(workspace) = self.workspace() else {
23518            return;
23519        };
23520
23521        let title = multibuffer.title(cx).to_string();
23522
23523        let locations = self
23524            .selections
23525            .all_anchors(&self.display_snapshot(cx))
23526            .iter()
23527            .map(|selection| {
23528                (
23529                    buffer.clone(),
23530                    (selection.start.text_anchor_in(&buffer_snapshot)
23531                        ..selection.end.text_anchor_in(&buffer_snapshot))
23532                        .to_point(buffer.read(cx)),
23533                )
23534            })
23535            .into_group_map();
23536
23537        cx.spawn_in(window, async move |_, cx| {
23538            workspace.update_in(cx, |workspace, window, cx| {
23539                Self::open_locations_in_multibuffer(
23540                    workspace,
23541                    locations,
23542                    format!("Selections for '{title}'"),
23543                    false,
23544                    false,
23545                    MultibufferSelectionMode::All,
23546                    window,
23547                    cx,
23548                );
23549            })
23550        })
23551        .detach();
23552    }
23553
23554    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23555    /// last highlight added will be used.
23556    ///
23557    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23558    pub fn highlight_rows<T: 'static>(
23559        &mut self,
23560        range: Range<Anchor>,
23561        color: Hsla,
23562        options: RowHighlightOptions,
23563        cx: &mut Context<Self>,
23564    ) {
23565        let snapshot = self.buffer().read(cx).snapshot(cx);
23566        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23567        let ix = row_highlights.binary_search_by(|highlight| {
23568            Ordering::Equal
23569                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23570                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23571        });
23572
23573        if let Err(mut ix) = ix {
23574            let index = post_inc(&mut self.highlight_order);
23575
23576            // If this range intersects with the preceding highlight, then merge it with
23577            // the preceding highlight. Otherwise insert a new highlight.
23578            let mut merged = false;
23579            if ix > 0 {
23580                let prev_highlight = &mut row_highlights[ix - 1];
23581                if prev_highlight
23582                    .range
23583                    .end
23584                    .cmp(&range.start, &snapshot)
23585                    .is_ge()
23586                {
23587                    ix -= 1;
23588                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23589                        prev_highlight.range.end = range.end;
23590                    }
23591                    merged = true;
23592                    prev_highlight.index = index;
23593                    prev_highlight.color = color;
23594                    prev_highlight.options = options;
23595                }
23596            }
23597
23598            if !merged {
23599                row_highlights.insert(
23600                    ix,
23601                    RowHighlight {
23602                        range,
23603                        index,
23604                        color,
23605                        options,
23606                        type_id: TypeId::of::<T>(),
23607                    },
23608                );
23609            }
23610
23611            // If any of the following highlights intersect with this one, merge them.
23612            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23613                let highlight = &row_highlights[ix];
23614                if next_highlight
23615                    .range
23616                    .start
23617                    .cmp(&highlight.range.end, &snapshot)
23618                    .is_le()
23619                {
23620                    if next_highlight
23621                        .range
23622                        .end
23623                        .cmp(&highlight.range.end, &snapshot)
23624                        .is_gt()
23625                    {
23626                        row_highlights[ix].range.end = next_highlight.range.end;
23627                    }
23628                    row_highlights.remove(ix + 1);
23629                } else {
23630                    break;
23631                }
23632            }
23633        }
23634    }
23635
23636    /// Remove any highlighted row ranges of the given type that intersect the
23637    /// given ranges.
23638    pub fn remove_highlighted_rows<T: 'static>(
23639        &mut self,
23640        ranges_to_remove: Vec<Range<Anchor>>,
23641        cx: &mut Context<Self>,
23642    ) {
23643        let snapshot = self.buffer().read(cx).snapshot(cx);
23644        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23645        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23646        row_highlights.retain(|highlight| {
23647            while let Some(range_to_remove) = ranges_to_remove.peek() {
23648                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23649                    Ordering::Less | Ordering::Equal => {
23650                        ranges_to_remove.next();
23651                    }
23652                    Ordering::Greater => {
23653                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23654                            Ordering::Less | Ordering::Equal => {
23655                                return false;
23656                            }
23657                            Ordering::Greater => break,
23658                        }
23659                    }
23660                }
23661            }
23662
23663            true
23664        })
23665    }
23666
23667    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23668    pub fn clear_row_highlights<T: 'static>(&mut self) {
23669        self.highlighted_rows.remove(&TypeId::of::<T>());
23670    }
23671
23672    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23673    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23674        self.highlighted_rows
23675            .get(&TypeId::of::<T>())
23676            .map_or(&[] as &[_], |vec| vec.as_slice())
23677            .iter()
23678            .map(|highlight| (highlight.range.clone(), highlight.color))
23679    }
23680
23681    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23682    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23683    /// Allows to ignore certain kinds of highlights.
23684    pub fn highlighted_display_rows(
23685        &self,
23686        window: &mut Window,
23687        cx: &mut App,
23688    ) -> BTreeMap<DisplayRow, LineHighlight> {
23689        let snapshot = self.snapshot(window, cx);
23690        let mut used_highlight_orders = HashMap::default();
23691        self.highlighted_rows
23692            .iter()
23693            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23694            .fold(
23695                BTreeMap::<DisplayRow, LineHighlight>::new(),
23696                |mut unique_rows, highlight| {
23697                    let start = highlight.range.start.to_display_point(&snapshot);
23698                    let end = highlight.range.end.to_display_point(&snapshot);
23699                    let start_row = start.row().0;
23700                    let end_row = if !highlight.range.end.is_max() && end.column() == 0 {
23701                        end.row().0.saturating_sub(1)
23702                    } else {
23703                        end.row().0
23704                    };
23705                    for row in start_row..=end_row {
23706                        let used_index =
23707                            used_highlight_orders.entry(row).or_insert(highlight.index);
23708                        if highlight.index >= *used_index {
23709                            *used_index = highlight.index;
23710                            unique_rows.insert(
23711                                DisplayRow(row),
23712                                LineHighlight {
23713                                    include_gutter: highlight.options.include_gutter,
23714                                    border: None,
23715                                    background: highlight.color.into(),
23716                                    type_id: Some(highlight.type_id),
23717                                },
23718                            );
23719                        }
23720                    }
23721                    unique_rows
23722                },
23723            )
23724    }
23725
23726    pub fn highlighted_display_row_for_autoscroll(
23727        &self,
23728        snapshot: &DisplaySnapshot,
23729    ) -> Option<DisplayRow> {
23730        self.highlighted_rows
23731            .values()
23732            .flat_map(|highlighted_rows| highlighted_rows.iter())
23733            .filter_map(|highlight| {
23734                if highlight.options.autoscroll {
23735                    Some(highlight.range.start.to_display_point(snapshot).row())
23736                } else {
23737                    None
23738                }
23739            })
23740            .min()
23741    }
23742
23743    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23744        self.highlight_background(
23745            HighlightKey::SearchWithinRange,
23746            ranges,
23747            |_, colors| colors.colors().editor_document_highlight_read_background,
23748            cx,
23749        )
23750    }
23751
23752    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23753        self.breadcrumb_header = Some(new_header);
23754    }
23755
23756    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23757        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23758    }
23759
23760    pub fn highlight_background(
23761        &mut self,
23762        key: HighlightKey,
23763        ranges: &[Range<Anchor>],
23764        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23765        cx: &mut Context<Self>,
23766    ) {
23767        self.background_highlights
23768            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23769        self.scrollbar_marker_state.dirty = true;
23770        cx.notify();
23771    }
23772
23773    pub fn clear_background_highlights(
23774        &mut self,
23775        key: HighlightKey,
23776        cx: &mut Context<Self>,
23777    ) -> Option<BackgroundHighlight> {
23778        let text_highlights = self.background_highlights.remove(&key)?;
23779        if !text_highlights.1.is_empty() {
23780            self.scrollbar_marker_state.dirty = true;
23781            cx.notify();
23782        }
23783        Some(text_highlights)
23784    }
23785
23786    pub fn highlight_gutter<T: 'static>(
23787        &mut self,
23788        ranges: impl Into<Vec<Range<Anchor>>>,
23789        color_fetcher: fn(&App) -> Hsla,
23790        cx: &mut Context<Self>,
23791    ) {
23792        self.gutter_highlights
23793            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23794        cx.notify();
23795    }
23796
23797    pub fn clear_gutter_highlights<T: 'static>(
23798        &mut self,
23799        cx: &mut Context<Self>,
23800    ) -> Option<GutterHighlight> {
23801        cx.notify();
23802        self.gutter_highlights.remove(&TypeId::of::<T>())
23803    }
23804
23805    pub fn insert_gutter_highlight<T: 'static>(
23806        &mut self,
23807        range: Range<Anchor>,
23808        color_fetcher: fn(&App) -> Hsla,
23809        cx: &mut Context<Self>,
23810    ) {
23811        let snapshot = self.buffer().read(cx).snapshot(cx);
23812        let mut highlights = self
23813            .gutter_highlights
23814            .remove(&TypeId::of::<T>())
23815            .map(|(_, highlights)| highlights)
23816            .unwrap_or_default();
23817        let ix = highlights.binary_search_by(|highlight| {
23818            Ordering::Equal
23819                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23820                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23821        });
23822        if let Err(ix) = ix {
23823            highlights.insert(ix, range);
23824        }
23825        self.gutter_highlights
23826            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23827    }
23828
23829    pub fn remove_gutter_highlights<T: 'static>(
23830        &mut self,
23831        ranges_to_remove: Vec<Range<Anchor>>,
23832        cx: &mut Context<Self>,
23833    ) {
23834        let snapshot = self.buffer().read(cx).snapshot(cx);
23835        let Some((color_fetcher, mut gutter_highlights)) =
23836            self.gutter_highlights.remove(&TypeId::of::<T>())
23837        else {
23838            return;
23839        };
23840        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23841        gutter_highlights.retain(|highlight| {
23842            while let Some(range_to_remove) = ranges_to_remove.peek() {
23843                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23844                    Ordering::Less | Ordering::Equal => {
23845                        ranges_to_remove.next();
23846                    }
23847                    Ordering::Greater => {
23848                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23849                            Ordering::Less | Ordering::Equal => {
23850                                return false;
23851                            }
23852                            Ordering::Greater => break,
23853                        }
23854                    }
23855                }
23856            }
23857
23858            true
23859        });
23860        self.gutter_highlights
23861            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23862    }
23863
23864    #[cfg(any(test, feature = "test-support"))]
23865    pub fn all_text_highlights(
23866        &self,
23867        window: &mut Window,
23868        cx: &mut Context<Self>,
23869    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23870        let snapshot = self.snapshot(window, cx);
23871        self.display_map.update(cx, |display_map, _| {
23872            display_map
23873                .all_text_highlights()
23874                .map(|(_, highlight)| {
23875                    let (style, ranges) = highlight.as_ref();
23876                    (
23877                        *style,
23878                        ranges
23879                            .iter()
23880                            .map(|range| range.clone().to_display_points(&snapshot))
23881                            .collect(),
23882                    )
23883                })
23884                .collect()
23885        })
23886    }
23887
23888    #[cfg(any(test, feature = "test-support"))]
23889    pub fn all_text_background_highlights(
23890        &self,
23891        window: &mut Window,
23892        cx: &mut Context<Self>,
23893    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23894        let snapshot = self.snapshot(window, cx);
23895        let buffer = &snapshot.buffer_snapshot();
23896        let start = buffer.anchor_before(MultiBufferOffset(0));
23897        let end = buffer.anchor_after(buffer.len());
23898        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23899    }
23900
23901    #[cfg(any(test, feature = "test-support"))]
23902    pub fn sorted_background_highlights_in_range(
23903        &self,
23904        search_range: Range<Anchor>,
23905        display_snapshot: &DisplaySnapshot,
23906        theme: &Theme,
23907    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23908        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23909        res.sort_by(|a, b| {
23910            a.0.start
23911                .cmp(&b.0.start)
23912                .then_with(|| a.0.end.cmp(&b.0.end))
23913                .then_with(|| a.1.cmp(&b.1))
23914        });
23915        res
23916    }
23917
23918    #[cfg(any(test, feature = "test-support"))]
23919    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23920        let snapshot = self.buffer().read(cx).snapshot(cx);
23921
23922        let highlights = self
23923            .background_highlights
23924            .get(&HighlightKey::BufferSearchHighlights);
23925
23926        if let Some((_color, ranges)) = highlights {
23927            ranges
23928                .iter()
23929                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23930                .collect_vec()
23931        } else {
23932            vec![]
23933        }
23934    }
23935
23936    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23937        self.background_highlights
23938            .get(&key)
23939            .is_some_and(|(_, highlights)| !highlights.is_empty())
23940    }
23941
23942    /// Returns all background highlights for a given range.
23943    ///
23944    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23945    pub fn background_highlights_in_range(
23946        &self,
23947        search_range: Range<Anchor>,
23948        display_snapshot: &DisplaySnapshot,
23949        theme: &Theme,
23950    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23951        let mut results = Vec::new();
23952        for (color_fetcher, ranges) in self.background_highlights.values() {
23953            let start_ix = match ranges.binary_search_by(|probe| {
23954                let cmp = probe
23955                    .end
23956                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23957                if cmp.is_gt() {
23958                    Ordering::Greater
23959                } else {
23960                    Ordering::Less
23961                }
23962            }) {
23963                Ok(i) | Err(i) => i,
23964            };
23965            for (index, range) in ranges[start_ix..].iter().enumerate() {
23966                if range
23967                    .start
23968                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23969                    .is_ge()
23970                {
23971                    break;
23972                }
23973
23974                let color = color_fetcher(&(start_ix + index), theme);
23975                let start = range.start.to_display_point(display_snapshot);
23976                let end = range.end.to_display_point(display_snapshot);
23977                results.push((start..end, color))
23978            }
23979        }
23980        results
23981    }
23982
23983    pub fn gutter_highlights_in_range(
23984        &self,
23985        search_range: Range<Anchor>,
23986        display_snapshot: &DisplaySnapshot,
23987        cx: &App,
23988    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23989        let mut results = Vec::new();
23990        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23991            let color = color_fetcher(cx);
23992            let start_ix = match ranges.binary_search_by(|probe| {
23993                let cmp = probe
23994                    .end
23995                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23996                if cmp.is_gt() {
23997                    Ordering::Greater
23998                } else {
23999                    Ordering::Less
24000                }
24001            }) {
24002                Ok(i) | Err(i) => i,
24003            };
24004            for range in &ranges[start_ix..] {
24005                if range
24006                    .start
24007                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24008                    .is_ge()
24009                {
24010                    break;
24011                }
24012
24013                let start = range.start.to_display_point(display_snapshot);
24014                let end = range.end.to_display_point(display_snapshot);
24015                results.push((start..end, color))
24016            }
24017        }
24018        results
24019    }
24020
24021    /// Get the text ranges corresponding to the redaction query
24022    pub fn redacted_ranges(
24023        &self,
24024        search_range: Range<Anchor>,
24025        display_snapshot: &DisplaySnapshot,
24026        cx: &App,
24027    ) -> Vec<Range<DisplayPoint>> {
24028        display_snapshot
24029            .buffer_snapshot()
24030            .redacted_ranges(search_range, |file| {
24031                if let Some(file) = file {
24032                    file.is_private()
24033                        && EditorSettings::get(
24034                            Some(SettingsLocation {
24035                                worktree_id: file.worktree_id(cx),
24036                                path: file.path().as_ref(),
24037                            }),
24038                            cx,
24039                        )
24040                        .redact_private_values
24041                } else {
24042                    false
24043                }
24044            })
24045            .map(|range| {
24046                range.start.to_display_point(display_snapshot)
24047                    ..range.end.to_display_point(display_snapshot)
24048            })
24049            .collect()
24050    }
24051
24052    pub fn highlight_text_key(
24053        &mut self,
24054        key: HighlightKey,
24055        ranges: Vec<Range<Anchor>>,
24056        style: HighlightStyle,
24057        merge: bool,
24058        cx: &mut Context<Self>,
24059    ) {
24060        self.display_map.update(cx, |map, cx| {
24061            map.highlight_text(key, ranges, style, merge, cx);
24062        });
24063        cx.notify();
24064    }
24065
24066    pub fn highlight_text(
24067        &mut self,
24068        key: HighlightKey,
24069        ranges: Vec<Range<Anchor>>,
24070        style: HighlightStyle,
24071        cx: &mut Context<Self>,
24072    ) {
24073        self.display_map.update(cx, |map, cx| {
24074            map.highlight_text(key, ranges, style, false, cx)
24075        });
24076        cx.notify();
24077    }
24078
24079    pub fn text_highlights<'a>(
24080        &'a self,
24081        key: HighlightKey,
24082        cx: &'a App,
24083    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24084        self.display_map.read(cx).text_highlights(key)
24085    }
24086
24087    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24088        let cleared = self
24089            .display_map
24090            .update(cx, |map, _| map.clear_highlights(key));
24091        if cleared {
24092            cx.notify();
24093        }
24094    }
24095
24096    pub fn clear_highlights_with(
24097        &mut self,
24098        f: &mut dyn FnMut(&HighlightKey) -> bool,
24099        cx: &mut Context<Self>,
24100    ) {
24101        let cleared = self
24102            .display_map
24103            .update(cx, |map, _| map.clear_highlights_with(f));
24104        if cleared {
24105            cx.notify();
24106        }
24107    }
24108
24109    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24110        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24111            && self.focus_handle.is_focused(window)
24112    }
24113
24114    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24115        self.show_cursor_when_unfocused = is_enabled;
24116        cx.notify();
24117    }
24118
24119    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24120        cx.notify();
24121    }
24122
24123    fn on_debug_session_event(
24124        &mut self,
24125        _session: Entity<Session>,
24126        event: &SessionEvent,
24127        cx: &mut Context<Self>,
24128    ) {
24129        if let SessionEvent::InvalidateInlineValue = event {
24130            self.refresh_inline_values(cx);
24131        }
24132    }
24133
24134    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24135        let Some(semantics) = self.semantics_provider.clone() else {
24136            return;
24137        };
24138
24139        if !self.inline_value_cache.enabled {
24140            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24141            self.splice_inlays(&inlays, Vec::new(), cx);
24142            return;
24143        }
24144
24145        let current_execution_position = self
24146            .highlighted_rows
24147            .get(&TypeId::of::<ActiveDebugLine>())
24148            .and_then(|lines| lines.last().map(|line| line.range.end));
24149
24150        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24151            let inline_values = editor
24152                .update(cx, |editor, cx| {
24153                    let Some(current_execution_position) = current_execution_position else {
24154                        return Some(Task::ready(Ok(Vec::new())));
24155                    };
24156
24157                    let (buffer, buffer_anchor) =
24158                        editor.buffer.read_with(cx, |multibuffer, cx| {
24159                            let multibuffer_snapshot = multibuffer.snapshot(cx);
24160                            let (buffer_anchor, _) = multibuffer_snapshot
24161                                .anchor_to_buffer_anchor(current_execution_position)?;
24162                            let buffer = multibuffer.buffer(buffer_anchor.buffer_id)?;
24163                            Some((buffer, buffer_anchor))
24164                        })?;
24165
24166                    let range = buffer.read(cx).anchor_before(0)..buffer_anchor;
24167
24168                    semantics.inline_values(buffer, range, cx)
24169                })
24170                .ok()
24171                .flatten()?
24172                .await
24173                .context("refreshing debugger inlays")
24174                .log_err()?;
24175
24176            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24177
24178            for (buffer_id, inline_value) in inline_values
24179                .into_iter()
24180                .map(|hint| (hint.position.buffer_id, hint))
24181            {
24182                buffer_inline_values
24183                    .entry(buffer_id)
24184                    .or_default()
24185                    .push(inline_value);
24186            }
24187
24188            editor
24189                .update(cx, |editor, cx| {
24190                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24191                    let mut new_inlays = Vec::default();
24192
24193                    for (_buffer_id, inline_values) in buffer_inline_values {
24194                        for hint in inline_values {
24195                            let Some(anchor) = snapshot.anchor_in_excerpt(hint.position) else {
24196                                continue;
24197                            };
24198                            let inlay = Inlay::debugger(
24199                                post_inc(&mut editor.next_inlay_id),
24200                                anchor,
24201                                hint.text(),
24202                            );
24203                            if !inlay.text().chars().contains(&'\n') {
24204                                new_inlays.push(inlay);
24205                            }
24206                        }
24207                    }
24208
24209                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24210                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24211
24212                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24213                })
24214                .ok()?;
24215            Some(())
24216        });
24217    }
24218
24219    fn on_buffer_event(
24220        &mut self,
24221        multibuffer: &Entity<MultiBuffer>,
24222        event: &multi_buffer::Event,
24223        window: &mut Window,
24224        cx: &mut Context<Self>,
24225    ) {
24226        match event {
24227            multi_buffer::Event::Edited {
24228                edited_buffer,
24229                is_local,
24230            } => {
24231                self.scrollbar_marker_state.dirty = true;
24232                self.active_indent_guides_state.dirty = true;
24233                self.refresh_active_diagnostics(cx);
24234                self.refresh_code_actions(window, cx);
24235                self.refresh_single_line_folds(window, cx);
24236                let snapshot = self.snapshot(window, cx);
24237                self.refresh_matching_bracket_highlights(&snapshot, cx);
24238                self.refresh_outline_symbols_at_cursor(cx);
24239                self.refresh_sticky_headers(&snapshot, cx);
24240                if *is_local && self.has_active_edit_prediction() {
24241                    self.update_visible_edit_prediction(window, cx);
24242                }
24243
24244                // Clean up orphaned review comments after edits
24245                self.cleanup_orphaned_review_comments(cx);
24246
24247                if let Some(buffer) = edited_buffer {
24248                    if buffer.read(cx).file().is_none() {
24249                        cx.emit(EditorEvent::TitleChanged);
24250                    }
24251
24252                    if self.project.is_some() {
24253                        let buffer_id = buffer.read(cx).remote_id();
24254                        self.register_buffer(buffer_id, cx);
24255                        self.update_lsp_data(Some(buffer_id), window, cx);
24256                        self.refresh_inlay_hints(
24257                            InlayHintRefreshReason::BufferEdited(buffer_id),
24258                            cx,
24259                        );
24260                    }
24261                }
24262
24263                cx.emit(EditorEvent::BufferEdited);
24264                cx.emit(SearchEvent::MatchesInvalidated);
24265
24266                let Some(project) = &self.project else { return };
24267                let (telemetry, is_via_ssh) = {
24268                    let project = project.read(cx);
24269                    let telemetry = project.client().telemetry().clone();
24270                    let is_via_ssh = project.is_via_remote_server();
24271                    (telemetry, is_via_ssh)
24272                };
24273                telemetry.log_edit_event("editor", is_via_ssh);
24274            }
24275            multi_buffer::Event::BufferRangesUpdated {
24276                buffer,
24277                ranges,
24278                path_key,
24279            } => {
24280                self.refresh_document_highlights(cx);
24281                let buffer_id = buffer.read(cx).remote_id();
24282                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24283                    && let Some(project) = &self.project
24284                {
24285                    update_uncommitted_diff_for_buffer(
24286                        cx.entity(),
24287                        project,
24288                        [buffer.clone()],
24289                        self.buffer.clone(),
24290                        cx,
24291                    )
24292                    .detach();
24293                }
24294                self.register_visible_buffers(cx);
24295                self.update_lsp_data(Some(buffer_id), window, cx);
24296                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24297                self.refresh_runnables(None, window, cx);
24298                self.bracket_fetched_tree_sitter_chunks
24299                    .retain(|range, _| range.start.buffer_id != buffer_id);
24300                self.colorize_brackets(false, cx);
24301                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24302                self.semantic_token_state.invalidate_buffer(&buffer_id);
24303                cx.emit(EditorEvent::BufferRangesUpdated {
24304                    buffer: buffer.clone(),
24305                    ranges: ranges.clone(),
24306                    path_key: path_key.clone(),
24307                });
24308            }
24309            multi_buffer::Event::BuffersRemoved { removed_buffer_ids } => {
24310                if let Some(inlay_hints) = &mut self.inlay_hints {
24311                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24312                }
24313                self.refresh_inlay_hints(
24314                    InlayHintRefreshReason::BuffersRemoved(removed_buffer_ids.clone()),
24315                    cx,
24316                );
24317                for buffer_id in removed_buffer_ids {
24318                    self.registered_buffers.remove(buffer_id);
24319                    self.clear_runnables(Some(*buffer_id));
24320                    self.semantic_token_state.invalidate_buffer(buffer_id);
24321                    self.display_map.update(cx, |display_map, cx| {
24322                        display_map.invalidate_semantic_highlights(*buffer_id);
24323                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24324                    });
24325                }
24326
24327                self.display_map.update(cx, |display_map, cx| {
24328                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24329                });
24330
24331                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24332                cx.emit(EditorEvent::BuffersRemoved {
24333                    removed_buffer_ids: removed_buffer_ids.clone(),
24334                });
24335            }
24336            multi_buffer::Event::BuffersEdited { buffer_ids } => {
24337                self.display_map.update(cx, |map, cx| {
24338                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24339                });
24340                cx.emit(EditorEvent::BuffersEdited {
24341                    buffer_ids: buffer_ids.clone(),
24342                });
24343            }
24344            multi_buffer::Event::Reparsed(buffer_id) => {
24345                self.refresh_runnables(Some(*buffer_id), window, cx);
24346                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24347                self.colorize_brackets(true, cx);
24348                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24349
24350                cx.emit(EditorEvent::Reparsed(*buffer_id));
24351            }
24352            multi_buffer::Event::DiffHunksToggled => {
24353                self.refresh_runnables(None, window, cx);
24354            }
24355            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24356                if !is_fresh_language {
24357                    self.registered_buffers.remove(&buffer_id);
24358                }
24359                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24360                cx.emit(EditorEvent::Reparsed(*buffer_id));
24361                self.update_edit_prediction_settings(cx);
24362                cx.notify();
24363            }
24364            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24365            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24366            multi_buffer::Event::FileHandleChanged
24367            | multi_buffer::Event::Reloaded
24368            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24369            multi_buffer::Event::DiagnosticsUpdated => {
24370                self.update_diagnostics_state(window, cx);
24371            }
24372            _ => {}
24373        };
24374    }
24375
24376    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24377        if !self.diagnostics_enabled() {
24378            return;
24379        }
24380        self.refresh_active_diagnostics(cx);
24381        self.refresh_inline_diagnostics(true, window, cx);
24382        self.scrollbar_marker_state.dirty = true;
24383        cx.notify();
24384    }
24385
24386    pub fn start_temporary_diff_override(&mut self) {
24387        self.load_diff_task.take();
24388        self.temporary_diff_override = true;
24389    }
24390
24391    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24392        self.temporary_diff_override = false;
24393        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24394        self.buffer.update(cx, |buffer, cx| {
24395            buffer.set_all_diff_hunks_collapsed(cx);
24396        });
24397
24398        if let Some(project) = self.project.clone() {
24399            self.load_diff_task = Some(
24400                update_uncommitted_diff_for_buffer(
24401                    cx.entity(),
24402                    &project,
24403                    self.buffer.read(cx).all_buffers(),
24404                    self.buffer.clone(),
24405                    cx,
24406                )
24407                .shared(),
24408            );
24409        }
24410    }
24411
24412    fn on_display_map_changed(
24413        &mut self,
24414        _: Entity<DisplayMap>,
24415        _: &mut Window,
24416        cx: &mut Context<Self>,
24417    ) {
24418        cx.notify();
24419    }
24420
24421    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24422        if !self.mode.is_full() {
24423            return None;
24424        }
24425
24426        let theme_settings = theme_settings::ThemeSettings::get_global(cx);
24427        let theme = cx.theme();
24428        let accent_colors = theme.accents().clone();
24429
24430        let accent_overrides = theme_settings
24431            .theme_overrides
24432            .get(theme.name.as_ref())
24433            .map(|theme_style| &theme_style.accents)
24434            .into_iter()
24435            .flatten()
24436            .chain(
24437                theme_settings
24438                    .experimental_theme_overrides
24439                    .as_ref()
24440                    .map(|overrides| &overrides.accents)
24441                    .into_iter()
24442                    .flatten(),
24443            )
24444            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24445            .collect();
24446
24447        Some(AccentData {
24448            colors: accent_colors,
24449            overrides: accent_overrides,
24450        })
24451    }
24452
24453    fn fetch_applicable_language_settings(
24454        &self,
24455        cx: &App,
24456    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24457        if !self.mode.is_full() {
24458            return HashMap::default();
24459        }
24460
24461        self.buffer().read(cx).all_buffers().into_iter().fold(
24462            HashMap::default(),
24463            |mut acc, buffer| {
24464                let buffer = buffer.read(cx);
24465                let language = buffer.language().map(|language| language.name());
24466                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24467                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24468                }
24469                acc
24470            },
24471        )
24472    }
24473
24474    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24475        let new_language_settings = self.fetch_applicable_language_settings(cx);
24476        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24477        self.applicable_language_settings = new_language_settings;
24478
24479        let new_accents = self.fetch_accent_data(cx);
24480        let accents_changed = new_accents != self.accent_data;
24481        self.accent_data = new_accents;
24482
24483        if self.diagnostics_enabled() {
24484            let new_severity = EditorSettings::get_global(cx)
24485                .diagnostics_max_severity
24486                .unwrap_or(DiagnosticSeverity::Hint);
24487            self.set_max_diagnostics_severity(new_severity, cx);
24488        }
24489        self.refresh_runnables(None, window, cx);
24490        self.update_edit_prediction_settings(cx);
24491        self.refresh_edit_prediction(true, false, window, cx);
24492        self.refresh_inline_values(cx);
24493
24494        let old_cursor_shape = self.cursor_shape;
24495        let old_show_breadcrumbs = self.show_breadcrumbs;
24496
24497        {
24498            let editor_settings = EditorSettings::get_global(cx);
24499            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24500            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24501            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24502            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24503        }
24504
24505        if old_cursor_shape != self.cursor_shape {
24506            cx.emit(EditorEvent::CursorShapeChanged);
24507        }
24508
24509        if old_show_breadcrumbs != self.show_breadcrumbs {
24510            cx.emit(EditorEvent::BreadcrumbsChanged);
24511        }
24512
24513        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24514            let project_settings = ProjectSettings::get_global(cx);
24515            (
24516                project_settings.session.restore_unsaved_buffers,
24517                project_settings.diagnostics.inline.enabled,
24518                project_settings.git.inline_blame.enabled,
24519            )
24520        };
24521        self.buffer_serialization = self
24522            .should_serialize_buffer()
24523            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24524
24525        if self.mode.is_full() {
24526            if self.show_inline_diagnostics != show_inline_diagnostics {
24527                self.show_inline_diagnostics = show_inline_diagnostics;
24528                self.refresh_inline_diagnostics(false, window, cx);
24529            }
24530
24531            if self.git_blame_inline_enabled != inline_blame_enabled {
24532                self.toggle_git_blame_inline_internal(false, window, cx);
24533            }
24534
24535            let minimap_settings = EditorSettings::get_global(cx).minimap;
24536            if self.minimap_visibility != MinimapVisibility::Disabled {
24537                if self.minimap_visibility.settings_visibility()
24538                    != minimap_settings.minimap_enabled()
24539                {
24540                    self.set_minimap_visibility(
24541                        MinimapVisibility::for_mode(self.mode(), cx),
24542                        window,
24543                        cx,
24544                    );
24545                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24546                    minimap_entity.update(cx, |minimap_editor, cx| {
24547                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24548                    })
24549                }
24550            }
24551
24552            if language_settings_changed || accents_changed {
24553                self.colorize_brackets(true, cx);
24554            }
24555
24556            if language_settings_changed {
24557                self.clear_disabled_lsp_folding_ranges(window, cx);
24558                self.refresh_document_symbols(None, cx);
24559            }
24560
24561            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24562                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24563            }) {
24564                if !inlay_splice.is_empty() {
24565                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24566                }
24567                self.refresh_document_colors(None, window, cx);
24568            }
24569
24570            self.refresh_inlay_hints(
24571                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24572                    self.selections.newest_anchor().head(),
24573                    &self.buffer.read(cx).snapshot(cx),
24574                    cx,
24575                )),
24576                cx,
24577            );
24578
24579            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24580                .global_lsp_settings
24581                .semantic_token_rules
24582                .clone();
24583            let semantic_token_rules_changed = self
24584                .semantic_token_state
24585                .update_rules(new_semantic_token_rules);
24586            if language_settings_changed || semantic_token_rules_changed {
24587                self.invalidate_semantic_tokens(None);
24588                self.refresh_semantic_tokens(None, None, cx);
24589            }
24590        }
24591
24592        cx.notify();
24593    }
24594
24595    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24596        if !self.mode.is_full() {
24597            return;
24598        }
24599
24600        let new_accents = self.fetch_accent_data(cx);
24601        if new_accents != self.accent_data {
24602            self.accent_data = new_accents;
24603            self.colorize_brackets(true, cx);
24604        }
24605
24606        self.invalidate_semantic_tokens(None);
24607        self.refresh_semantic_tokens(None, None, cx);
24608    }
24609
24610    pub fn set_searchable(&mut self, searchable: bool) {
24611        self.searchable = searchable;
24612    }
24613
24614    pub fn searchable(&self) -> bool {
24615        self.searchable
24616    }
24617
24618    pub fn open_excerpts_in_split(
24619        &mut self,
24620        _: &OpenExcerptsSplit,
24621        window: &mut Window,
24622        cx: &mut Context<Self>,
24623    ) {
24624        self.open_excerpts_common(None, true, window, cx)
24625    }
24626
24627    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24628        self.open_excerpts_common(None, false, window, cx)
24629    }
24630
24631    pub(crate) fn open_excerpts_common(
24632        &mut self,
24633        jump_data: Option<JumpData>,
24634        split: bool,
24635        window: &mut Window,
24636        cx: &mut Context<Self>,
24637    ) {
24638        if self.buffer.read(cx).is_singleton() {
24639            cx.propagate();
24640            return;
24641        }
24642
24643        let mut new_selections_by_buffer = HashMap::default();
24644        match &jump_data {
24645            Some(JumpData::MultiBufferPoint {
24646                anchor,
24647                position,
24648                line_offset_from_top,
24649            }) => {
24650                if let Some(buffer) = self.buffer.read(cx).buffer(anchor.buffer_id) {
24651                    let buffer_snapshot = buffer.read(cx).snapshot();
24652                    let jump_to_point = if buffer_snapshot.can_resolve(&anchor) {
24653                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24654                    } else {
24655                        buffer_snapshot.clip_point(*position, Bias::Left)
24656                    };
24657                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24658                    new_selections_by_buffer.insert(
24659                        buffer,
24660                        (
24661                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24662                            Some(*line_offset_from_top),
24663                        ),
24664                    );
24665                }
24666            }
24667            Some(JumpData::MultiBufferRow {
24668                row,
24669                line_offset_from_top,
24670            }) => {
24671                let point = MultiBufferPoint::new(row.0, 0);
24672                if let Some((buffer, buffer_point)) =
24673                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24674                {
24675                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24676                    new_selections_by_buffer
24677                        .entry(buffer)
24678                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24679                        .0
24680                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24681                }
24682            }
24683            None => {
24684                let selections = self
24685                    .selections
24686                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24687                let multi_buffer = self.buffer.read(cx);
24688                let multi_buffer_snapshot = multi_buffer.snapshot(cx);
24689                for selection in selections {
24690                    for (snapshot, range, anchor) in multi_buffer_snapshot
24691                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24692                    {
24693                        if let Some((text_anchor, _)) = anchor.and_then(|anchor| {
24694                            multi_buffer_snapshot.anchor_to_buffer_anchor(anchor)
24695                        }) {
24696                            let Some(buffer_handle) = multi_buffer.buffer(text_anchor.buffer_id)
24697                            else {
24698                                continue;
24699                            };
24700                            let offset = text::ToOffset::to_offset(
24701                                &text_anchor,
24702                                &buffer_handle.read(cx).snapshot(),
24703                            );
24704                            let range = BufferOffset(offset)..BufferOffset(offset);
24705                            new_selections_by_buffer
24706                                .entry(buffer_handle)
24707                                .or_insert((Vec::new(), None))
24708                                .0
24709                                .push(range)
24710                        } else {
24711                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24712                            else {
24713                                continue;
24714                            };
24715                            new_selections_by_buffer
24716                                .entry(buffer_handle)
24717                                .or_insert((Vec::new(), None))
24718                                .0
24719                                .push(range)
24720                        }
24721                    }
24722                }
24723            }
24724        }
24725
24726        if self.delegate_open_excerpts {
24727            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24728                .into_iter()
24729                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24730                .collect();
24731            if !selections_by_buffer.is_empty() {
24732                cx.emit(EditorEvent::OpenExcerptsRequested {
24733                    selections_by_buffer,
24734                    split,
24735                });
24736            }
24737            return;
24738        }
24739
24740        let Some(workspace) = self.workspace() else {
24741            cx.propagate();
24742            return;
24743        };
24744
24745        new_selections_by_buffer
24746            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24747
24748        if new_selections_by_buffer.is_empty() {
24749            return;
24750        }
24751
24752        Self::open_buffers_in_workspace(
24753            workspace.downgrade(),
24754            new_selections_by_buffer,
24755            split,
24756            window,
24757            cx,
24758        );
24759    }
24760
24761    pub(crate) fn open_buffers_in_workspace(
24762        workspace: WeakEntity<Workspace>,
24763        new_selections_by_buffer: HashMap<
24764            Entity<language::Buffer>,
24765            (Vec<Range<BufferOffset>>, Option<u32>),
24766        >,
24767        split: bool,
24768        window: &mut Window,
24769        cx: &mut App,
24770    ) {
24771        // We defer the pane interaction because we ourselves are a workspace item
24772        // and activating a new item causes the pane to call a method on us reentrantly,
24773        // which panics if we're on the stack.
24774        window.defer(cx, move |window, cx| {
24775            workspace
24776                .update(cx, |workspace, cx| {
24777                    let pane = if split {
24778                        workspace.adjacent_pane(window, cx)
24779                    } else {
24780                        workspace.active_pane().clone()
24781                    };
24782
24783                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24784                        let buffer_read = buffer.read(cx);
24785                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24786                            (true, project::File::from_dyn(Some(file)).is_some())
24787                        } else {
24788                            (false, false)
24789                        };
24790
24791                        // If project file is none workspace.open_project_item will fail to open the excerpt
24792                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24793                        // so we check if there's a tab match in that case first
24794                        let editor = (!has_file || !is_project_file)
24795                            .then(|| {
24796                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24797                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24798                                // Instead, we try to activate the existing editor in the pane first.
24799                                let (editor, pane_item_index, pane_item_id) =
24800                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24801                                        let editor = item.downcast::<Editor>()?;
24802                                        let singleton_buffer =
24803                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24804                                        if singleton_buffer == buffer {
24805                                            Some((editor, i, item.item_id()))
24806                                        } else {
24807                                            None
24808                                        }
24809                                    })?;
24810                                pane.update(cx, |pane, cx| {
24811                                    pane.activate_item(pane_item_index, true, true, window, cx);
24812                                    if !PreviewTabsSettings::get_global(cx)
24813                                        .enable_preview_from_multibuffer
24814                                    {
24815                                        pane.unpreview_item_if_preview(pane_item_id);
24816                                    }
24817                                });
24818                                Some(editor)
24819                            })
24820                            .flatten()
24821                            .unwrap_or_else(|| {
24822                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24823                                    .enable_keep_preview_on_code_navigation;
24824                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24825                                    .enable_preview_from_multibuffer;
24826                                workspace.open_project_item::<Self>(
24827                                    pane.clone(),
24828                                    buffer,
24829                                    true,
24830                                    true,
24831                                    keep_old_preview,
24832                                    allow_new_preview,
24833                                    window,
24834                                    cx,
24835                                )
24836                            });
24837
24838                        editor.update(cx, |editor, cx| {
24839                            if has_file && !is_project_file {
24840                                editor.set_read_only(true);
24841                            }
24842                            let autoscroll = match scroll_offset {
24843                                Some(scroll_offset) => {
24844                                    Autoscroll::top_relative(scroll_offset as usize)
24845                                }
24846                                None => Autoscroll::newest(),
24847                            };
24848                            let nav_history = editor.nav_history.take();
24849                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24850                            let Some(buffer_snapshot) = multibuffer_snapshot.as_singleton() else {
24851                                return;
24852                            };
24853                            editor.change_selections(
24854                                SelectionEffects::scroll(autoscroll),
24855                                window,
24856                                cx,
24857                                |s| {
24858                                    s.select_ranges(ranges.into_iter().map(|range| {
24859                                        let range = buffer_snapshot.anchor_before(range.start)
24860                                            ..buffer_snapshot.anchor_after(range.end);
24861                                        multibuffer_snapshot
24862                                            .buffer_anchor_range_to_anchor_range(range)
24863                                            .unwrap()
24864                                    }));
24865                                },
24866                            );
24867                            editor.nav_history = nav_history;
24868                        });
24869                    }
24870                })
24871                .ok();
24872        });
24873    }
24874
24875    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24876        let snapshot = self.buffer.read(cx).read(cx);
24877        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24878        Some(
24879            ranges
24880                .iter()
24881                .map(move |range| {
24882                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24883                })
24884                .collect(),
24885        )
24886    }
24887
24888    fn selection_replacement_ranges(
24889        &self,
24890        range: Range<MultiBufferOffsetUtf16>,
24891        cx: &mut App,
24892    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24893        let selections = self
24894            .selections
24895            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24896        let newest_selection = selections
24897            .iter()
24898            .max_by_key(|selection| selection.id)
24899            .unwrap();
24900        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24901        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24902        let snapshot = self.buffer.read(cx).read(cx);
24903        selections
24904            .into_iter()
24905            .map(|mut selection| {
24906                selection.start.0.0 =
24907                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24908                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24909                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24910                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24911            })
24912            .collect()
24913    }
24914
24915    fn report_editor_event(
24916        &self,
24917        reported_event: ReportEditorEvent,
24918        file_extension: Option<String>,
24919        cx: &App,
24920    ) {
24921        if cfg!(any(test, feature = "test-support")) {
24922            return;
24923        }
24924
24925        let Some(project) = &self.project else { return };
24926
24927        // If None, we are in a file without an extension
24928        let file = self
24929            .buffer
24930            .read(cx)
24931            .as_singleton()
24932            .and_then(|b| b.read(cx).file());
24933        let file_extension = file_extension.or(file
24934            .as_ref()
24935            .and_then(|file| Path::new(file.file_name(cx)).extension())
24936            .and_then(|e| e.to_str())
24937            .map(|a| a.to_string()));
24938
24939        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24940            .map(|vim_mode| vim_mode.0)
24941            .unwrap_or(false);
24942
24943        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24944        let copilot_enabled = edit_predictions_provider
24945            == language::language_settings::EditPredictionProvider::Copilot;
24946        let copilot_enabled_for_language = self
24947            .buffer
24948            .read(cx)
24949            .language_settings(cx)
24950            .show_edit_predictions;
24951
24952        let project = project.read(cx);
24953        let event_type = reported_event.event_type();
24954
24955        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24956            telemetry::event!(
24957                event_type,
24958                type = if auto_saved {"autosave"} else {"manual"},
24959                file_extension,
24960                vim_mode,
24961                copilot_enabled,
24962                copilot_enabled_for_language,
24963                edit_predictions_provider,
24964                is_via_ssh = project.is_via_remote_server(),
24965            );
24966        } else {
24967            telemetry::event!(
24968                event_type,
24969                file_extension,
24970                vim_mode,
24971                copilot_enabled,
24972                copilot_enabled_for_language,
24973                edit_predictions_provider,
24974                is_via_ssh = project.is_via_remote_server(),
24975            );
24976        };
24977    }
24978
24979    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24980    /// with each line being an array of {text, highlight} objects.
24981    fn copy_highlight_json(
24982        &mut self,
24983        _: &CopyHighlightJson,
24984        _: &mut Window,
24985        cx: &mut Context<Self>,
24986    ) {
24987        #[derive(Serialize)]
24988        struct Chunk<'a> {
24989            text: String,
24990            highlight: Option<&'a str>,
24991        }
24992
24993        let snapshot = self.buffer.read(cx).snapshot(cx);
24994        let mut selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
24995        let max_point = snapshot.max_point();
24996
24997        let range = if self.selections.line_mode() {
24998            selection.start = Point::new(selection.start.row, 0);
24999            selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
25000            selection.goal = SelectionGoal::None;
25001            selection.range()
25002        } else if selection.is_empty() {
25003            Point::new(0, 0)..max_point
25004        } else {
25005            selection.range()
25006        };
25007
25008        let chunks = snapshot.chunks(range, true);
25009        let mut lines = Vec::new();
25010        let mut line: VecDeque<Chunk> = VecDeque::new();
25011
25012        let Some(style) = self.style.as_ref() else {
25013            return;
25014        };
25015
25016        for chunk in chunks {
25017            let highlight = chunk
25018                .syntax_highlight_id
25019                .and_then(|id| style.syntax.get_capture_name(id));
25020
25021            let mut chunk_lines = chunk.text.split('\n').peekable();
25022            while let Some(text) = chunk_lines.next() {
25023                let mut merged_with_last_token = false;
25024                if let Some(last_token) = line.back_mut()
25025                    && last_token.highlight == highlight
25026                {
25027                    last_token.text.push_str(text);
25028                    merged_with_last_token = true;
25029                }
25030
25031                if !merged_with_last_token {
25032                    line.push_back(Chunk {
25033                        text: text.into(),
25034                        highlight,
25035                    });
25036                }
25037
25038                if chunk_lines.peek().is_some() {
25039                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25040                        line.pop_front();
25041                    }
25042                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25043                        line.pop_back();
25044                    }
25045
25046                    lines.push(mem::take(&mut line));
25047                }
25048            }
25049        }
25050
25051        if line.iter().any(|chunk| !chunk.text.is_empty()) {
25052            lines.push(line);
25053        }
25054
25055        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25056            return;
25057        };
25058        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25059    }
25060
25061    pub fn open_context_menu(
25062        &mut self,
25063        _: &OpenContextMenu,
25064        window: &mut Window,
25065        cx: &mut Context<Self>,
25066    ) {
25067        self.request_autoscroll(Autoscroll::newest(), cx);
25068        let position = self
25069            .selections
25070            .newest_display(&self.display_snapshot(cx))
25071            .start;
25072        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25073    }
25074
25075    pub fn replay_insert_event(
25076        &mut self,
25077        text: &str,
25078        relative_utf16_range: Option<Range<isize>>,
25079        window: &mut Window,
25080        cx: &mut Context<Self>,
25081    ) {
25082        if !self.input_enabled {
25083            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25084            return;
25085        }
25086        if let Some(relative_utf16_range) = relative_utf16_range {
25087            let selections = self
25088                .selections
25089                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25090            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25091                let new_ranges = selections.into_iter().map(|range| {
25092                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25093                        range
25094                            .head()
25095                            .0
25096                            .0
25097                            .saturating_add_signed(relative_utf16_range.start),
25098                    ));
25099                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25100                        range
25101                            .head()
25102                            .0
25103                            .0
25104                            .saturating_add_signed(relative_utf16_range.end),
25105                    ));
25106                    start..end
25107                });
25108                s.select_ranges(new_ranges);
25109            });
25110        }
25111
25112        self.handle_input(text, window, cx);
25113    }
25114
25115    pub fn is_focused(&self, window: &Window) -> bool {
25116        self.focus_handle.is_focused(window)
25117    }
25118
25119    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25120        cx.emit(EditorEvent::Focused);
25121
25122        if let Some(descendant) = self
25123            .last_focused_descendant
25124            .take()
25125            .and_then(|descendant| descendant.upgrade())
25126        {
25127            window.focus(&descendant, cx);
25128        } else {
25129            if let Some(blame) = self.blame.as_ref() {
25130                blame.update(cx, GitBlame::focus)
25131            }
25132
25133            self.blink_manager.update(cx, BlinkManager::enable);
25134            self.show_cursor_names(window, cx);
25135            self.buffer.update(cx, |buffer, cx| {
25136                buffer.finalize_last_transaction(cx);
25137                if self.leader_id.is_none() {
25138                    buffer.set_active_selections(
25139                        &self.selections.disjoint_anchors_arc(),
25140                        self.selections.line_mode(),
25141                        self.cursor_shape,
25142                        cx,
25143                    );
25144                }
25145            });
25146
25147            if let Some(position_map) = self.last_position_map.clone()
25148                && !self.mouse_cursor_hidden
25149            {
25150                EditorElement::mouse_moved(
25151                    self,
25152                    &MouseMoveEvent {
25153                        position: window.mouse_position(),
25154                        pressed_button: None,
25155                        modifiers: window.modifiers(),
25156                    },
25157                    &position_map,
25158                    None,
25159                    window,
25160                    cx,
25161                );
25162            }
25163        }
25164    }
25165
25166    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25167        cx.emit(EditorEvent::FocusedIn)
25168    }
25169
25170    fn handle_focus_out(
25171        &mut self,
25172        event: FocusOutEvent,
25173        _window: &mut Window,
25174        cx: &mut Context<Self>,
25175    ) {
25176        if event.blurred != self.focus_handle {
25177            self.last_focused_descendant = Some(event.blurred);
25178        }
25179        self.selection_drag_state = SelectionDragState::None;
25180        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25181    }
25182
25183    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25184        self.blink_manager.update(cx, BlinkManager::disable);
25185        self.buffer
25186            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25187
25188        if let Some(blame) = self.blame.as_ref() {
25189            blame.update(cx, GitBlame::blur)
25190        }
25191        if !self.hover_state.focused(window, cx) {
25192            hide_hover(self, cx);
25193        }
25194        if !self
25195            .context_menu
25196            .borrow()
25197            .as_ref()
25198            .is_some_and(|context_menu| context_menu.focused(window, cx))
25199        {
25200            self.hide_context_menu(window, cx);
25201        }
25202        self.take_active_edit_prediction(true, cx);
25203        cx.emit(EditorEvent::Blurred);
25204        cx.notify();
25205    }
25206
25207    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25208        let mut pending: String = window
25209            .pending_input_keystrokes()
25210            .into_iter()
25211            .flatten()
25212            .filter_map(|keystroke| keystroke.key_char.clone())
25213            .collect();
25214
25215        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25216            pending = "".to_string();
25217        }
25218
25219        let existing_pending = self
25220            .text_highlights(HighlightKey::PendingInput, cx)
25221            .map(|(_, ranges)| ranges.to_vec());
25222        if existing_pending.is_none() && pending.is_empty() {
25223            return;
25224        }
25225        let transaction =
25226            self.transact(window, cx, |this, window, cx| {
25227                let selections = this
25228                    .selections
25229                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25230                let edits = selections
25231                    .iter()
25232                    .map(|selection| (selection.end..selection.end, pending.clone()));
25233                this.edit(edits, cx);
25234                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25235                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25236                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25237                    }));
25238                });
25239                if let Some(existing_ranges) = existing_pending {
25240                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25241                    this.edit(edits, cx);
25242                }
25243            });
25244
25245        let snapshot = self.snapshot(window, cx);
25246        let ranges = self
25247            .selections
25248            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25249            .into_iter()
25250            .map(|selection| {
25251                snapshot.buffer_snapshot().anchor_after(selection.end)
25252                    ..snapshot
25253                        .buffer_snapshot()
25254                        .anchor_before(selection.end + pending.len())
25255            })
25256            .collect();
25257
25258        if pending.is_empty() {
25259            self.clear_highlights(HighlightKey::PendingInput, cx);
25260        } else {
25261            self.highlight_text(
25262                HighlightKey::PendingInput,
25263                ranges,
25264                HighlightStyle {
25265                    underline: Some(UnderlineStyle {
25266                        thickness: px(1.),
25267                        color: None,
25268                        wavy: false,
25269                    }),
25270                    ..Default::default()
25271                },
25272                cx,
25273            );
25274        }
25275
25276        self.ime_transaction = self.ime_transaction.or(transaction);
25277        if let Some(transaction) = self.ime_transaction {
25278            self.buffer.update(cx, |buffer, cx| {
25279                buffer.group_until_transaction(transaction, cx);
25280            });
25281        }
25282
25283        if self
25284            .text_highlights(HighlightKey::PendingInput, cx)
25285            .is_none()
25286        {
25287            self.ime_transaction.take();
25288        }
25289    }
25290
25291    pub fn register_action_renderer(
25292        &mut self,
25293        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25294    ) -> Subscription {
25295        let id = self.next_editor_action_id.post_inc();
25296        self.editor_actions
25297            .borrow_mut()
25298            .insert(id, Box::new(listener));
25299
25300        let editor_actions = self.editor_actions.clone();
25301        Subscription::new(move || {
25302            editor_actions.borrow_mut().remove(&id);
25303        })
25304    }
25305
25306    pub fn register_action<A: Action>(
25307        &mut self,
25308        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25309    ) -> Subscription {
25310        let id = self.next_editor_action_id.post_inc();
25311        let listener = Arc::new(listener);
25312        self.editor_actions.borrow_mut().insert(
25313            id,
25314            Box::new(move |_, window, _| {
25315                let listener = listener.clone();
25316                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25317                    let action = action.downcast_ref().unwrap();
25318                    if phase == DispatchPhase::Bubble {
25319                        listener(action, window, cx)
25320                    }
25321                })
25322            }),
25323        );
25324
25325        let editor_actions = self.editor_actions.clone();
25326        Subscription::new(move || {
25327            editor_actions.borrow_mut().remove(&id);
25328        })
25329    }
25330
25331    pub fn file_header_size(&self) -> u32 {
25332        FILE_HEADER_HEIGHT
25333    }
25334
25335    pub fn restore(
25336        &mut self,
25337        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25338        window: &mut Window,
25339        cx: &mut Context<Self>,
25340    ) {
25341        self.buffer().update(cx, |multi_buffer, cx| {
25342            for (buffer_id, changes) in revert_changes {
25343                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25344                    buffer.update(cx, |buffer, cx| {
25345                        buffer.edit(
25346                            changes
25347                                .into_iter()
25348                                .map(|(range, text)| (range, text.to_string())),
25349                            None,
25350                            cx,
25351                        );
25352                    });
25353                }
25354            }
25355        });
25356        let selections = self
25357            .selections
25358            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
25359        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25360            s.select(selections);
25361        });
25362    }
25363
25364    pub fn to_pixel_point(
25365        &mut self,
25366        source: Anchor,
25367        editor_snapshot: &EditorSnapshot,
25368        window: &mut Window,
25369        cx: &mut App,
25370    ) -> Option<gpui::Point<Pixels>> {
25371        let source_point = source.to_display_point(editor_snapshot);
25372        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25373    }
25374
25375    pub fn display_to_pixel_point(
25376        &mut self,
25377        source: DisplayPoint,
25378        editor_snapshot: &EditorSnapshot,
25379        window: &mut Window,
25380        cx: &mut App,
25381    ) -> Option<gpui::Point<Pixels>> {
25382        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25383        let text_layout_details = self.text_layout_details(window, cx);
25384        let scroll_top = text_layout_details
25385            .scroll_anchor
25386            .scroll_position(editor_snapshot)
25387            .y;
25388
25389        if source.row().as_f64() < scroll_top.floor() {
25390            return None;
25391        }
25392        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25393        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25394        Some(gpui::Point::new(source_x, source_y))
25395    }
25396
25397    pub fn has_visible_completions_menu(&self) -> bool {
25398        !self.edit_prediction_preview_is_active()
25399            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25400                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25401            })
25402    }
25403
25404    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25405        if self.mode.is_minimap() {
25406            return;
25407        }
25408        self.addons
25409            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25410    }
25411
25412    pub fn unregister_addon<T: Addon>(&mut self) {
25413        self.addons.remove(&std::any::TypeId::of::<T>());
25414    }
25415
25416    pub fn addon<T: Addon>(&self) -> Option<&T> {
25417        let type_id = std::any::TypeId::of::<T>();
25418        self.addons
25419            .get(&type_id)
25420            .and_then(|item| item.to_any().downcast_ref::<T>())
25421    }
25422
25423    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25424        let type_id = std::any::TypeId::of::<T>();
25425        self.addons
25426            .get_mut(&type_id)
25427            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25428    }
25429
25430    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25431        let text_layout_details = self.text_layout_details(window, cx);
25432        let style = &text_layout_details.editor_style;
25433        let font_id = window.text_system().resolve_font(&style.text.font());
25434        let font_size = style.text.font_size.to_pixels(window.rem_size());
25435        let line_height = style.text.line_height_in_pixels(window.rem_size());
25436        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25437        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25438
25439        CharacterDimensions {
25440            em_width,
25441            em_advance,
25442            line_height,
25443        }
25444    }
25445
25446    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25447        self.load_diff_task.clone()
25448    }
25449
25450    fn read_metadata_from_db(
25451        &mut self,
25452        item_id: u64,
25453        workspace_id: WorkspaceId,
25454        window: &mut Window,
25455        cx: &mut Context<Editor>,
25456    ) {
25457        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25458            && !self.mode.is_minimap()
25459            && WorkspaceSettings::get(None, cx).restore_on_startup
25460                != RestoreOnStartupBehavior::EmptyTab
25461        {
25462            let buffer_snapshot = OnceCell::new();
25463
25464            // Get file path for path-based fold lookup
25465            let file_path: Option<Arc<Path>> =
25466                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25467                    project::File::from_dyn(buffer.read(cx).file())
25468                        .map(|file| Arc::from(file.abs_path(cx)))
25469                });
25470
25471            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25472            let db = EditorDb::global(cx);
25473            let (folds, needs_migration) = if let Some(ref path) = file_path {
25474                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25475                    && !folds.is_empty()
25476                {
25477                    (Some(folds), false)
25478                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25479                    && !folds.is_empty()
25480                {
25481                    // Found old editor_folds data, will migrate to file_folds
25482                    (Some(folds), true)
25483                } else {
25484                    (None, false)
25485                }
25486            } else {
25487                // No file path, try editor_folds as fallback
25488                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25489                (folds.filter(|f| !f.is_empty()), false)
25490            };
25491
25492            if let Some(folds) = folds {
25493                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25494                let snapshot_len = snapshot.len().0;
25495
25496                // Helper: search for fingerprint in buffer, return offset if found
25497                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25498                    // Ensure we start at a character boundary (defensive)
25499                    let search_start = snapshot
25500                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25501                        .0;
25502                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25503
25504                    let mut byte_offset = search_start;
25505                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25506                        if byte_offset > search_end {
25507                            break;
25508                        }
25509                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25510                            return Some(byte_offset);
25511                        }
25512                        byte_offset += ch.len_utf8();
25513                    }
25514                    None
25515                };
25516
25517                // Track search position to handle duplicate fingerprints correctly.
25518                // Folds are stored in document order, so we advance after each match.
25519                let mut search_start = 0usize;
25520
25521                // Collect db_folds for migration (only folds with valid fingerprints)
25522                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25523
25524                let valid_folds: Vec<_> = folds
25525                    .into_iter()
25526                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25527                        // Skip folds without fingerprints (old data before migration)
25528                        let sfp = start_fp?;
25529                        let efp = end_fp?;
25530                        let efp_len = efp.len();
25531
25532                        // Fast path: check if fingerprints match at stored offsets
25533                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25534                        let start_matches = stored_start < snapshot_len
25535                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25536                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25537                        let end_matches = efp_check_pos >= stored_start
25538                            && stored_end <= snapshot_len
25539                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25540
25541                        let (new_start, new_end) = if start_matches && end_matches {
25542                            // Offsets unchanged, use stored values
25543                            (stored_start, stored_end)
25544                        } else if sfp == efp {
25545                            // Short fold: identical fingerprints can only match once per search
25546                            // Use stored fold length to compute new_end
25547                            let new_start = find_fingerprint(&sfp, search_start)?;
25548                            let fold_len = stored_end - stored_start;
25549                            let new_end = new_start + fold_len;
25550                            (new_start, new_end)
25551                        } else {
25552                            // Slow path: search for fingerprints in buffer
25553                            let new_start = find_fingerprint(&sfp, search_start)?;
25554                            // Search for end_fp after start, then add efp_len to get actual fold end
25555                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25556                            let new_end = efp_pos + efp_len;
25557                            (new_start, new_end)
25558                        };
25559
25560                        // Advance search position for next fold
25561                        search_start = new_end;
25562
25563                        // Validate fold makes sense (end must be after start)
25564                        if new_end <= new_start {
25565                            return None;
25566                        }
25567
25568                        // Collect for migration if needed
25569                        if needs_migration {
25570                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25571                        }
25572
25573                        Some(
25574                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25575                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25576                        )
25577                    })
25578                    .collect();
25579
25580                if !valid_folds.is_empty() {
25581                    self.fold_ranges(valid_folds, false, window, cx);
25582
25583                    // Migrate from editor_folds to file_folds if we loaded from old table
25584                    if needs_migration {
25585                        if let Some(ref path) = file_path {
25586                            let path = path.clone();
25587                            let db = EditorDb::global(cx);
25588                            cx.spawn(async move |_, _| {
25589                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25590                                    .await
25591                                    .log_err();
25592                            })
25593                            .detach();
25594                        }
25595                    }
25596                }
25597            }
25598
25599            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25600                && !selections.is_empty()
25601            {
25602                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25603                // skip adding the initial selection to selection history
25604                self.selection_history.mode = SelectionHistoryMode::Skipping;
25605                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25606                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25607                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25608                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25609                    }));
25610                });
25611                self.selection_history.mode = SelectionHistoryMode::Normal;
25612            };
25613        }
25614
25615        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25616    }
25617
25618    /// Load folds from the file_folds database table by file path.
25619    /// Used when manually opening a file that was previously closed.
25620    fn load_folds_from_db(
25621        &mut self,
25622        workspace_id: WorkspaceId,
25623        file_path: PathBuf,
25624        window: &mut Window,
25625        cx: &mut Context<Editor>,
25626    ) {
25627        if self.mode.is_minimap()
25628            || WorkspaceSettings::get(None, cx).restore_on_startup
25629                == RestoreOnStartupBehavior::EmptyTab
25630        {
25631            return;
25632        }
25633
25634        let Some(folds) = EditorDb::global(cx)
25635            .get_file_folds(workspace_id, &file_path)
25636            .log_err()
25637        else {
25638            return;
25639        };
25640        if folds.is_empty() {
25641            return;
25642        }
25643
25644        let snapshot = self.buffer.read(cx).snapshot(cx);
25645        let snapshot_len = snapshot.len().0;
25646
25647        // Helper: search for fingerprint in buffer, return offset if found
25648        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25649            let search_start = snapshot
25650                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25651                .0;
25652            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25653
25654            let mut byte_offset = search_start;
25655            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25656                if byte_offset > search_end {
25657                    break;
25658                }
25659                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25660                    return Some(byte_offset);
25661                }
25662                byte_offset += ch.len_utf8();
25663            }
25664            None
25665        };
25666
25667        let mut search_start = 0usize;
25668
25669        let valid_folds: Vec<_> = folds
25670            .into_iter()
25671            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25672                let sfp = start_fp?;
25673                let efp = end_fp?;
25674                let efp_len = efp.len();
25675
25676                let start_matches = stored_start < snapshot_len
25677                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25678                let efp_check_pos = stored_end.saturating_sub(efp_len);
25679                let end_matches = efp_check_pos >= stored_start
25680                    && stored_end <= snapshot_len
25681                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25682
25683                let (new_start, new_end) = if start_matches && end_matches {
25684                    (stored_start, stored_end)
25685                } else if sfp == efp {
25686                    let new_start = find_fingerprint(&sfp, search_start)?;
25687                    let fold_len = stored_end - stored_start;
25688                    let new_end = new_start + fold_len;
25689                    (new_start, new_end)
25690                } else {
25691                    let new_start = find_fingerprint(&sfp, search_start)?;
25692                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25693                    let new_end = efp_pos + efp_len;
25694                    (new_start, new_end)
25695                };
25696
25697                search_start = new_end;
25698
25699                if new_end <= new_start {
25700                    return None;
25701                }
25702
25703                Some(
25704                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25705                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25706                )
25707            })
25708            .collect();
25709
25710        if !valid_folds.is_empty() {
25711            self.fold_ranges(valid_folds, false, window, cx);
25712        }
25713    }
25714
25715    fn lsp_data_enabled(&self) -> bool {
25716        self.enable_lsp_data && self.mode().is_full()
25717    }
25718
25719    fn update_lsp_data(
25720        &mut self,
25721        for_buffer: Option<BufferId>,
25722        window: &mut Window,
25723        cx: &mut Context<'_, Self>,
25724    ) {
25725        if !self.lsp_data_enabled() {
25726            return;
25727        }
25728
25729        if let Some(buffer_id) = for_buffer {
25730            self.pull_diagnostics(buffer_id, window, cx);
25731        }
25732        self.refresh_semantic_tokens(for_buffer, None, cx);
25733        self.refresh_document_colors(for_buffer, window, cx);
25734        self.refresh_folding_ranges(for_buffer, window, cx);
25735        self.refresh_document_symbols(for_buffer, cx);
25736    }
25737
25738    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25739        if !self.lsp_data_enabled() {
25740            return;
25741        }
25742        let visible_buffers: Vec<_> = self
25743            .visible_buffers(cx)
25744            .into_iter()
25745            .filter(|buffer| self.is_lsp_relevant(buffer.read(cx).file(), cx))
25746            .collect();
25747        for visible_buffer in visible_buffers {
25748            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25749        }
25750    }
25751
25752    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25753        if !self.lsp_data_enabled() {
25754            return;
25755        }
25756
25757        if !self.registered_buffers.contains_key(&buffer_id)
25758            && let Some(project) = self.project.as_ref()
25759        {
25760            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25761                project.update(cx, |project, cx| {
25762                    self.registered_buffers.insert(
25763                        buffer_id,
25764                        project.register_buffer_with_language_servers(&buffer, cx),
25765                    );
25766                });
25767            } else {
25768                self.registered_buffers.remove(&buffer_id);
25769            }
25770        }
25771    }
25772
25773    fn create_style(&self, cx: &App) -> EditorStyle {
25774        let settings = ThemeSettings::get_global(cx);
25775
25776        let mut text_style = match self.mode {
25777            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25778                color: cx.theme().colors().editor_foreground,
25779                font_family: settings.ui_font.family.clone(),
25780                font_features: settings.ui_font.features.clone(),
25781                font_fallbacks: settings.ui_font.fallbacks.clone(),
25782                font_size: rems(0.875).into(),
25783                font_weight: settings.ui_font.weight,
25784                line_height: relative(settings.buffer_line_height.value()),
25785                ..Default::default()
25786            },
25787            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25788                color: cx.theme().colors().editor_foreground,
25789                font_family: settings.buffer_font.family.clone(),
25790                font_features: settings.buffer_font.features.clone(),
25791                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25792                font_size: settings.buffer_font_size(cx).into(),
25793                font_weight: settings.buffer_font.weight,
25794                line_height: relative(settings.buffer_line_height.value()),
25795                ..Default::default()
25796            },
25797        };
25798        if let Some(text_style_refinement) = &self.text_style_refinement {
25799            text_style.refine(text_style_refinement)
25800        }
25801
25802        let background = match self.mode {
25803            EditorMode::SingleLine => cx.theme().system().transparent,
25804            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25805            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25806            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25807        };
25808
25809        EditorStyle {
25810            background,
25811            border: cx.theme().colors().border,
25812            local_player: cx.theme().players().local(),
25813            text: text_style,
25814            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25815            syntax: cx.theme().syntax().clone(),
25816            status: cx.theme().status().clone(),
25817            inlay_hints_style: make_inlay_hints_style(cx),
25818            edit_prediction_styles: make_suggestion_styles(cx),
25819            unnecessary_code_fade: settings.unnecessary_code_fade,
25820            show_underlines: self.diagnostics_enabled(),
25821        }
25822    }
25823
25824    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25825        let multibuffer = self.buffer().read(cx);
25826        let is_singleton = multibuffer.is_singleton();
25827        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25828        let buffer = multibuffer.buffer(*buffer_id)?;
25829
25830        let buffer = buffer.read(cx);
25831        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25832        let mut breadcrumbs = if is_singleton {
25833            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25834                buffer
25835                    .snapshot()
25836                    .resolve_file_path(
25837                        self.project
25838                            .as_ref()
25839                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25840                            .unwrap_or_default(),
25841                        cx,
25842                    )
25843                    .unwrap_or_else(|| {
25844                        if multibuffer.is_singleton() {
25845                            multibuffer.title(cx).to_string()
25846                        } else {
25847                            "untitled".to_string()
25848                        }
25849                    })
25850            });
25851            vec![HighlightedText {
25852                text: text.into(),
25853                highlights: vec![],
25854            }]
25855        } else {
25856            vec![]
25857        };
25858
25859        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25860            text: symbol.text.clone().into(),
25861            highlights: symbol.highlight_ranges.clone(),
25862        }));
25863        Some(breadcrumbs)
25864    }
25865
25866    fn disable_lsp_data(&mut self) {
25867        self.enable_lsp_data = false;
25868    }
25869
25870    fn disable_runnables(&mut self) {
25871        self.enable_runnables = false;
25872    }
25873
25874    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25875        self.register_visible_buffers(cx);
25876        self.colorize_brackets(false, cx);
25877        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25878        if !self.buffer().read(cx).is_singleton() {
25879            self.update_lsp_data(None, window, cx);
25880            self.refresh_runnables(None, window, cx);
25881        }
25882    }
25883}
25884
25885fn edit_for_markdown_paste<'a>(
25886    buffer: &MultiBufferSnapshot,
25887    range: Range<MultiBufferOffset>,
25888    to_insert: &'a str,
25889    url: Option<url::Url>,
25890) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25891    if url.is_none() {
25892        return (range, Cow::Borrowed(to_insert));
25893    };
25894
25895    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25896
25897    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25898        Cow::Borrowed(to_insert)
25899    } else {
25900        Cow::Owned(format!("[{old_text}]({to_insert})"))
25901    };
25902    (range, new_text)
25903}
25904
25905fn process_completion_for_edit(
25906    completion: &Completion,
25907    intent: CompletionIntent,
25908    buffer: &Entity<Buffer>,
25909    cursor_position: &text::Anchor,
25910    cx: &mut Context<Editor>,
25911) -> CompletionEdit {
25912    let buffer = buffer.read(cx);
25913    let buffer_snapshot = buffer.snapshot();
25914    let (snippet, new_text) = if completion.is_snippet() {
25915        let mut snippet_source = completion.new_text.clone();
25916        // Workaround for typescript language server issues so that methods don't expand within
25917        // strings and functions with type expressions. The previous point is used because the query
25918        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25919        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25920        let previous_point = if previous_point.column > 0 {
25921            cursor_position.to_previous_offset(&buffer_snapshot)
25922        } else {
25923            cursor_position.to_offset(&buffer_snapshot)
25924        };
25925        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25926            && scope.prefers_label_for_snippet_in_completion()
25927            && let Some(label) = completion.label()
25928            && matches!(
25929                completion.kind(),
25930                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25931            )
25932        {
25933            snippet_source = label;
25934        }
25935        match Snippet::parse(&snippet_source).log_err() {
25936            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25937            None => (None, completion.new_text.clone()),
25938        }
25939    } else {
25940        (None, completion.new_text.clone())
25941    };
25942
25943    let mut range_to_replace = {
25944        let replace_range = &completion.replace_range;
25945        if let CompletionSource::Lsp {
25946            insert_range: Some(insert_range),
25947            ..
25948        } = &completion.source
25949        {
25950            debug_assert_eq!(
25951                insert_range.start, replace_range.start,
25952                "insert_range and replace_range should start at the same position"
25953            );
25954            debug_assert!(
25955                insert_range
25956                    .start
25957                    .cmp(cursor_position, &buffer_snapshot)
25958                    .is_le(),
25959                "insert_range should start before or at cursor position"
25960            );
25961            debug_assert!(
25962                replace_range
25963                    .start
25964                    .cmp(cursor_position, &buffer_snapshot)
25965                    .is_le(),
25966                "replace_range should start before or at cursor position"
25967            );
25968
25969            let should_replace = match intent {
25970                CompletionIntent::CompleteWithInsert => false,
25971                CompletionIntent::CompleteWithReplace => true,
25972                CompletionIntent::Complete | CompletionIntent::Compose => {
25973                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
25974                        .completions
25975                        .lsp_insert_mode;
25976                    match insert_mode {
25977                        LspInsertMode::Insert => false,
25978                        LspInsertMode::Replace => true,
25979                        LspInsertMode::ReplaceSubsequence => {
25980                            let mut text_to_replace = buffer.chars_for_range(
25981                                buffer.anchor_before(replace_range.start)
25982                                    ..buffer.anchor_after(replace_range.end),
25983                            );
25984                            let mut current_needle = text_to_replace.next();
25985                            for haystack_ch in completion.label.text.chars() {
25986                                if let Some(needle_ch) = current_needle
25987                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25988                                {
25989                                    current_needle = text_to_replace.next();
25990                                }
25991                            }
25992                            current_needle.is_none()
25993                        }
25994                        LspInsertMode::ReplaceSuffix => {
25995                            if replace_range
25996                                .end
25997                                .cmp(cursor_position, &buffer_snapshot)
25998                                .is_gt()
25999                            {
26000                                let range_after_cursor = *cursor_position..replace_range.end;
26001                                let text_after_cursor = buffer
26002                                    .text_for_range(
26003                                        buffer.anchor_before(range_after_cursor.start)
26004                                            ..buffer.anchor_after(range_after_cursor.end),
26005                                    )
26006                                    .collect::<String>()
26007                                    .to_ascii_lowercase();
26008                                completion
26009                                    .label
26010                                    .text
26011                                    .to_ascii_lowercase()
26012                                    .ends_with(&text_after_cursor)
26013                            } else {
26014                                true
26015                            }
26016                        }
26017                    }
26018                }
26019            };
26020
26021            if should_replace {
26022                replace_range.clone()
26023            } else {
26024                insert_range.clone()
26025            }
26026        } else {
26027            replace_range.clone()
26028        }
26029    };
26030
26031    if range_to_replace
26032        .end
26033        .cmp(cursor_position, &buffer_snapshot)
26034        .is_lt()
26035    {
26036        range_to_replace.end = *cursor_position;
26037    }
26038
26039    CompletionEdit {
26040        new_text,
26041        replace_range: range_to_replace,
26042        snippet,
26043    }
26044}
26045
26046struct CompletionEdit {
26047    new_text: String,
26048    replace_range: Range<text::Anchor>,
26049    snippet: Option<Snippet>,
26050}
26051
26052fn comment_delimiter_for_newline(
26053    start_point: &Point,
26054    buffer: &MultiBufferSnapshot,
26055    language: &LanguageScope,
26056) -> Option<Arc<str>> {
26057    let delimiters = language.line_comment_prefixes();
26058    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26059    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26060
26061    let num_of_whitespaces = snapshot
26062        .chars_for_range(range.clone())
26063        .take_while(|c| c.is_whitespace())
26064        .count();
26065    let comment_candidate = snapshot
26066        .chars_for_range(range.clone())
26067        .skip(num_of_whitespaces)
26068        .take(max_len_of_delimiter + 2)
26069        .collect::<String>();
26070    let (delimiter, trimmed_len, is_repl) = delimiters
26071        .iter()
26072        .filter_map(|delimiter| {
26073            let prefix = delimiter.trim_end();
26074            if comment_candidate.starts_with(prefix) {
26075                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26076                {
26077                    stripped_comment.starts_with(" %%")
26078                } else {
26079                    false
26080                };
26081                Some((delimiter, prefix.len(), is_repl))
26082            } else {
26083                None
26084            }
26085        })
26086        .max_by_key(|(_, len, _)| *len)?;
26087
26088    if let Some(BlockCommentConfig {
26089        start: block_start, ..
26090    }) = language.block_comment()
26091    {
26092        let block_start_trimmed = block_start.trim_end();
26093        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26094            let line_content = snapshot
26095                .chars_for_range(range.clone())
26096                .skip(num_of_whitespaces)
26097                .take(block_start_trimmed.len())
26098                .collect::<String>();
26099
26100            if line_content.starts_with(block_start_trimmed) {
26101                return None;
26102            }
26103        }
26104    }
26105
26106    let cursor_is_placed_after_comment_marker =
26107        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26108    if cursor_is_placed_after_comment_marker {
26109        if !is_repl {
26110            return Some(delimiter.clone());
26111        }
26112
26113        let line_content_after_cursor: String = snapshot
26114            .chars_for_range(range)
26115            .skip(start_point.column as usize)
26116            .collect();
26117
26118        if line_content_after_cursor.trim().is_empty() {
26119            return None;
26120        } else {
26121            return Some(delimiter.clone());
26122        }
26123    } else {
26124        None
26125    }
26126}
26127
26128fn documentation_delimiter_for_newline(
26129    start_point: &Point,
26130    buffer: &MultiBufferSnapshot,
26131    language: &LanguageScope,
26132    newline_config: &mut NewlineConfig,
26133) -> Option<Arc<str>> {
26134    let BlockCommentConfig {
26135        start: start_tag,
26136        end: end_tag,
26137        prefix: delimiter,
26138        tab_size: len,
26139    } = language.documentation_comment()?;
26140    let is_within_block_comment = buffer
26141        .language_scope_at(*start_point)
26142        .is_some_and(|scope| scope.override_name() == Some("comment"));
26143    if !is_within_block_comment {
26144        return None;
26145    }
26146
26147    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26148
26149    let num_of_whitespaces = snapshot
26150        .chars_for_range(range.clone())
26151        .take_while(|c| c.is_whitespace())
26152        .count();
26153
26154    // 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.
26155    let column = start_point.column;
26156    let cursor_is_after_start_tag = {
26157        let start_tag_len = start_tag.len();
26158        let start_tag_line = snapshot
26159            .chars_for_range(range.clone())
26160            .skip(num_of_whitespaces)
26161            .take(start_tag_len)
26162            .collect::<String>();
26163        if start_tag_line.starts_with(start_tag.as_ref()) {
26164            num_of_whitespaces + start_tag_len <= column as usize
26165        } else {
26166            false
26167        }
26168    };
26169
26170    let cursor_is_after_delimiter = {
26171        let delimiter_trim = delimiter.trim_end();
26172        let delimiter_line = snapshot
26173            .chars_for_range(range.clone())
26174            .skip(num_of_whitespaces)
26175            .take(delimiter_trim.len())
26176            .collect::<String>();
26177        if delimiter_line.starts_with(delimiter_trim) {
26178            num_of_whitespaces + delimiter_trim.len() <= column as usize
26179        } else {
26180            false
26181        }
26182    };
26183
26184    let mut needs_extra_line = false;
26185    let mut extra_line_additional_indent = IndentSize::spaces(0);
26186
26187    let cursor_is_before_end_tag_if_exists = {
26188        let mut char_position = 0u32;
26189        let mut end_tag_offset = None;
26190
26191        'outer: for chunk in snapshot.text_for_range(range) {
26192            if let Some(byte_pos) = chunk.find(&**end_tag) {
26193                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26194                end_tag_offset = Some(char_position + chars_before_match);
26195                break 'outer;
26196            }
26197            char_position += chunk.chars().count() as u32;
26198        }
26199
26200        if let Some(end_tag_offset) = end_tag_offset {
26201            let cursor_is_before_end_tag = column <= end_tag_offset;
26202            if cursor_is_after_start_tag {
26203                if cursor_is_before_end_tag {
26204                    needs_extra_line = true;
26205                }
26206                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26207                if cursor_is_at_start_of_end_tag {
26208                    extra_line_additional_indent.len = *len;
26209                }
26210            }
26211            cursor_is_before_end_tag
26212        } else {
26213            true
26214        }
26215    };
26216
26217    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26218        && cursor_is_before_end_tag_if_exists
26219    {
26220        let additional_indent = if cursor_is_after_start_tag {
26221            IndentSize::spaces(*len)
26222        } else {
26223            IndentSize::spaces(0)
26224        };
26225
26226        *newline_config = NewlineConfig::Newline {
26227            additional_indent,
26228            extra_line_additional_indent: if needs_extra_line {
26229                Some(extra_line_additional_indent)
26230            } else {
26231                None
26232            },
26233            prevent_auto_indent: true,
26234        };
26235        Some(delimiter.clone())
26236    } else {
26237        None
26238    }
26239}
26240
26241const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26242
26243fn list_delimiter_for_newline(
26244    start_point: &Point,
26245    buffer: &MultiBufferSnapshot,
26246    language: &LanguageScope,
26247    newline_config: &mut NewlineConfig,
26248) -> Option<Arc<str>> {
26249    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26250
26251    let num_of_whitespaces = snapshot
26252        .chars_for_range(range.clone())
26253        .take_while(|c| c.is_whitespace())
26254        .count();
26255
26256    let task_list_entries: Vec<_> = language
26257        .task_list()
26258        .into_iter()
26259        .flat_map(|config| {
26260            config
26261                .prefixes
26262                .iter()
26263                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26264        })
26265        .collect();
26266    let unordered_list_entries: Vec<_> = language
26267        .unordered_list()
26268        .iter()
26269        .map(|marker| (marker.as_ref(), marker.as_ref()))
26270        .collect();
26271
26272    let all_entries: Vec<_> = task_list_entries
26273        .into_iter()
26274        .chain(unordered_list_entries)
26275        .collect();
26276
26277    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26278        let candidate: String = snapshot
26279            .chars_for_range(range.clone())
26280            .skip(num_of_whitespaces)
26281            .take(max_prefix_len)
26282            .collect();
26283
26284        if let Some((prefix, continuation)) = all_entries
26285            .iter()
26286            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26287            .max_by_key(|(prefix, _)| prefix.len())
26288        {
26289            let end_of_prefix = num_of_whitespaces + prefix.len();
26290            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26291            let has_content_after_marker = snapshot
26292                .chars_for_range(range)
26293                .skip(end_of_prefix)
26294                .any(|c| !c.is_whitespace());
26295
26296            if has_content_after_marker && cursor_is_after_prefix {
26297                return Some((*continuation).into());
26298            }
26299
26300            if start_point.column as usize == end_of_prefix {
26301                if num_of_whitespaces == 0 {
26302                    *newline_config = NewlineConfig::ClearCurrentLine;
26303                } else {
26304                    *newline_config = NewlineConfig::UnindentCurrentLine {
26305                        continuation: (*continuation).into(),
26306                    };
26307                }
26308            }
26309
26310            return None;
26311        }
26312    }
26313
26314    let candidate: String = snapshot
26315        .chars_for_range(range.clone())
26316        .skip(num_of_whitespaces)
26317        .take(ORDERED_LIST_MAX_MARKER_LEN)
26318        .collect();
26319
26320    for ordered_config in language.ordered_list() {
26321        let regex = match Regex::new(&ordered_config.pattern) {
26322            Ok(r) => r,
26323            Err(_) => continue,
26324        };
26325
26326        if let Some(captures) = regex.captures(&candidate) {
26327            let full_match = captures.get(0)?;
26328            let marker_len = full_match.len();
26329            let end_of_prefix = num_of_whitespaces + marker_len;
26330            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26331
26332            let has_content_after_marker = snapshot
26333                .chars_for_range(range)
26334                .skip(end_of_prefix)
26335                .any(|c| !c.is_whitespace());
26336
26337            if has_content_after_marker && cursor_is_after_prefix {
26338                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26339                let continuation = ordered_config
26340                    .format
26341                    .replace("{1}", &(number + 1).to_string());
26342                return Some(continuation.into());
26343            }
26344
26345            if start_point.column as usize == end_of_prefix {
26346                let continuation = ordered_config.format.replace("{1}", "1");
26347                if num_of_whitespaces == 0 {
26348                    *newline_config = NewlineConfig::ClearCurrentLine;
26349                } else {
26350                    *newline_config = NewlineConfig::UnindentCurrentLine {
26351                        continuation: continuation.into(),
26352                    };
26353                }
26354            }
26355
26356            return None;
26357        }
26358    }
26359
26360    None
26361}
26362
26363fn is_list_prefix_row(
26364    row: MultiBufferRow,
26365    buffer: &MultiBufferSnapshot,
26366    language: &LanguageScope,
26367) -> bool {
26368    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26369        return false;
26370    };
26371
26372    let num_of_whitespaces = snapshot
26373        .chars_for_range(range.clone())
26374        .take_while(|c| c.is_whitespace())
26375        .count();
26376
26377    let task_list_prefixes: Vec<_> = language
26378        .task_list()
26379        .into_iter()
26380        .flat_map(|config| {
26381            config
26382                .prefixes
26383                .iter()
26384                .map(|p| p.as_ref())
26385                .collect::<Vec<_>>()
26386        })
26387        .collect();
26388    let unordered_list_markers: Vec<_> = language
26389        .unordered_list()
26390        .iter()
26391        .map(|marker| marker.as_ref())
26392        .collect();
26393    let all_prefixes: Vec<_> = task_list_prefixes
26394        .into_iter()
26395        .chain(unordered_list_markers)
26396        .collect();
26397    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26398        let candidate: String = snapshot
26399            .chars_for_range(range.clone())
26400            .skip(num_of_whitespaces)
26401            .take(max_prefix_len)
26402            .collect();
26403        if all_prefixes
26404            .iter()
26405            .any(|prefix| candidate.starts_with(*prefix))
26406        {
26407            return true;
26408        }
26409    }
26410
26411    let ordered_list_candidate: String = snapshot
26412        .chars_for_range(range)
26413        .skip(num_of_whitespaces)
26414        .take(ORDERED_LIST_MAX_MARKER_LEN)
26415        .collect();
26416    for ordered_config in language.ordered_list() {
26417        let regex = match Regex::new(&ordered_config.pattern) {
26418            Ok(r) => r,
26419            Err(_) => continue,
26420        };
26421        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26422            return captures.get(0).is_some();
26423        }
26424    }
26425
26426    false
26427}
26428
26429#[derive(Debug)]
26430enum NewlineConfig {
26431    /// Insert newline with optional additional indent and optional extra blank line
26432    Newline {
26433        additional_indent: IndentSize,
26434        extra_line_additional_indent: Option<IndentSize>,
26435        prevent_auto_indent: bool,
26436    },
26437    /// Clear the current line
26438    ClearCurrentLine,
26439    /// Unindent the current line and add continuation
26440    UnindentCurrentLine { continuation: Arc<str> },
26441}
26442
26443impl NewlineConfig {
26444    fn has_extra_line(&self) -> bool {
26445        matches!(
26446            self,
26447            Self::Newline {
26448                extra_line_additional_indent: Some(_),
26449                ..
26450            }
26451        )
26452    }
26453
26454    fn insert_extra_newline_brackets(
26455        buffer: &MultiBufferSnapshot,
26456        range: Range<MultiBufferOffset>,
26457        language: &language::LanguageScope,
26458    ) -> bool {
26459        let leading_whitespace_len = buffer
26460            .reversed_chars_at(range.start)
26461            .take_while(|c| c.is_whitespace() && *c != '\n')
26462            .map(|c| c.len_utf8())
26463            .sum::<usize>();
26464        let trailing_whitespace_len = buffer
26465            .chars_at(range.end)
26466            .take_while(|c| c.is_whitespace() && *c != '\n')
26467            .map(|c| c.len_utf8())
26468            .sum::<usize>();
26469        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26470
26471        language.brackets().any(|(pair, enabled)| {
26472            let pair_start = pair.start.trim_end();
26473            let pair_end = pair.end.trim_start();
26474
26475            enabled
26476                && pair.newline
26477                && buffer.contains_str_at(range.end, pair_end)
26478                && buffer.contains_str_at(
26479                    range.start.saturating_sub_usize(pair_start.len()),
26480                    pair_start,
26481                )
26482        })
26483    }
26484
26485    fn insert_extra_newline_tree_sitter(
26486        buffer: &MultiBufferSnapshot,
26487        range: Range<MultiBufferOffset>,
26488    ) -> bool {
26489        let (buffer, range) = match buffer
26490            .range_to_buffer_ranges(range.start..range.end)
26491            .as_slice()
26492        {
26493            [(buffer_snapshot, range, _)] => (buffer_snapshot.clone(), range.clone()),
26494            _ => return false,
26495        };
26496        let pair = {
26497            let mut result: Option<BracketMatch<usize>> = None;
26498
26499            for pair in buffer
26500                .all_bracket_ranges(range.start.0..range.end.0)
26501                .filter(move |pair| {
26502                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26503                })
26504            {
26505                let len = pair.close_range.end - pair.open_range.start;
26506
26507                if let Some(existing) = &result {
26508                    let existing_len = existing.close_range.end - existing.open_range.start;
26509                    if len > existing_len {
26510                        continue;
26511                    }
26512                }
26513
26514                result = Some(pair);
26515            }
26516
26517            result
26518        };
26519        let Some(pair) = pair else {
26520            return false;
26521        };
26522        pair.newline_only
26523            && buffer
26524                .chars_for_range(pair.open_range.end..range.start.0)
26525                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26526                .all(|c| c.is_whitespace() && c != '\n')
26527    }
26528}
26529
26530fn update_uncommitted_diff_for_buffer(
26531    editor: Entity<Editor>,
26532    project: &Entity<Project>,
26533    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26534    buffer: Entity<MultiBuffer>,
26535    cx: &mut App,
26536) -> Task<()> {
26537    let mut tasks = Vec::new();
26538    project.update(cx, |project, cx| {
26539        for buffer in buffers {
26540            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26541                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26542            }
26543        }
26544    });
26545    cx.spawn(async move |cx| {
26546        let diffs = future::join_all(tasks).await;
26547        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26548            return;
26549        }
26550
26551        buffer.update(cx, |buffer, cx| {
26552            for diff in diffs.into_iter().flatten() {
26553                buffer.add_diff(diff, cx);
26554            }
26555        });
26556    })
26557}
26558
26559fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26560    let tab_size = tab_size.get() as usize;
26561    let mut width = offset;
26562
26563    for ch in text.chars() {
26564        width += if ch == '\t' {
26565            tab_size - (width % tab_size)
26566        } else {
26567            1
26568        };
26569    }
26570
26571    width - offset
26572}
26573
26574#[cfg(test)]
26575mod tests {
26576    use super::*;
26577
26578    #[test]
26579    fn test_string_size_with_expanded_tabs() {
26580        let nz = |val| NonZeroU32::new(val).unwrap();
26581        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26582        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26583        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26584        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26585        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26586        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26587        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26588        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26589    }
26590}
26591
26592/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26593struct WordBreakingTokenizer<'a> {
26594    input: &'a str,
26595}
26596
26597impl<'a> WordBreakingTokenizer<'a> {
26598    fn new(input: &'a str) -> Self {
26599        Self { input }
26600    }
26601}
26602
26603fn is_char_ideographic(ch: char) -> bool {
26604    use unicode_script::Script::*;
26605    use unicode_script::UnicodeScript;
26606    matches!(ch.script(), Han | Tangut | Yi)
26607}
26608
26609fn is_grapheme_ideographic(text: &str) -> bool {
26610    text.chars().any(is_char_ideographic)
26611}
26612
26613fn is_grapheme_whitespace(text: &str) -> bool {
26614    text.chars().any(|x| x.is_whitespace())
26615}
26616
26617fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26618    text.chars()
26619        .next()
26620        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26621}
26622
26623#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26624enum WordBreakToken<'a> {
26625    Word { token: &'a str, grapheme_len: usize },
26626    InlineWhitespace { token: &'a str, grapheme_len: usize },
26627    Newline,
26628}
26629
26630impl<'a> Iterator for WordBreakingTokenizer<'a> {
26631    /// Yields a span, the count of graphemes in the token, and whether it was
26632    /// whitespace. Note that it also breaks at word boundaries.
26633    type Item = WordBreakToken<'a>;
26634
26635    fn next(&mut self) -> Option<Self::Item> {
26636        use unicode_segmentation::UnicodeSegmentation;
26637        if self.input.is_empty() {
26638            return None;
26639        }
26640
26641        let mut iter = self.input.graphemes(true).peekable();
26642        let mut offset = 0;
26643        let mut grapheme_len = 0;
26644        if let Some(first_grapheme) = iter.next() {
26645            let is_newline = first_grapheme == "\n";
26646            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26647            offset += first_grapheme.len();
26648            grapheme_len += 1;
26649            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26650                if let Some(grapheme) = iter.peek().copied()
26651                    && should_stay_with_preceding_ideograph(grapheme)
26652                {
26653                    offset += grapheme.len();
26654                    grapheme_len += 1;
26655                }
26656            } else {
26657                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26658                let mut next_word_bound = words.peek().copied();
26659                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26660                    next_word_bound = words.next();
26661                }
26662                while let Some(grapheme) = iter.peek().copied() {
26663                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26664                        break;
26665                    };
26666                    if is_grapheme_whitespace(grapheme) != is_whitespace
26667                        || (grapheme == "\n") != is_newline
26668                    {
26669                        break;
26670                    };
26671                    offset += grapheme.len();
26672                    grapheme_len += 1;
26673                    iter.next();
26674                }
26675            }
26676            let token = &self.input[..offset];
26677            self.input = &self.input[offset..];
26678            if token == "\n" {
26679                Some(WordBreakToken::Newline)
26680            } else if is_whitespace {
26681                Some(WordBreakToken::InlineWhitespace {
26682                    token,
26683                    grapheme_len,
26684                })
26685            } else {
26686                Some(WordBreakToken::Word {
26687                    token,
26688                    grapheme_len,
26689                })
26690            }
26691        } else {
26692            None
26693        }
26694    }
26695}
26696
26697#[test]
26698fn test_word_breaking_tokenizer() {
26699    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26700        ("", &[]),
26701        ("  ", &[whitespace("  ", 2)]),
26702        ("Ʒ", &[word("Ʒ", 1)]),
26703        ("Ǽ", &[word("Ǽ", 1)]),
26704        ("", &[word("", 1)]),
26705        ("⋑⋑", &[word("⋑⋑", 2)]),
26706        (
26707            "原理,进而",
26708            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26709        ),
26710        (
26711            "hello world",
26712            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26713        ),
26714        (
26715            "hello, world",
26716            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26717        ),
26718        (
26719            "  hello world",
26720            &[
26721                whitespace("  ", 2),
26722                word("hello", 5),
26723                whitespace(" ", 1),
26724                word("world", 5),
26725            ],
26726        ),
26727        (
26728            "这是什么 \n 钢笔",
26729            &[
26730                word("", 1),
26731                word("", 1),
26732                word("", 1),
26733                word("", 1),
26734                whitespace(" ", 1),
26735                newline(),
26736                whitespace(" ", 1),
26737                word("", 1),
26738                word("", 1),
26739            ],
26740        ),
26741        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26742    ];
26743
26744    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26745        WordBreakToken::Word {
26746            token,
26747            grapheme_len,
26748        }
26749    }
26750
26751    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26752        WordBreakToken::InlineWhitespace {
26753            token,
26754            grapheme_len,
26755        }
26756    }
26757
26758    fn newline() -> WordBreakToken<'static> {
26759        WordBreakToken::Newline
26760    }
26761
26762    for (input, result) in tests {
26763        assert_eq!(
26764            WordBreakingTokenizer::new(input)
26765                .collect::<Vec<_>>()
26766                .as_slice(),
26767            *result,
26768        );
26769    }
26770}
26771
26772fn wrap_with_prefix(
26773    first_line_prefix: String,
26774    subsequent_lines_prefix: String,
26775    unwrapped_text: String,
26776    wrap_column: usize,
26777    tab_size: NonZeroU32,
26778    preserve_existing_whitespace: bool,
26779) -> String {
26780    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26781    let subsequent_lines_prefix_len =
26782        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26783    let mut wrapped_text = String::new();
26784    let mut current_line = first_line_prefix;
26785    let mut is_first_line = true;
26786
26787    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26788    let mut current_line_len = first_line_prefix_len;
26789    let mut in_whitespace = false;
26790    for token in tokenizer {
26791        let have_preceding_whitespace = in_whitespace;
26792        match token {
26793            WordBreakToken::Word {
26794                token,
26795                grapheme_len,
26796            } => {
26797                in_whitespace = false;
26798                let current_prefix_len = if is_first_line {
26799                    first_line_prefix_len
26800                } else {
26801                    subsequent_lines_prefix_len
26802                };
26803                if current_line_len + grapheme_len > wrap_column
26804                    && current_line_len != current_prefix_len
26805                {
26806                    wrapped_text.push_str(current_line.trim_end());
26807                    wrapped_text.push('\n');
26808                    is_first_line = false;
26809                    current_line = subsequent_lines_prefix.clone();
26810                    current_line_len = subsequent_lines_prefix_len;
26811                }
26812                current_line.push_str(token);
26813                current_line_len += grapheme_len;
26814            }
26815            WordBreakToken::InlineWhitespace {
26816                mut token,
26817                mut grapheme_len,
26818            } => {
26819                in_whitespace = true;
26820                if have_preceding_whitespace && !preserve_existing_whitespace {
26821                    continue;
26822                }
26823                if !preserve_existing_whitespace {
26824                    // Keep a single whitespace grapheme as-is
26825                    if let Some(first) =
26826                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26827                    {
26828                        token = first;
26829                    } else {
26830                        token = " ";
26831                    }
26832                    grapheme_len = 1;
26833                }
26834                let current_prefix_len = if is_first_line {
26835                    first_line_prefix_len
26836                } else {
26837                    subsequent_lines_prefix_len
26838                };
26839                if current_line_len + grapheme_len > wrap_column {
26840                    wrapped_text.push_str(current_line.trim_end());
26841                    wrapped_text.push('\n');
26842                    is_first_line = false;
26843                    current_line = subsequent_lines_prefix.clone();
26844                    current_line_len = subsequent_lines_prefix_len;
26845                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26846                    current_line.push_str(token);
26847                    current_line_len += grapheme_len;
26848                }
26849            }
26850            WordBreakToken::Newline => {
26851                in_whitespace = true;
26852                let current_prefix_len = if is_first_line {
26853                    first_line_prefix_len
26854                } else {
26855                    subsequent_lines_prefix_len
26856                };
26857                if preserve_existing_whitespace {
26858                    wrapped_text.push_str(current_line.trim_end());
26859                    wrapped_text.push('\n');
26860                    is_first_line = false;
26861                    current_line = subsequent_lines_prefix.clone();
26862                    current_line_len = subsequent_lines_prefix_len;
26863                } else if have_preceding_whitespace {
26864                    continue;
26865                } else if current_line_len + 1 > wrap_column
26866                    && current_line_len != current_prefix_len
26867                {
26868                    wrapped_text.push_str(current_line.trim_end());
26869                    wrapped_text.push('\n');
26870                    is_first_line = false;
26871                    current_line = subsequent_lines_prefix.clone();
26872                    current_line_len = subsequent_lines_prefix_len;
26873                } else if current_line_len != current_prefix_len {
26874                    current_line.push(' ');
26875                    current_line_len += 1;
26876                }
26877            }
26878        }
26879    }
26880
26881    if !current_line.is_empty() {
26882        wrapped_text.push_str(&current_line);
26883    }
26884    wrapped_text
26885}
26886
26887#[test]
26888fn test_wrap_with_prefix() {
26889    assert_eq!(
26890        wrap_with_prefix(
26891            "# ".to_string(),
26892            "# ".to_string(),
26893            "abcdefg".to_string(),
26894            4,
26895            NonZeroU32::new(4).unwrap(),
26896            false,
26897        ),
26898        "# abcdefg"
26899    );
26900    assert_eq!(
26901        wrap_with_prefix(
26902            "".to_string(),
26903            "".to_string(),
26904            "\thello world".to_string(),
26905            8,
26906            NonZeroU32::new(4).unwrap(),
26907            false,
26908        ),
26909        "hello\nworld"
26910    );
26911    assert_eq!(
26912        wrap_with_prefix(
26913            "// ".to_string(),
26914            "// ".to_string(),
26915            "xx \nyy zz aa bb cc".to_string(),
26916            12,
26917            NonZeroU32::new(4).unwrap(),
26918            false,
26919        ),
26920        "// xx yy zz\n// aa bb cc"
26921    );
26922    assert_eq!(
26923        wrap_with_prefix(
26924            String::new(),
26925            String::new(),
26926            "这是什么 \n 钢笔".to_string(),
26927            3,
26928            NonZeroU32::new(4).unwrap(),
26929            false,
26930        ),
26931        "这是什\n么 钢\n"
26932    );
26933    assert_eq!(
26934        wrap_with_prefix(
26935            String::new(),
26936            String::new(),
26937            format!("foo{}bar", '\u{2009}'), // thin space
26938            80,
26939            NonZeroU32::new(4).unwrap(),
26940            false,
26941        ),
26942        format!("foo{}bar", '\u{2009}')
26943    );
26944}
26945
26946pub trait CollaborationHub {
26947    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26948    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26949    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26950}
26951
26952impl CollaborationHub for Entity<Project> {
26953    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26954        self.read(cx).collaborators()
26955    }
26956
26957    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26958        self.read(cx).user_store().read(cx).participant_indices()
26959    }
26960
26961    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26962        let this = self.read(cx);
26963        let user_ids = this.collaborators().values().map(|c| c.user_id);
26964        this.user_store().read(cx).participant_names(user_ids, cx)
26965    }
26966}
26967
26968pub trait SemanticsProvider {
26969    fn hover(
26970        &self,
26971        buffer: &Entity<Buffer>,
26972        position: text::Anchor,
26973        cx: &mut App,
26974    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26975
26976    fn inline_values(
26977        &self,
26978        buffer_handle: Entity<Buffer>,
26979        range: Range<text::Anchor>,
26980        cx: &mut App,
26981    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26982
26983    fn applicable_inlay_chunks(
26984        &self,
26985        buffer: &Entity<Buffer>,
26986        ranges: &[Range<text::Anchor>],
26987        cx: &mut App,
26988    ) -> Vec<Range<BufferRow>>;
26989
26990    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26991
26992    fn inlay_hints(
26993        &self,
26994        invalidate: InvalidationStrategy,
26995        buffer: Entity<Buffer>,
26996        ranges: Vec<Range<text::Anchor>>,
26997        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26998        cx: &mut App,
26999    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27000
27001    fn semantic_tokens(
27002        &self,
27003        buffer: Entity<Buffer>,
27004        refresh: Option<RefreshForServer>,
27005        cx: &mut App,
27006    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27007
27008    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27009
27010    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27011
27012    fn document_highlights(
27013        &self,
27014        buffer: &Entity<Buffer>,
27015        position: text::Anchor,
27016        cx: &mut App,
27017    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27018
27019    fn definitions(
27020        &self,
27021        buffer: &Entity<Buffer>,
27022        position: text::Anchor,
27023        kind: GotoDefinitionKind,
27024        cx: &mut App,
27025    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27026
27027    fn range_for_rename(
27028        &self,
27029        buffer: &Entity<Buffer>,
27030        position: text::Anchor,
27031        cx: &mut App,
27032    ) -> Task<Result<Option<Range<text::Anchor>>>>;
27033
27034    fn perform_rename(
27035        &self,
27036        buffer: &Entity<Buffer>,
27037        position: text::Anchor,
27038        new_name: String,
27039        cx: &mut App,
27040    ) -> Option<Task<Result<ProjectTransaction>>>;
27041}
27042
27043pub trait CompletionProvider {
27044    fn completions(
27045        &self,
27046        buffer: &Entity<Buffer>,
27047        buffer_position: text::Anchor,
27048        trigger: CompletionContext,
27049        window: &mut Window,
27050        cx: &mut Context<Editor>,
27051    ) -> Task<Result<Vec<CompletionResponse>>>;
27052
27053    fn resolve_completions(
27054        &self,
27055        _buffer: Entity<Buffer>,
27056        _completion_indices: Vec<usize>,
27057        _completions: Rc<RefCell<Box<[Completion]>>>,
27058        _cx: &mut Context<Editor>,
27059    ) -> Task<Result<bool>> {
27060        Task::ready(Ok(false))
27061    }
27062
27063    fn apply_additional_edits_for_completion(
27064        &self,
27065        _buffer: Entity<Buffer>,
27066        _completions: Rc<RefCell<Box<[Completion]>>>,
27067        _completion_index: usize,
27068        _push_to_history: bool,
27069        _all_commit_ranges: Vec<Range<language::Anchor>>,
27070        _cx: &mut Context<Editor>,
27071    ) -> Task<Result<Option<language::Transaction>>> {
27072        Task::ready(Ok(None))
27073    }
27074
27075    fn is_completion_trigger(
27076        &self,
27077        buffer: &Entity<Buffer>,
27078        position: language::Anchor,
27079        text: &str,
27080        trigger_in_words: bool,
27081        cx: &mut Context<Editor>,
27082    ) -> bool;
27083
27084    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27085
27086    fn sort_completions(&self) -> bool {
27087        true
27088    }
27089
27090    fn filter_completions(&self) -> bool {
27091        true
27092    }
27093
27094    fn show_snippets(&self) -> bool {
27095        false
27096    }
27097}
27098
27099pub trait CodeActionProvider {
27100    fn id(&self) -> Arc<str>;
27101
27102    fn code_actions(
27103        &self,
27104        buffer: &Entity<Buffer>,
27105        range: Range<text::Anchor>,
27106        window: &mut Window,
27107        cx: &mut App,
27108    ) -> Task<Result<Vec<CodeAction>>>;
27109
27110    fn apply_code_action(
27111        &self,
27112        buffer_handle: Entity<Buffer>,
27113        action: CodeAction,
27114        push_to_history: bool,
27115        window: &mut Window,
27116        cx: &mut App,
27117    ) -> Task<Result<ProjectTransaction>>;
27118}
27119
27120impl CodeActionProvider for Entity<Project> {
27121    fn id(&self) -> Arc<str> {
27122        "project".into()
27123    }
27124
27125    fn code_actions(
27126        &self,
27127        buffer: &Entity<Buffer>,
27128        range: Range<text::Anchor>,
27129        _window: &mut Window,
27130        cx: &mut App,
27131    ) -> Task<Result<Vec<CodeAction>>> {
27132        self.update(cx, |project, cx| {
27133            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27134            let code_actions = project.code_actions(buffer, range, None, cx);
27135            cx.background_spawn(async move {
27136                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27137                Ok(code_lens_actions
27138                    .context("code lens fetch")?
27139                    .into_iter()
27140                    .flatten()
27141                    .chain(
27142                        code_actions
27143                            .context("code action fetch")?
27144                            .into_iter()
27145                            .flatten(),
27146                    )
27147                    .collect())
27148            })
27149        })
27150    }
27151
27152    fn apply_code_action(
27153        &self,
27154        buffer_handle: Entity<Buffer>,
27155        action: CodeAction,
27156        push_to_history: bool,
27157        _window: &mut Window,
27158        cx: &mut App,
27159    ) -> Task<Result<ProjectTransaction>> {
27160        self.update(cx, |project, cx| {
27161            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27162        })
27163    }
27164}
27165
27166fn snippet_completions(
27167    project: &Project,
27168    buffer: &Entity<Buffer>,
27169    buffer_anchor: text::Anchor,
27170    classifier: CharClassifier,
27171    cx: &mut App,
27172) -> Task<Result<CompletionResponse>> {
27173    let languages = buffer.read(cx).languages_at(buffer_anchor);
27174    let snippet_store = project.snippets().read(cx);
27175
27176    let scopes: Vec<_> = languages
27177        .iter()
27178        .filter_map(|language| {
27179            let language_name = language.lsp_id();
27180            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27181
27182            if snippets.is_empty() {
27183                None
27184            } else {
27185                Some((language.default_scope(), snippets))
27186            }
27187        })
27188        .collect();
27189
27190    if scopes.is_empty() {
27191        return Task::ready(Ok(CompletionResponse {
27192            completions: vec![],
27193            display_options: CompletionDisplayOptions::default(),
27194            is_incomplete: false,
27195        }));
27196    }
27197
27198    let snapshot = buffer.read(cx).text_snapshot();
27199    let executor = cx.background_executor().clone();
27200
27201    cx.background_spawn(async move {
27202        let is_word_char = |c| classifier.is_word(c);
27203
27204        let mut is_incomplete = false;
27205        let mut completions: Vec<Completion> = Vec::new();
27206
27207        const MAX_PREFIX_LEN: usize = 128;
27208        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27209        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27210        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27211
27212        let max_buffer_window: String = snapshot
27213            .text_for_range(window_start..buffer_offset)
27214            .collect();
27215
27216        if max_buffer_window.is_empty() {
27217            return Ok(CompletionResponse {
27218                completions: vec![],
27219                display_options: CompletionDisplayOptions::default(),
27220                is_incomplete: true,
27221            });
27222        }
27223
27224        for (_scope, snippets) in scopes.into_iter() {
27225            // Sort snippets by word count to match longer snippet prefixes first.
27226            let mut sorted_snippet_candidates = snippets
27227                .iter()
27228                .enumerate()
27229                .flat_map(|(snippet_ix, snippet)| {
27230                    snippet
27231                        .prefix
27232                        .iter()
27233                        .enumerate()
27234                        .map(move |(prefix_ix, prefix)| {
27235                            let word_count =
27236                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27237                            ((snippet_ix, prefix_ix), prefix, word_count)
27238                        })
27239                })
27240                .collect_vec();
27241            sorted_snippet_candidates
27242                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27243
27244            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27245
27246            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27247                .take(
27248                    sorted_snippet_candidates
27249                        .first()
27250                        .map(|(_, _, word_count)| *word_count)
27251                        .unwrap_or_default(),
27252                )
27253                .collect_vec();
27254
27255            const MAX_RESULTS: usize = 100;
27256            // Each match also remembers how many characters from the buffer it consumed
27257            let mut matches: Vec<(StringMatch, usize)> = vec![];
27258
27259            let mut snippet_list_cutoff_index = 0;
27260            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27261                let word_count = buffer_index + 1;
27262                // Increase `snippet_list_cutoff_index` until we have all of the
27263                // snippets with sufficiently many words.
27264                while sorted_snippet_candidates
27265                    .get(snippet_list_cutoff_index)
27266                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27267                        *snippet_word_count >= word_count
27268                    })
27269                {
27270                    snippet_list_cutoff_index += 1;
27271                }
27272
27273                // Take only the candidates with at least `word_count` many words
27274                let snippet_candidates_at_word_len =
27275                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27276
27277                let candidates = snippet_candidates_at_word_len
27278                    .iter()
27279                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27280                    .enumerate() // index in `sorted_snippet_candidates`
27281                    // First char must match
27282                    .filter(|(_ix, prefix)| {
27283                        itertools::equal(
27284                            prefix
27285                                .chars()
27286                                .next()
27287                                .into_iter()
27288                                .flat_map(|c| c.to_lowercase()),
27289                            buffer_window
27290                                .chars()
27291                                .next()
27292                                .into_iter()
27293                                .flat_map(|c| c.to_lowercase()),
27294                        )
27295                    })
27296                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27297                    .collect::<Vec<StringMatchCandidate>>();
27298
27299                matches.extend(
27300                    fuzzy::match_strings(
27301                        &candidates,
27302                        &buffer_window,
27303                        buffer_window.chars().any(|c| c.is_uppercase()),
27304                        true,
27305                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27306                        &Default::default(),
27307                        executor.clone(),
27308                    )
27309                    .await
27310                    .into_iter()
27311                    .map(|string_match| (string_match, buffer_window.len())),
27312                );
27313
27314                if matches.len() >= MAX_RESULTS {
27315                    break;
27316                }
27317            }
27318
27319            let to_lsp = |point: &text::Anchor| {
27320                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27321                point_to_lsp(end)
27322            };
27323            let lsp_end = to_lsp(&buffer_anchor);
27324
27325            if matches.len() >= MAX_RESULTS {
27326                is_incomplete = true;
27327            }
27328
27329            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27330                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27331                    sorted_snippet_candidates[string_match.candidate_id];
27332                let snippet = &snippets[snippet_index];
27333                let start = buffer_offset - buffer_window_len;
27334                let start = snapshot.anchor_before(start);
27335                let range = start..buffer_anchor;
27336                let lsp_start = to_lsp(&start);
27337                let lsp_range = lsp::Range {
27338                    start: lsp_start,
27339                    end: lsp_end,
27340                };
27341                Completion {
27342                    replace_range: range,
27343                    new_text: snippet.body.clone(),
27344                    source: CompletionSource::Lsp {
27345                        insert_range: None,
27346                        server_id: LanguageServerId(usize::MAX),
27347                        resolved: true,
27348                        lsp_completion: Box::new(lsp::CompletionItem {
27349                            label: snippet.prefix.first().unwrap().clone(),
27350                            kind: Some(CompletionItemKind::SNIPPET),
27351                            label_details: snippet.description.as_ref().map(|description| {
27352                                lsp::CompletionItemLabelDetails {
27353                                    detail: Some(description.clone()),
27354                                    description: None,
27355                                }
27356                            }),
27357                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27358                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27359                                lsp::InsertReplaceEdit {
27360                                    new_text: snippet.body.clone(),
27361                                    insert: lsp_range,
27362                                    replace: lsp_range,
27363                                },
27364                            )),
27365                            filter_text: Some(snippet.body.clone()),
27366                            sort_text: Some(char::MAX.to_string()),
27367                            ..lsp::CompletionItem::default()
27368                        }),
27369                        lsp_defaults: None,
27370                    },
27371                    label: CodeLabel {
27372                        text: matching_prefix.clone(),
27373                        runs: Vec::new(),
27374                        filter_range: 0..matching_prefix.len(),
27375                    },
27376                    icon_path: None,
27377                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27378                        single_line: snippet.name.clone().into(),
27379                        plain_text: snippet
27380                            .description
27381                            .clone()
27382                            .map(|description| description.into()),
27383                    }),
27384                    insert_text_mode: None,
27385                    confirm: None,
27386                    match_start: Some(start),
27387                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27388                }
27389            }));
27390        }
27391
27392        Ok(CompletionResponse {
27393            completions,
27394            display_options: CompletionDisplayOptions::default(),
27395            is_incomplete,
27396        })
27397    })
27398}
27399
27400impl CompletionProvider for Entity<Project> {
27401    fn completions(
27402        &self,
27403        buffer: &Entity<Buffer>,
27404        buffer_position: text::Anchor,
27405        options: CompletionContext,
27406        _window: &mut Window,
27407        cx: &mut Context<Editor>,
27408    ) -> Task<Result<Vec<CompletionResponse>>> {
27409        self.update(cx, |project, cx| {
27410            let task = project.completions(buffer, buffer_position, options, cx);
27411            cx.background_spawn(task)
27412        })
27413    }
27414
27415    fn resolve_completions(
27416        &self,
27417        buffer: Entity<Buffer>,
27418        completion_indices: Vec<usize>,
27419        completions: Rc<RefCell<Box<[Completion]>>>,
27420        cx: &mut Context<Editor>,
27421    ) -> Task<Result<bool>> {
27422        self.update(cx, |project, cx| {
27423            project.lsp_store().update(cx, |lsp_store, cx| {
27424                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27425            })
27426        })
27427    }
27428
27429    fn apply_additional_edits_for_completion(
27430        &self,
27431        buffer: Entity<Buffer>,
27432        completions: Rc<RefCell<Box<[Completion]>>>,
27433        completion_index: usize,
27434        push_to_history: bool,
27435        all_commit_ranges: Vec<Range<language::Anchor>>,
27436        cx: &mut Context<Editor>,
27437    ) -> Task<Result<Option<language::Transaction>>> {
27438        self.update(cx, |project, cx| {
27439            project.lsp_store().update(cx, |lsp_store, cx| {
27440                lsp_store.apply_additional_edits_for_completion(
27441                    buffer,
27442                    completions,
27443                    completion_index,
27444                    push_to_history,
27445                    all_commit_ranges,
27446                    cx,
27447                )
27448            })
27449        })
27450    }
27451
27452    fn is_completion_trigger(
27453        &self,
27454        buffer: &Entity<Buffer>,
27455        position: language::Anchor,
27456        text: &str,
27457        trigger_in_words: bool,
27458        cx: &mut Context<Editor>,
27459    ) -> bool {
27460        let mut chars = text.chars();
27461        let char = if let Some(char) = chars.next() {
27462            char
27463        } else {
27464            return false;
27465        };
27466        if chars.next().is_some() {
27467            return false;
27468        }
27469
27470        let buffer = buffer.read(cx);
27471        let snapshot = buffer.snapshot();
27472        let classifier = snapshot
27473            .char_classifier_at(position)
27474            .scope_context(Some(CharScopeContext::Completion));
27475        if trigger_in_words && classifier.is_word(char) {
27476            return true;
27477        }
27478
27479        buffer.completion_triggers().contains(text)
27480    }
27481
27482    fn show_snippets(&self) -> bool {
27483        true
27484    }
27485}
27486
27487impl SemanticsProvider for WeakEntity<Project> {
27488    fn hover(
27489        &self,
27490        buffer: &Entity<Buffer>,
27491        position: text::Anchor,
27492        cx: &mut App,
27493    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27494        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27495            .ok()
27496    }
27497
27498    fn document_highlights(
27499        &self,
27500        buffer: &Entity<Buffer>,
27501        position: text::Anchor,
27502        cx: &mut App,
27503    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27504        self.update(cx, |project, cx| {
27505            project.document_highlights(buffer, position, cx)
27506        })
27507        .ok()
27508    }
27509
27510    fn definitions(
27511        &self,
27512        buffer: &Entity<Buffer>,
27513        position: text::Anchor,
27514        kind: GotoDefinitionKind,
27515        cx: &mut App,
27516    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27517        self.update(cx, |project, cx| match kind {
27518            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27519            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27520            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27521            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27522        })
27523        .ok()
27524    }
27525
27526    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27527        self.update(cx, |project, cx| {
27528            if project
27529                .active_debug_session(cx)
27530                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27531            {
27532                return true;
27533            }
27534
27535            buffer.update(cx, |buffer, cx| {
27536                project.any_language_server_supports_inlay_hints(buffer, cx)
27537            })
27538        })
27539        .unwrap_or(false)
27540    }
27541
27542    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27543        self.update(cx, |project, cx| {
27544            buffer.update(cx, |buffer, cx| {
27545                project.any_language_server_supports_semantic_tokens(buffer, cx)
27546            })
27547        })
27548        .unwrap_or(false)
27549    }
27550
27551    fn inline_values(
27552        &self,
27553        buffer_handle: Entity<Buffer>,
27554        range: Range<text::Anchor>,
27555        cx: &mut App,
27556    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27557        self.update(cx, |project, cx| {
27558            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27559
27560            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27561        })
27562        .ok()
27563        .flatten()
27564    }
27565
27566    fn applicable_inlay_chunks(
27567        &self,
27568        buffer: &Entity<Buffer>,
27569        ranges: &[Range<text::Anchor>],
27570        cx: &mut App,
27571    ) -> Vec<Range<BufferRow>> {
27572        self.update(cx, |project, cx| {
27573            project.lsp_store().update(cx, |lsp_store, cx| {
27574                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27575            })
27576        })
27577        .unwrap_or_default()
27578    }
27579
27580    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27581        self.update(cx, |project, cx| {
27582            project.lsp_store().update(cx, |lsp_store, _| {
27583                lsp_store.invalidate_inlay_hints(for_buffers)
27584            })
27585        })
27586        .ok();
27587    }
27588
27589    fn inlay_hints(
27590        &self,
27591        invalidate: InvalidationStrategy,
27592        buffer: Entity<Buffer>,
27593        ranges: Vec<Range<text::Anchor>>,
27594        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27595        cx: &mut App,
27596    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27597        self.update(cx, |project, cx| {
27598            project.lsp_store().update(cx, |lsp_store, cx| {
27599                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27600            })
27601        })
27602        .ok()
27603    }
27604
27605    fn semantic_tokens(
27606        &self,
27607        buffer: Entity<Buffer>,
27608        refresh: Option<RefreshForServer>,
27609        cx: &mut App,
27610    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27611        self.update(cx, |this, cx| {
27612            this.lsp_store().update(cx, |lsp_store, cx| {
27613                lsp_store.semantic_tokens(buffer, refresh, cx)
27614            })
27615        })
27616        .ok()
27617    }
27618
27619    fn range_for_rename(
27620        &self,
27621        buffer: &Entity<Buffer>,
27622        position: text::Anchor,
27623        cx: &mut App,
27624    ) -> Task<Result<Option<Range<text::Anchor>>>> {
27625        let Some(this) = self.upgrade() else {
27626            return Task::ready(Ok(None));
27627        };
27628
27629        this.update(cx, |project, cx| {
27630            let buffer = buffer.clone();
27631            let task = project.prepare_rename(buffer.clone(), position, cx);
27632            cx.spawn(async move |_, cx| {
27633                Ok(match task.await? {
27634                    PrepareRenameResponse::Success(range) => Some(range),
27635                    PrepareRenameResponse::InvalidPosition => None,
27636                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27637                        // Fallback on using TreeSitter info to determine identifier range
27638                        buffer.read_with(cx, |buffer, _| {
27639                            let snapshot = buffer.snapshot();
27640                            let (range, kind) = snapshot.surrounding_word(position, None);
27641                            if kind != Some(CharKind::Word) {
27642                                return None;
27643                            }
27644                            Some(
27645                                snapshot.anchor_before(range.start)
27646                                    ..snapshot.anchor_after(range.end),
27647                            )
27648                        })
27649                    }
27650                })
27651            })
27652        })
27653    }
27654
27655    fn perform_rename(
27656        &self,
27657        buffer: &Entity<Buffer>,
27658        position: text::Anchor,
27659        new_name: String,
27660        cx: &mut App,
27661    ) -> Option<Task<Result<ProjectTransaction>>> {
27662        self.update(cx, |project, cx| {
27663            project.perform_rename(buffer.clone(), position, new_name, cx)
27664        })
27665        .ok()
27666    }
27667}
27668
27669fn consume_contiguous_rows(
27670    contiguous_row_selections: &mut Vec<Selection<Point>>,
27671    selection: &Selection<Point>,
27672    display_map: &DisplaySnapshot,
27673    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27674) -> (MultiBufferRow, MultiBufferRow) {
27675    contiguous_row_selections.push(selection.clone());
27676    let start_row = starting_row(selection, display_map);
27677    let mut end_row = ending_row(selection, display_map);
27678
27679    while let Some(next_selection) = selections.peek() {
27680        if next_selection.start.row <= end_row.0 {
27681            end_row = ending_row(next_selection, display_map);
27682            contiguous_row_selections.push(selections.next().unwrap().clone());
27683        } else {
27684            break;
27685        }
27686    }
27687    (start_row, end_row)
27688}
27689
27690fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27691    if selection.start.column > 0 {
27692        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27693    } else {
27694        MultiBufferRow(selection.start.row)
27695    }
27696}
27697
27698fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27699    if next_selection.end.column > 0 || next_selection.is_empty() {
27700        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27701    } else {
27702        MultiBufferRow(next_selection.end.row)
27703    }
27704}
27705
27706impl EditorSnapshot {
27707    pub fn remote_selections_in_range<'a>(
27708        &'a self,
27709        range: &'a Range<Anchor>,
27710        collaboration_hub: &dyn CollaborationHub,
27711        cx: &'a App,
27712    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27713        let participant_names = collaboration_hub.user_names(cx);
27714        let participant_indices = collaboration_hub.user_participant_indices(cx);
27715        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27716        let collaborators_by_replica_id = collaborators_by_peer_id
27717            .values()
27718            .map(|collaborator| (collaborator.replica_id, collaborator))
27719            .collect::<HashMap<_, _>>();
27720        self.buffer_snapshot()
27721            .selections_in_range(range, false)
27722            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27723                if replica_id == ReplicaId::AGENT {
27724                    Some(RemoteSelection {
27725                        replica_id,
27726                        selection,
27727                        cursor_shape,
27728                        line_mode,
27729                        collaborator_id: CollaboratorId::Agent,
27730                        user_name: Some("Agent".into()),
27731                        color: cx.theme().players().agent(),
27732                    })
27733                } else {
27734                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27735                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27736                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27737                    Some(RemoteSelection {
27738                        replica_id,
27739                        selection,
27740                        cursor_shape,
27741                        line_mode,
27742                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27743                        user_name,
27744                        color: if let Some(index) = participant_index {
27745                            cx.theme().players().color_for_participant(index.0)
27746                        } else {
27747                            cx.theme().players().absent()
27748                        },
27749                    })
27750                }
27751            })
27752    }
27753
27754    pub fn hunks_for_ranges(
27755        &self,
27756        ranges: impl IntoIterator<Item = Range<Point>>,
27757    ) -> Vec<MultiBufferDiffHunk> {
27758        let mut hunks = Vec::new();
27759        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27760            HashMap::default();
27761        for query_range in ranges {
27762            let query_rows =
27763                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27764            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27765                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27766            ) {
27767                // Include deleted hunks that are adjacent to the query range, because
27768                // otherwise they would be missed.
27769                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27770                if hunk.status().is_deleted() {
27771                    intersects_range |= hunk.row_range.start == query_rows.end;
27772                    intersects_range |= hunk.row_range.end == query_rows.start;
27773                }
27774                if intersects_range {
27775                    if !processed_buffer_rows
27776                        .entry(hunk.buffer_id)
27777                        .or_default()
27778                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27779                    {
27780                        continue;
27781                    }
27782                    hunks.push(hunk);
27783                }
27784            }
27785        }
27786
27787        hunks
27788    }
27789
27790    fn display_diff_hunks_for_rows<'a>(
27791        &'a self,
27792        display_rows: Range<DisplayRow>,
27793        folded_buffers: &'a HashSet<BufferId>,
27794    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27795        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27796        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27797
27798        self.buffer_snapshot()
27799            .diff_hunks_in_range(buffer_start..buffer_end)
27800            .filter_map(|hunk| {
27801                if folded_buffers.contains(&hunk.buffer_id)
27802                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27803                {
27804                    return None;
27805                }
27806
27807                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27808                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27809                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27810                    let line_len = self.buffer_snapshot().line_len(last_row);
27811                    Point::new(last_row.0, line_len)
27812                } else {
27813                    Point::new(hunk.row_range.end.0, 0)
27814                };
27815
27816                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27817                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27818
27819                let display_hunk = if hunk_display_start.column() != 0 {
27820                    DisplayDiffHunk::Folded {
27821                        display_row: hunk_display_start.row(),
27822                    }
27823                } else {
27824                    let mut end_row = hunk_display_end.row();
27825                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27826                        end_row.0 += 1;
27827                    }
27828                    let is_created_file = hunk.is_created_file();
27829                    let multi_buffer_range = hunk.multi_buffer_range.clone();
27830
27831                    DisplayDiffHunk::Unfolded {
27832                        status: hunk.status(),
27833                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27834                            ..hunk.diff_base_byte_range.end.0,
27835                        word_diffs: hunk.word_diffs,
27836                        display_row_range: hunk_display_start.row()..end_row,
27837                        multi_buffer_range,
27838                        is_created_file,
27839                    }
27840                };
27841
27842                Some(display_hunk)
27843            })
27844    }
27845
27846    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27847        self.display_snapshot
27848            .buffer_snapshot()
27849            .language_at(position)
27850    }
27851
27852    pub fn is_focused(&self) -> bool {
27853        self.is_focused
27854    }
27855
27856    pub fn placeholder_text(&self) -> Option<String> {
27857        self.placeholder_display_snapshot
27858            .as_ref()
27859            .map(|display_map| display_map.text())
27860    }
27861
27862    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27863        self.scroll_anchor.scroll_position(&self.display_snapshot)
27864    }
27865
27866    pub fn gutter_dimensions(
27867        &self,
27868        font_id: FontId,
27869        font_size: Pixels,
27870        style: &EditorStyle,
27871        window: &mut Window,
27872        cx: &App,
27873    ) -> GutterDimensions {
27874        if self.show_gutter
27875            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27876            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27877        {
27878            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27879                matches!(
27880                    ProjectSettings::get_global(cx).git.git_gutter,
27881                    GitGutterSetting::TrackedFiles
27882                )
27883            });
27884            let gutter_settings = EditorSettings::get_global(cx).gutter;
27885            let show_line_numbers = self
27886                .show_line_numbers
27887                .unwrap_or(gutter_settings.line_numbers);
27888            let line_gutter_width = if show_line_numbers {
27889                // Avoid flicker-like gutter resizes when the line number gains another digit by
27890                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27891                let min_width_for_number_on_gutter =
27892                    ch_advance * gutter_settings.min_line_number_digits as f32;
27893                self.max_line_number_width(style, window)
27894                    .max(min_width_for_number_on_gutter)
27895            } else {
27896                0.0.into()
27897            };
27898
27899            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27900            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27901
27902            let git_blame_entries_width =
27903                self.git_blame_gutter_max_author_length
27904                    .map(|max_author_length| {
27905                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27906                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27907
27908                        /// The number of characters to dedicate to gaps and margins.
27909                        const SPACING_WIDTH: usize = 4;
27910
27911                        let max_char_count = max_author_length.min(renderer.max_author_length())
27912                            + ::git::SHORT_SHA_LENGTH
27913                            + MAX_RELATIVE_TIMESTAMP.len()
27914                            + SPACING_WIDTH;
27915
27916                        ch_advance * max_char_count
27917                    });
27918
27919            let is_singleton = self.buffer_snapshot().is_singleton();
27920
27921            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27922            left_padding += if !is_singleton {
27923                ch_width * 4.0
27924            } else if show_runnables || show_breakpoints {
27925                ch_width * 3.0
27926            } else if show_git_gutter && show_line_numbers {
27927                ch_width * 2.0
27928            } else if show_git_gutter || show_line_numbers {
27929                ch_width
27930            } else {
27931                px(0.)
27932            };
27933
27934            let shows_folds = is_singleton && gutter_settings.folds;
27935
27936            let right_padding = if shows_folds && show_line_numbers {
27937                ch_width * 4.0
27938            } else if shows_folds || (!is_singleton && show_line_numbers) {
27939                ch_width * 3.0
27940            } else if show_line_numbers {
27941                ch_width
27942            } else {
27943                px(0.)
27944            };
27945
27946            GutterDimensions {
27947                left_padding,
27948                right_padding,
27949                width: line_gutter_width + left_padding + right_padding,
27950                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27951                git_blame_entries_width,
27952            }
27953        } else if self.offset_content {
27954            GutterDimensions::default_with_margin(font_id, font_size, cx)
27955        } else {
27956            GutterDimensions::default()
27957        }
27958    }
27959
27960    pub fn render_crease_toggle(
27961        &self,
27962        buffer_row: MultiBufferRow,
27963        row_contains_cursor: bool,
27964        editor: Entity<Editor>,
27965        window: &mut Window,
27966        cx: &mut App,
27967    ) -> Option<AnyElement> {
27968        let folded = self.is_line_folded(buffer_row);
27969        let mut is_foldable = false;
27970
27971        if let Some(crease) = self
27972            .crease_snapshot
27973            .query_row(buffer_row, self.buffer_snapshot())
27974        {
27975            is_foldable = true;
27976            match crease {
27977                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27978                    if let Some(render_toggle) = render_toggle {
27979                        let toggle_callback =
27980                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27981                                if folded {
27982                                    editor.update(cx, |editor, cx| {
27983                                        editor.fold_at(buffer_row, window, cx)
27984                                    });
27985                                } else {
27986                                    editor.update(cx, |editor, cx| {
27987                                        editor.unfold_at(buffer_row, window, cx)
27988                                    });
27989                                }
27990                            });
27991                        return Some((render_toggle)(
27992                            buffer_row,
27993                            folded,
27994                            toggle_callback,
27995                            window,
27996                            cx,
27997                        ));
27998                    }
27999                }
28000            }
28001        }
28002
28003        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28004
28005        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28006            Some(
28007                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28008                    .toggle_state(folded)
28009                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28010                        if folded {
28011                            this.unfold_at(buffer_row, window, cx);
28012                        } else {
28013                            this.fold_at(buffer_row, window, cx);
28014                        }
28015                    }))
28016                    .into_any_element(),
28017            )
28018        } else {
28019            None
28020        }
28021    }
28022
28023    pub fn render_crease_trailer(
28024        &self,
28025        buffer_row: MultiBufferRow,
28026        window: &mut Window,
28027        cx: &mut App,
28028    ) -> Option<AnyElement> {
28029        let folded = self.is_line_folded(buffer_row);
28030        if let Crease::Inline { render_trailer, .. } = self
28031            .crease_snapshot
28032            .query_row(buffer_row, self.buffer_snapshot())?
28033        {
28034            let render_trailer = render_trailer.as_ref()?;
28035            Some(render_trailer(buffer_row, folded, window, cx))
28036        } else {
28037            None
28038        }
28039    }
28040
28041    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28042        let digit_count = self.widest_line_number().ilog10() + 1;
28043        column_pixels(style, digit_count as usize, window)
28044    }
28045
28046    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28047    ///
28048    /// This is positive if `base` is before `line`.
28049    fn relative_line_delta(
28050        &self,
28051        current_selection_head: DisplayRow,
28052        first_visible_row: DisplayRow,
28053        consider_wrapped_lines: bool,
28054    ) -> i64 {
28055        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28056        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28057
28058        if consider_wrapped_lines {
28059            let wrap_snapshot = self.wrap_snapshot();
28060            let base_wrap_row = wrap_snapshot
28061                .make_wrap_point(current_selection_head, Bias::Left)
28062                .row();
28063            let wrap_row = wrap_snapshot
28064                .make_wrap_point(first_visible_row, Bias::Left)
28065                .row();
28066
28067            wrap_row.0 as i64 - base_wrap_row.0 as i64
28068        } else {
28069            let fold_snapshot = self.fold_snapshot();
28070            let base_fold_row = fold_snapshot
28071                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28072                .row();
28073            let fold_row = fold_snapshot
28074                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28075                .row();
28076
28077            fold_row as i64 - base_fold_row as i64
28078        }
28079    }
28080
28081    /// Returns the unsigned relative line number to display for each row in `rows`.
28082    ///
28083    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28084    pub fn calculate_relative_line_numbers(
28085        &self,
28086        rows: &Range<DisplayRow>,
28087        current_selection_head: DisplayRow,
28088        count_wrapped_lines: bool,
28089    ) -> HashMap<DisplayRow, u32> {
28090        let initial_offset =
28091            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28092
28093        self.row_infos(rows.start)
28094            .take(rows.len())
28095            .enumerate()
28096            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28097            .filter(|(_row, row_info)| {
28098                row_info.buffer_row.is_some()
28099                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28100            })
28101            .enumerate()
28102            .filter_map(|(i, (row, row_info))| {
28103                // We want to ensure here that the current line has absolute
28104                // numbering, even if we are in a soft-wrapped line. With the
28105                // exception that if we are in a deleted line, we should number this
28106                // relative with 0, as otherwise it would have no line number at all
28107                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28108
28109                (relative_line_number != 0
28110                    || row_info
28111                        .diff_status
28112                        .is_some_and(|status| status.is_deleted()))
28113                .then_some((row, relative_line_number))
28114            })
28115            .collect()
28116    }
28117}
28118
28119pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28120    let font_size = style.text.font_size.to_pixels(window.rem_size());
28121    let layout = window.text_system().shape_line(
28122        SharedString::from(" ".repeat(column)),
28123        font_size,
28124        &[TextRun {
28125            len: column,
28126            font: style.text.font(),
28127            color: Hsla::default(),
28128            ..Default::default()
28129        }],
28130        None,
28131    );
28132
28133    layout.width
28134}
28135
28136impl Deref for EditorSnapshot {
28137    type Target = DisplaySnapshot;
28138
28139    fn deref(&self) -> &Self::Target {
28140        &self.display_snapshot
28141    }
28142}
28143
28144#[derive(Clone, Debug, PartialEq, Eq)]
28145pub enum EditorEvent {
28146    /// Emitted when the stored review comments change (added, removed, or updated).
28147    ReviewCommentsChanged {
28148        /// The new total count of review comments.
28149        total_count: usize,
28150    },
28151    InputIgnored {
28152        text: Arc<str>,
28153    },
28154    InputHandled {
28155        utf16_range_to_replace: Option<Range<isize>>,
28156        text: Arc<str>,
28157    },
28158    BufferRangesUpdated {
28159        buffer: Entity<Buffer>,
28160        path_key: PathKey,
28161        ranges: Vec<ExcerptRange<text::Anchor>>,
28162    },
28163    BuffersRemoved {
28164        removed_buffer_ids: Vec<BufferId>,
28165    },
28166    BuffersEdited {
28167        buffer_ids: Vec<BufferId>,
28168    },
28169    BufferFoldToggled {
28170        ids: Vec<BufferId>,
28171        folded: bool,
28172    },
28173    ExpandExcerptsRequested {
28174        excerpt_anchors: Vec<Anchor>,
28175        lines: u32,
28176        direction: ExpandExcerptDirection,
28177    },
28178    StageOrUnstageRequested {
28179        stage: bool,
28180        hunks: Vec<MultiBufferDiffHunk>,
28181    },
28182    OpenExcerptsRequested {
28183        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28184        split: bool,
28185    },
28186    RestoreRequested {
28187        hunks: Vec<MultiBufferDiffHunk>,
28188    },
28189    BufferEdited,
28190    Edited {
28191        transaction_id: clock::Lamport,
28192    },
28193    Reparsed(BufferId),
28194    Focused,
28195    FocusedIn,
28196    Blurred,
28197    DirtyChanged,
28198    Saved,
28199    TitleChanged,
28200    SelectionsChanged {
28201        local: bool,
28202    },
28203    ScrollPositionChanged {
28204        local: bool,
28205        autoscroll: bool,
28206    },
28207    TransactionUndone {
28208        transaction_id: clock::Lamport,
28209    },
28210    TransactionBegun {
28211        transaction_id: clock::Lamport,
28212    },
28213    CursorShapeChanged,
28214    BreadcrumbsChanged,
28215    OutlineSymbolsChanged,
28216    PushedToNavHistory {
28217        anchor: Anchor,
28218        is_deactivate: bool,
28219    },
28220}
28221
28222impl EventEmitter<EditorEvent> for Editor {}
28223
28224impl Focusable for Editor {
28225    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28226        self.focus_handle.clone()
28227    }
28228}
28229
28230impl Render for Editor {
28231    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28232        EditorElement::new(&cx.entity(), self.create_style(cx))
28233    }
28234}
28235
28236impl EntityInputHandler for Editor {
28237    fn text_for_range(
28238        &mut self,
28239        range_utf16: Range<usize>,
28240        adjusted_range: &mut Option<Range<usize>>,
28241        _: &mut Window,
28242        cx: &mut Context<Self>,
28243    ) -> Option<String> {
28244        let snapshot = self.buffer.read(cx).read(cx);
28245        let start = snapshot.clip_offset_utf16(
28246            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28247            Bias::Left,
28248        );
28249        let end = snapshot.clip_offset_utf16(
28250            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28251            Bias::Right,
28252        );
28253        if (start.0.0..end.0.0) != range_utf16 {
28254            adjusted_range.replace(start.0.0..end.0.0);
28255        }
28256        Some(snapshot.text_for_range(start..end).collect())
28257    }
28258
28259    fn selected_text_range(
28260        &mut self,
28261        ignore_disabled_input: bool,
28262        _: &mut Window,
28263        cx: &mut Context<Self>,
28264    ) -> Option<UTF16Selection> {
28265        // Prevent the IME menu from appearing when holding down an alphabetic key
28266        // while input is disabled.
28267        if !ignore_disabled_input && !self.input_enabled {
28268            return None;
28269        }
28270
28271        let selection = self
28272            .selections
28273            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28274        let range = selection.range();
28275
28276        Some(UTF16Selection {
28277            range: range.start.0.0..range.end.0.0,
28278            reversed: selection.reversed,
28279        })
28280    }
28281
28282    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28283        let snapshot = self.buffer.read(cx).read(cx);
28284        let range = self
28285            .text_highlights(HighlightKey::InputComposition, cx)?
28286            .1
28287            .first()?;
28288        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28289    }
28290
28291    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28292        self.clear_highlights(HighlightKey::InputComposition, cx);
28293        self.ime_transaction.take();
28294    }
28295
28296    fn replace_text_in_range(
28297        &mut self,
28298        range_utf16: Option<Range<usize>>,
28299        text: &str,
28300        window: &mut Window,
28301        cx: &mut Context<Self>,
28302    ) {
28303        if !self.input_enabled {
28304            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28305            return;
28306        }
28307
28308        self.transact(window, cx, |this, window, cx| {
28309            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28310                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28311                    // During IME composition, macOS reports the replacement range
28312                    // relative to the first marked region (the only one visible via
28313                    // marked_text_range). The correct targets for replacement are the
28314                    // marked ranges themselves — one per cursor — so use them directly.
28315                    Some(marked_ranges)
28316                } else if range_utf16.start == range_utf16.end {
28317                    // An empty replacement range means "insert at cursor" with no text
28318                    // to replace. macOS reports the cursor position from its own
28319                    // (single-cursor) view of the buffer, which diverges from our actual
28320                    // cursor positions after multi-cursor edits have shifted offsets.
28321                    // Treating this as range_utf16=None lets each cursor insert in place.
28322                    None
28323                } else {
28324                    // Outside of IME composition (e.g. Accessibility Keyboard word
28325                    // completion), the range is an absolute document offset for the
28326                    // newest cursor. Fan it out to all cursors via
28327                    // selection_replacement_ranges, which applies the delta relative
28328                    // to the newest selection to every cursor.
28329                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28330                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28331                    Some(this.selection_replacement_ranges(range_utf16, cx))
28332                }
28333            } else {
28334                this.marked_text_ranges(cx)
28335            };
28336
28337            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28338                let newest_selection_id = this.selections.newest_anchor().id;
28339                this.selections
28340                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28341                    .iter()
28342                    .zip(ranges_to_replace.iter())
28343                    .find_map(|(selection, range)| {
28344                        if selection.id == newest_selection_id {
28345                            Some(
28346                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28347                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28348                            )
28349                        } else {
28350                            None
28351                        }
28352                    })
28353            });
28354
28355            cx.emit(EditorEvent::InputHandled {
28356                utf16_range_to_replace: range_to_replace,
28357                text: text.into(),
28358            });
28359
28360            if let Some(new_selected_ranges) = new_selected_ranges {
28361                // Only backspace if at least one range covers actual text. When all
28362                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28363                // Keyboard sends replacementRange=cursor..cursor), backspace would
28364                // incorrectly delete the character just before the cursor.
28365                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28366                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28367                    selections.select_ranges(new_selected_ranges)
28368                });
28369                if should_backspace {
28370                    this.backspace(&Default::default(), window, cx);
28371                }
28372            }
28373
28374            this.handle_input(text, window, cx);
28375        });
28376
28377        if let Some(transaction) = self.ime_transaction {
28378            self.buffer.update(cx, |buffer, cx| {
28379                buffer.group_until_transaction(transaction, cx);
28380            });
28381        }
28382
28383        self.unmark_text(window, cx);
28384    }
28385
28386    fn replace_and_mark_text_in_range(
28387        &mut self,
28388        range_utf16: Option<Range<usize>>,
28389        text: &str,
28390        new_selected_range_utf16: Option<Range<usize>>,
28391        window: &mut Window,
28392        cx: &mut Context<Self>,
28393    ) {
28394        if !self.input_enabled {
28395            return;
28396        }
28397
28398        let transaction = self.transact(window, cx, |this, window, cx| {
28399            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28400                let snapshot = this.buffer.read(cx).read(cx);
28401                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28402                    for marked_range in &mut marked_ranges {
28403                        marked_range.end = marked_range.start + relative_range_utf16.end;
28404                        marked_range.start += relative_range_utf16.start;
28405                        marked_range.start =
28406                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28407                        marked_range.end =
28408                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28409                    }
28410                }
28411                Some(marked_ranges)
28412            } else if let Some(range_utf16) = range_utf16 {
28413                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28414                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28415                Some(this.selection_replacement_ranges(range_utf16, cx))
28416            } else {
28417                None
28418            };
28419
28420            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28421                let newest_selection_id = this.selections.newest_anchor().id;
28422                this.selections
28423                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28424                    .iter()
28425                    .zip(ranges_to_replace.iter())
28426                    .find_map(|(selection, range)| {
28427                        if selection.id == newest_selection_id {
28428                            Some(
28429                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28430                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28431                            )
28432                        } else {
28433                            None
28434                        }
28435                    })
28436            });
28437
28438            cx.emit(EditorEvent::InputHandled {
28439                utf16_range_to_replace: range_to_replace,
28440                text: text.into(),
28441            });
28442
28443            if let Some(ranges) = ranges_to_replace {
28444                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28445                    s.select_ranges(ranges)
28446                });
28447            }
28448
28449            let marked_ranges = {
28450                let snapshot = this.buffer.read(cx).read(cx);
28451                this.selections
28452                    .disjoint_anchors_arc()
28453                    .iter()
28454                    .map(|selection| {
28455                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28456                    })
28457                    .collect::<Vec<_>>()
28458            };
28459
28460            if text.is_empty() {
28461                this.unmark_text(window, cx);
28462            } else {
28463                this.highlight_text(
28464                    HighlightKey::InputComposition,
28465                    marked_ranges.clone(),
28466                    HighlightStyle {
28467                        underline: Some(UnderlineStyle {
28468                            thickness: px(1.),
28469                            color: None,
28470                            wavy: false,
28471                        }),
28472                        ..Default::default()
28473                    },
28474                    cx,
28475                );
28476            }
28477
28478            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28479            let use_autoclose = this.use_autoclose;
28480            let use_auto_surround = this.use_auto_surround;
28481            this.set_use_autoclose(false);
28482            this.set_use_auto_surround(false);
28483            this.handle_input(text, window, cx);
28484            this.set_use_autoclose(use_autoclose);
28485            this.set_use_auto_surround(use_auto_surround);
28486
28487            if let Some(new_selected_range) = new_selected_range_utf16 {
28488                let snapshot = this.buffer.read(cx).read(cx);
28489                let new_selected_ranges = marked_ranges
28490                    .into_iter()
28491                    .map(|marked_range| {
28492                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28493                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28494                            insertion_start.0 + new_selected_range.start,
28495                        ));
28496                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28497                            insertion_start.0 + new_selected_range.end,
28498                        ));
28499                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28500                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28501                    })
28502                    .collect::<Vec<_>>();
28503
28504                drop(snapshot);
28505                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28506                    selections.select_ranges(new_selected_ranges)
28507                });
28508            }
28509        });
28510
28511        self.ime_transaction = self.ime_transaction.or(transaction);
28512        if let Some(transaction) = self.ime_transaction {
28513            self.buffer.update(cx, |buffer, cx| {
28514                buffer.group_until_transaction(transaction, cx);
28515            });
28516        }
28517
28518        if self
28519            .text_highlights(HighlightKey::InputComposition, cx)
28520            .is_none()
28521        {
28522            self.ime_transaction.take();
28523        }
28524    }
28525
28526    fn bounds_for_range(
28527        &mut self,
28528        range_utf16: Range<usize>,
28529        element_bounds: gpui::Bounds<Pixels>,
28530        window: &mut Window,
28531        cx: &mut Context<Self>,
28532    ) -> Option<gpui::Bounds<Pixels>> {
28533        let text_layout_details = self.text_layout_details(window, cx);
28534        let CharacterDimensions {
28535            em_width,
28536            em_advance,
28537            line_height,
28538        } = self.character_dimensions(window, cx);
28539
28540        let snapshot = self.snapshot(window, cx);
28541        let scroll_position = snapshot.scroll_position();
28542        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28543
28544        let start =
28545            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28546        let x = Pixels::from(
28547            ScrollOffset::from(
28548                snapshot.x_for_display_point(start, &text_layout_details)
28549                    + self.gutter_dimensions.full_width(),
28550            ) - scroll_left,
28551        );
28552        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28553
28554        Some(Bounds {
28555            origin: element_bounds.origin + point(x, y),
28556            size: size(em_width, line_height),
28557        })
28558    }
28559
28560    fn character_index_for_point(
28561        &mut self,
28562        point: gpui::Point<Pixels>,
28563        _window: &mut Window,
28564        _cx: &mut Context<Self>,
28565    ) -> Option<usize> {
28566        let position_map = self.last_position_map.as_ref()?;
28567        if !position_map.text_hitbox.contains(&point) {
28568            return None;
28569        }
28570        let display_point = position_map.point_for_position(point).previous_valid;
28571        let anchor = position_map
28572            .snapshot
28573            .display_point_to_anchor(display_point, Bias::Left);
28574        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28575        Some(utf16_offset.0.0)
28576    }
28577
28578    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28579        self.expects_character_input
28580    }
28581}
28582
28583trait SelectionExt {
28584    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28585    fn spanned_rows(
28586        &self,
28587        include_end_if_at_line_start: bool,
28588        map: &DisplaySnapshot,
28589    ) -> Range<MultiBufferRow>;
28590}
28591
28592impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28593    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28594        let start = self
28595            .start
28596            .to_point(map.buffer_snapshot())
28597            .to_display_point(map);
28598        let end = self
28599            .end
28600            .to_point(map.buffer_snapshot())
28601            .to_display_point(map);
28602        if self.reversed {
28603            end..start
28604        } else {
28605            start..end
28606        }
28607    }
28608
28609    fn spanned_rows(
28610        &self,
28611        include_end_if_at_line_start: bool,
28612        map: &DisplaySnapshot,
28613    ) -> Range<MultiBufferRow> {
28614        let start = self.start.to_point(map.buffer_snapshot());
28615        let mut end = self.end.to_point(map.buffer_snapshot());
28616        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28617            end.row -= 1;
28618        }
28619
28620        let buffer_start = map.prev_line_boundary(start).0;
28621        let buffer_end = map.next_line_boundary(end).0;
28622        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28623    }
28624}
28625
28626impl<T: InvalidationRegion> InvalidationStack<T> {
28627    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28628    where
28629        S: Clone + ToOffset,
28630    {
28631        while let Some(region) = self.last() {
28632            let all_selections_inside_invalidation_ranges =
28633                if selections.len() == region.ranges().len() {
28634                    selections
28635                        .iter()
28636                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28637                        .all(|(selection, invalidation_range)| {
28638                            let head = selection.head().to_offset(buffer);
28639                            invalidation_range.start <= head && invalidation_range.end >= head
28640                        })
28641                } else {
28642                    false
28643                };
28644
28645            if all_selections_inside_invalidation_ranges {
28646                break;
28647            } else {
28648                self.pop();
28649            }
28650        }
28651    }
28652}
28653
28654#[derive(Clone)]
28655struct ErasedEditorImpl(Entity<Editor>);
28656
28657impl ui_input::ErasedEditor for ErasedEditorImpl {
28658    fn text(&self, cx: &App) -> String {
28659        self.0.read(cx).text(cx)
28660    }
28661
28662    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28663        self.0.update(cx, |this, cx| {
28664            this.set_text(text, window, cx);
28665        })
28666    }
28667
28668    fn clear(&self, window: &mut Window, cx: &mut App) {
28669        self.0.update(cx, |this, cx| this.clear(window, cx));
28670    }
28671
28672    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28673        self.0.update(cx, |this, cx| {
28674            this.set_placeholder_text(text, window, cx);
28675        });
28676    }
28677
28678    fn focus_handle(&self, cx: &App) -> FocusHandle {
28679        self.0.read(cx).focus_handle(cx)
28680    }
28681
28682    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28683        let settings = ThemeSettings::get_global(cx);
28684        let theme_color = cx.theme().colors();
28685
28686        let text_style = TextStyle {
28687            font_family: settings.ui_font.family.clone(),
28688            font_features: settings.ui_font.features.clone(),
28689            font_size: rems(0.875).into(),
28690            font_weight: settings.ui_font.weight,
28691            font_style: FontStyle::Normal,
28692            line_height: relative(1.2),
28693            color: theme_color.text,
28694            ..Default::default()
28695        };
28696        let editor_style = EditorStyle {
28697            background: theme_color.ghost_element_background,
28698            local_player: cx.theme().players().local(),
28699            syntax: cx.theme().syntax().clone(),
28700            text: text_style,
28701            ..Default::default()
28702        };
28703        EditorElement::new(&self.0, editor_style).into_any()
28704    }
28705
28706    fn as_any(&self) -> &dyn Any {
28707        &self.0
28708    }
28709
28710    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28711        self.0.update(cx, |editor, cx| {
28712            let editor_offset = editor.buffer().read(cx).len(cx);
28713            editor.change_selections(
28714                SelectionEffects::scroll(Autoscroll::Next),
28715                window,
28716                cx,
28717                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28718            );
28719        });
28720    }
28721
28722    fn subscribe(
28723        &self,
28724        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28725        window: &mut Window,
28726        cx: &mut App,
28727    ) -> Subscription {
28728        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28729            let event = match event {
28730                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28731                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28732                _ => return,
28733            };
28734            (callback)(event, window, cx);
28735        })
28736    }
28737
28738    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28739        self.0.update(cx, |editor, cx| {
28740            editor.set_masked(masked, cx);
28741        });
28742    }
28743}
28744impl<T> Default for InvalidationStack<T> {
28745    fn default() -> Self {
28746        Self(Default::default())
28747    }
28748}
28749
28750impl<T> Deref for InvalidationStack<T> {
28751    type Target = Vec<T>;
28752
28753    fn deref(&self) -> &Self::Target {
28754        &self.0
28755    }
28756}
28757
28758impl<T> DerefMut for InvalidationStack<T> {
28759    fn deref_mut(&mut self) -> &mut Self::Target {
28760        &mut self.0
28761    }
28762}
28763
28764impl InvalidationRegion for SnippetState {
28765    fn ranges(&self) -> &[Range<Anchor>] {
28766        &self.ranges[self.active_index]
28767    }
28768}
28769
28770fn edit_prediction_edit_text(
28771    current_snapshot: &BufferSnapshot,
28772    edits: &[(Range<Anchor>, impl AsRef<str>)],
28773    edit_preview: &EditPreview,
28774    include_deletions: bool,
28775    multibuffer_snapshot: &MultiBufferSnapshot,
28776    cx: &App,
28777) -> HighlightedText {
28778    let edits = edits
28779        .iter()
28780        .filter_map(|(anchor, text)| {
28781            Some((
28782                multibuffer_snapshot
28783                    .anchor_range_to_buffer_anchor_range(anchor.clone())?
28784                    .1,
28785                text,
28786            ))
28787        })
28788        .collect::<Vec<_>>();
28789
28790    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28791}
28792
28793fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28794    // Fallback for providers that don't provide edit_preview (like Copilot)
28795    // Just show the raw edit text with basic styling
28796    let mut text = String::new();
28797    let mut highlights = Vec::new();
28798
28799    let insertion_highlight_style = HighlightStyle {
28800        color: Some(cx.theme().colors().text),
28801        ..Default::default()
28802    };
28803
28804    for (_, edit_text) in edits {
28805        let start_offset = text.len();
28806        text.push_str(edit_text);
28807        let end_offset = text.len();
28808
28809        if start_offset < end_offset {
28810            highlights.push((start_offset..end_offset, insertion_highlight_style));
28811        }
28812    }
28813
28814    HighlightedText {
28815        text: text.into(),
28816        highlights,
28817    }
28818}
28819
28820pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28821    match severity {
28822        lsp::DiagnosticSeverity::ERROR => colors.error,
28823        lsp::DiagnosticSeverity::WARNING => colors.warning,
28824        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28825        lsp::DiagnosticSeverity::HINT => colors.info,
28826        _ => colors.ignored,
28827    }
28828}
28829
28830pub fn styled_runs_for_code_label<'a>(
28831    label: &'a CodeLabel,
28832    syntax_theme: &'a theme::SyntaxTheme,
28833    local_player: &'a theme::PlayerColor,
28834) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28835    let fade_out = HighlightStyle {
28836        fade_out: Some(0.35),
28837        ..Default::default()
28838    };
28839
28840    if label.runs.is_empty() {
28841        let desc_start = label.filter_range.end;
28842        let fade_run =
28843            (desc_start < label.text.len()).then(|| (desc_start..label.text.len(), fade_out));
28844        return Either::Left(fade_run.into_iter());
28845    }
28846
28847    let mut prev_end = label.filter_range.end;
28848    Either::Right(
28849        label
28850            .runs
28851            .iter()
28852            .enumerate()
28853            .flat_map(move |(ix, (range, highlight_id))| {
28854                let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28855                    HighlightStyle {
28856                        color: Some(local_player.cursor),
28857                        ..Default::default()
28858                    }
28859                } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28860                    HighlightStyle {
28861                        background_color: Some(local_player.selection),
28862                        ..Default::default()
28863                    }
28864                } else if let Some(style) = syntax_theme.get(*highlight_id).cloned() {
28865                    style
28866                } else {
28867                    return Default::default();
28868                };
28869
28870                let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28871                let muted_style = style.highlight(fade_out);
28872                if range.start >= label.filter_range.end {
28873                    if range.start > prev_end {
28874                        runs.push((prev_end..range.start, fade_out));
28875                    }
28876                    runs.push((range.clone(), muted_style));
28877                } else if range.end <= label.filter_range.end {
28878                    runs.push((range.clone(), style));
28879                } else {
28880                    runs.push((range.start..label.filter_range.end, style));
28881                    runs.push((label.filter_range.end..range.end, muted_style));
28882                }
28883                prev_end = cmp::max(prev_end, range.end);
28884
28885                if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28886                    runs.push((prev_end..label.text.len(), fade_out));
28887                }
28888
28889                runs
28890            }),
28891    )
28892}
28893
28894pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28895    let mut prev_index = 0;
28896    let mut prev_codepoint: Option<char> = None;
28897    text.char_indices()
28898        .chain([(text.len(), '\0')])
28899        .filter_map(move |(index, codepoint)| {
28900            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28901            let is_boundary = index == text.len()
28902                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28903                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28904            if is_boundary {
28905                let chunk = &text[prev_index..index];
28906                prev_index = index;
28907                Some(chunk)
28908            } else {
28909                None
28910            }
28911        })
28912}
28913
28914/// Given a string of text immediately before the cursor, iterates over possible
28915/// strings a snippet could match to. More precisely: returns an iterator over
28916/// suffixes of `text` created by splitting at word boundaries (before & after
28917/// every non-word character).
28918///
28919/// Shorter suffixes are returned first.
28920pub(crate) fn snippet_candidate_suffixes<'a>(
28921    text: &'a str,
28922    is_word_char: &'a dyn Fn(char) -> bool,
28923) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28924    let mut prev_index = text.len();
28925    let mut prev_codepoint = None;
28926    text.char_indices()
28927        .rev()
28928        .chain([(0, '\0')])
28929        .filter_map(move |(index, codepoint)| {
28930            let prev_index = std::mem::replace(&mut prev_index, index);
28931            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28932            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28933                None
28934            } else {
28935                let chunk = &text[prev_index..]; // go to end of string
28936                Some(chunk)
28937            }
28938        })
28939}
28940
28941pub trait RangeToAnchorExt: Sized {
28942    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28943
28944    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28945        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28946        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28947    }
28948}
28949
28950impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28951    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28952        let start_offset = self.start.to_offset(snapshot);
28953        let end_offset = self.end.to_offset(snapshot);
28954        if start_offset == end_offset {
28955            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28956        } else {
28957            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28958        }
28959    }
28960}
28961
28962pub trait RowExt {
28963    fn as_f64(&self) -> f64;
28964
28965    fn next_row(&self) -> Self;
28966
28967    fn previous_row(&self) -> Self;
28968
28969    fn minus(&self, other: Self) -> u32;
28970}
28971
28972impl RowExt for DisplayRow {
28973    fn as_f64(&self) -> f64 {
28974        self.0 as _
28975    }
28976
28977    fn next_row(&self) -> Self {
28978        Self(self.0 + 1)
28979    }
28980
28981    fn previous_row(&self) -> Self {
28982        Self(self.0.saturating_sub(1))
28983    }
28984
28985    fn minus(&self, other: Self) -> u32 {
28986        self.0 - other.0
28987    }
28988}
28989
28990impl RowExt for MultiBufferRow {
28991    fn as_f64(&self) -> f64 {
28992        self.0 as _
28993    }
28994
28995    fn next_row(&self) -> Self {
28996        Self(self.0 + 1)
28997    }
28998
28999    fn previous_row(&self) -> Self {
29000        Self(self.0.saturating_sub(1))
29001    }
29002
29003    fn minus(&self, other: Self) -> u32 {
29004        self.0 - other.0
29005    }
29006}
29007
29008trait RowRangeExt {
29009    type Row;
29010
29011    fn len(&self) -> usize;
29012
29013    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29014}
29015
29016impl RowRangeExt for Range<MultiBufferRow> {
29017    type Row = MultiBufferRow;
29018
29019    fn len(&self) -> usize {
29020        (self.end.0 - self.start.0) as usize
29021    }
29022
29023    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29024        (self.start.0..self.end.0).map(MultiBufferRow)
29025    }
29026}
29027
29028impl RowRangeExt for Range<DisplayRow> {
29029    type Row = DisplayRow;
29030
29031    fn len(&self) -> usize {
29032        (self.end.0 - self.start.0) as usize
29033    }
29034
29035    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29036        (self.start.0..self.end.0).map(DisplayRow)
29037    }
29038}
29039
29040/// If select range has more than one line, we
29041/// just point the cursor to range.start.
29042fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29043    if range.start.row == range.end.row {
29044        range
29045    } else {
29046        range.start..range.start
29047    }
29048}
29049pub struct KillRing(ClipboardItem);
29050impl Global for KillRing {}
29051
29052const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29053
29054enum BreakpointPromptEditAction {
29055    Log,
29056    Condition,
29057    HitCondition,
29058}
29059
29060struct BreakpointPromptEditor {
29061    pub(crate) prompt: Entity<Editor>,
29062    editor: WeakEntity<Editor>,
29063    breakpoint_anchor: Anchor,
29064    breakpoint: Breakpoint,
29065    edit_action: BreakpointPromptEditAction,
29066    block_ids: HashSet<CustomBlockId>,
29067    editor_margins: Arc<Mutex<EditorMargins>>,
29068    _subscriptions: Vec<Subscription>,
29069}
29070
29071impl BreakpointPromptEditor {
29072    const MAX_LINES: u8 = 4;
29073
29074    fn new(
29075        editor: WeakEntity<Editor>,
29076        breakpoint_anchor: Anchor,
29077        breakpoint: Breakpoint,
29078        edit_action: BreakpointPromptEditAction,
29079        window: &mut Window,
29080        cx: &mut Context<Self>,
29081    ) -> Self {
29082        let base_text = match edit_action {
29083            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29084            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29085            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29086        }
29087        .map(|msg| msg.to_string())
29088        .unwrap_or_default();
29089
29090        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29091        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29092
29093        let prompt = cx.new(|cx| {
29094            let mut prompt = Editor::new(
29095                EditorMode::AutoHeight {
29096                    min_lines: 1,
29097                    max_lines: Some(Self::MAX_LINES as usize),
29098                },
29099                buffer,
29100                None,
29101                window,
29102                cx,
29103            );
29104            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29105            prompt.set_show_cursor_when_unfocused(false, cx);
29106            prompt.set_placeholder_text(
29107                match edit_action {
29108                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29109                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29110                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29111                },
29112                window,
29113                cx,
29114            );
29115
29116            prompt
29117        });
29118
29119        Self {
29120            prompt,
29121            editor,
29122            breakpoint_anchor,
29123            breakpoint,
29124            edit_action,
29125            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29126            block_ids: Default::default(),
29127            _subscriptions: vec![],
29128        }
29129    }
29130
29131    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29132        self.block_ids.extend(block_ids)
29133    }
29134
29135    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29136        if let Some(editor) = self.editor.upgrade() {
29137            let message = self
29138                .prompt
29139                .read(cx)
29140                .buffer
29141                .read(cx)
29142                .as_singleton()
29143                .expect("A multi buffer in breakpoint prompt isn't possible")
29144                .read(cx)
29145                .as_rope()
29146                .to_string();
29147
29148            editor.update(cx, |editor, cx| {
29149                editor.edit_breakpoint_at_anchor(
29150                    self.breakpoint_anchor,
29151                    self.breakpoint.clone(),
29152                    match self.edit_action {
29153                        BreakpointPromptEditAction::Log => {
29154                            BreakpointEditAction::EditLogMessage(message.into())
29155                        }
29156                        BreakpointPromptEditAction::Condition => {
29157                            BreakpointEditAction::EditCondition(message.into())
29158                        }
29159                        BreakpointPromptEditAction::HitCondition => {
29160                            BreakpointEditAction::EditHitCondition(message.into())
29161                        }
29162                    },
29163                    cx,
29164                );
29165
29166                editor.remove_blocks(self.block_ids.clone(), None, cx);
29167                cx.focus_self(window);
29168            });
29169        }
29170    }
29171
29172    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29173        self.editor
29174            .update(cx, |editor, cx| {
29175                editor.remove_blocks(self.block_ids.clone(), None, cx);
29176                window.focus(&editor.focus_handle, cx);
29177            })
29178            .log_err();
29179    }
29180
29181    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29182        let settings = ThemeSettings::get_global(cx);
29183        let text_style = TextStyle {
29184            color: if self.prompt.read(cx).read_only(cx) {
29185                cx.theme().colors().text_disabled
29186            } else {
29187                cx.theme().colors().text
29188            },
29189            font_family: settings.buffer_font.family.clone(),
29190            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29191            font_size: settings.buffer_font_size(cx).into(),
29192            font_weight: settings.buffer_font.weight,
29193            line_height: relative(settings.buffer_line_height.value()),
29194            ..Default::default()
29195        };
29196        EditorElement::new(
29197            &self.prompt,
29198            EditorStyle {
29199                background: cx.theme().colors().editor_background,
29200                local_player: cx.theme().players().local(),
29201                text: text_style,
29202                ..Default::default()
29203            },
29204        )
29205    }
29206
29207    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29208        let focus_handle = self.prompt.focus_handle(cx);
29209        IconButton::new("cancel", IconName::Close)
29210            .icon_color(Color::Muted)
29211            .shape(IconButtonShape::Square)
29212            .tooltip(move |_window, cx| {
29213                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29214            })
29215            .on_click(cx.listener(|this, _, window, cx| {
29216                this.cancel(&menu::Cancel, window, cx);
29217            }))
29218    }
29219
29220    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29221        let focus_handle = self.prompt.focus_handle(cx);
29222        IconButton::new("confirm", IconName::Return)
29223            .icon_color(Color::Muted)
29224            .shape(IconButtonShape::Square)
29225            .tooltip(move |_window, cx| {
29226                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29227            })
29228            .on_click(cx.listener(|this, _, window, cx| {
29229                this.confirm(&menu::Confirm, window, cx);
29230            }))
29231    }
29232}
29233
29234impl Render for BreakpointPromptEditor {
29235    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29236        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29237        let editor_margins = *self.editor_margins.lock();
29238        let gutter_dimensions = editor_margins.gutter;
29239        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29240        let right_padding = editor_margins.right + px(9.);
29241        h_flex()
29242            .key_context("Editor")
29243            .bg(cx.theme().colors().editor_background)
29244            .border_y_1()
29245            .border_color(cx.theme().status().info_border)
29246            .size_full()
29247            .py(window.line_height() / 2.5)
29248            .pr(right_padding)
29249            .on_action(cx.listener(Self::confirm))
29250            .on_action(cx.listener(Self::cancel))
29251            .child(
29252                WithRemSize::new(ui_font_size)
29253                    .h_full()
29254                    .w(left_gutter_width)
29255                    .flex()
29256                    .flex_row()
29257                    .flex_shrink_0()
29258                    .items_center()
29259                    .justify_center()
29260                    .gap_1()
29261                    .child(self.render_close_button(cx)),
29262            )
29263            .child(
29264                h_flex()
29265                    .w_full()
29266                    .justify_between()
29267                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29268                    .child(
29269                        WithRemSize::new(ui_font_size)
29270                            .flex()
29271                            .flex_row()
29272                            .items_center()
29273                            .child(self.render_confirm_button(cx)),
29274                    ),
29275            )
29276    }
29277}
29278
29279impl Focusable for BreakpointPromptEditor {
29280    fn focus_handle(&self, cx: &App) -> FocusHandle {
29281        self.prompt.focus_handle(cx)
29282    }
29283}
29284
29285fn all_edits_insertions_or_deletions(
29286    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29287    snapshot: &MultiBufferSnapshot,
29288) -> bool {
29289    let mut all_insertions = true;
29290    let mut all_deletions = true;
29291
29292    for (range, new_text) in edits.iter() {
29293        let range_is_empty = range.to_offset(snapshot).is_empty();
29294        let text_is_empty = new_text.is_empty();
29295
29296        if range_is_empty != text_is_empty {
29297            if range_is_empty {
29298                all_deletions = false;
29299            } else {
29300                all_insertions = false;
29301            }
29302        } else {
29303            return false;
29304        }
29305
29306        if !all_insertions && !all_deletions {
29307            return false;
29308        }
29309    }
29310    all_insertions || all_deletions
29311}
29312
29313struct MissingEditPredictionKeybindingTooltip;
29314
29315impl Render for MissingEditPredictionKeybindingTooltip {
29316    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29317        ui::tooltip_container(cx, |container, cx| {
29318            container
29319                .flex_shrink_0()
29320                .max_w_80()
29321                .min_h(rems_from_px(124.))
29322                .justify_between()
29323                .child(
29324                    v_flex()
29325                        .flex_1()
29326                        .text_ui_sm(cx)
29327                        .child(Label::new("Conflict with Accept Keybinding"))
29328                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29329                )
29330                .child(
29331                    h_flex()
29332                        .pb_1()
29333                        .gap_1()
29334                        .items_end()
29335                        .w_full()
29336                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29337                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29338                        }))
29339                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29340                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29341                        })),
29342                )
29343        })
29344    }
29345}
29346
29347#[derive(Debug, Clone, Copy, PartialEq)]
29348pub struct LineHighlight {
29349    pub background: Background,
29350    pub border: Option<gpui::Hsla>,
29351    pub include_gutter: bool,
29352    pub type_id: Option<TypeId>,
29353}
29354
29355struct LineManipulationResult {
29356    pub new_text: String,
29357    pub line_count_before: usize,
29358    pub line_count_after: usize,
29359}
29360
29361fn render_diff_hunk_controls(
29362    row: u32,
29363    status: &DiffHunkStatus,
29364    hunk_range: Range<Anchor>,
29365    is_created_file: bool,
29366    line_height: Pixels,
29367    editor: &Entity<Editor>,
29368    _window: &mut Window,
29369    cx: &mut App,
29370) -> AnyElement {
29371    h_flex()
29372        .h(line_height)
29373        .mr_1()
29374        .gap_1()
29375        .px_0p5()
29376        .pb_1()
29377        .border_x_1()
29378        .border_b_1()
29379        .border_color(cx.theme().colors().border_variant)
29380        .rounded_b_lg()
29381        .bg(cx.theme().colors().editor_background)
29382        .gap_1()
29383        .block_mouse_except_scroll()
29384        .shadow_md()
29385        .child(if status.has_secondary_hunk() {
29386            Button::new(("stage", row as u64), "Stage")
29387                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29388                .tooltip({
29389                    let focus_handle = editor.focus_handle(cx);
29390                    move |_window, cx| {
29391                        Tooltip::for_action_in(
29392                            "Stage Hunk",
29393                            &::git::ToggleStaged,
29394                            &focus_handle,
29395                            cx,
29396                        )
29397                    }
29398                })
29399                .on_click({
29400                    let editor = editor.clone();
29401                    move |_event, _window, cx| {
29402                        editor.update(cx, |editor, cx| {
29403                            editor.stage_or_unstage_diff_hunks(
29404                                true,
29405                                vec![hunk_range.start..hunk_range.start],
29406                                cx,
29407                            );
29408                        });
29409                    }
29410                })
29411        } else {
29412            Button::new(("unstage", row as u64), "Unstage")
29413                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29414                .tooltip({
29415                    let focus_handle = editor.focus_handle(cx);
29416                    move |_window, cx| {
29417                        Tooltip::for_action_in(
29418                            "Unstage Hunk",
29419                            &::git::ToggleStaged,
29420                            &focus_handle,
29421                            cx,
29422                        )
29423                    }
29424                })
29425                .on_click({
29426                    let editor = editor.clone();
29427                    move |_event, _window, cx| {
29428                        editor.update(cx, |editor, cx| {
29429                            editor.stage_or_unstage_diff_hunks(
29430                                false,
29431                                vec![hunk_range.start..hunk_range.start],
29432                                cx,
29433                            );
29434                        });
29435                    }
29436                })
29437        })
29438        .child(
29439            Button::new(("restore", row as u64), "Restore")
29440                .tooltip({
29441                    let focus_handle = editor.focus_handle(cx);
29442                    move |_window, cx| {
29443                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29444                    }
29445                })
29446                .on_click({
29447                    let editor = editor.clone();
29448                    move |_event, window, cx| {
29449                        editor.update(cx, |editor, cx| {
29450                            let snapshot = editor.snapshot(window, cx);
29451                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29452                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29453                        });
29454                    }
29455                })
29456                .disabled(is_created_file),
29457        )
29458        .when(
29459            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29460            |el| {
29461                el.child(
29462                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29463                        .shape(IconButtonShape::Square)
29464                        .icon_size(IconSize::Small)
29465                        // .disabled(!has_multiple_hunks)
29466                        .tooltip({
29467                            let focus_handle = editor.focus_handle(cx);
29468                            move |_window, cx| {
29469                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29470                            }
29471                        })
29472                        .on_click({
29473                            let editor = editor.clone();
29474                            move |_event, window, cx| {
29475                                editor.update(cx, |editor, cx| {
29476                                    let snapshot = editor.snapshot(window, cx);
29477                                    let position =
29478                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29479                                    editor.go_to_hunk_before_or_after_position(
29480                                        &snapshot,
29481                                        position,
29482                                        Direction::Next,
29483                                        true,
29484                                        window,
29485                                        cx,
29486                                    );
29487                                    editor.expand_selected_diff_hunks(cx);
29488                                });
29489                            }
29490                        }),
29491                )
29492                .child(
29493                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29494                        .shape(IconButtonShape::Square)
29495                        .icon_size(IconSize::Small)
29496                        // .disabled(!has_multiple_hunks)
29497                        .tooltip({
29498                            let focus_handle = editor.focus_handle(cx);
29499                            move |_window, cx| {
29500                                Tooltip::for_action_in(
29501                                    "Previous Hunk",
29502                                    &GoToPreviousHunk,
29503                                    &focus_handle,
29504                                    cx,
29505                                )
29506                            }
29507                        })
29508                        .on_click({
29509                            let editor = editor.clone();
29510                            move |_event, window, cx| {
29511                                editor.update(cx, |editor, cx| {
29512                                    let snapshot = editor.snapshot(window, cx);
29513                                    let point =
29514                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29515                                    editor.go_to_hunk_before_or_after_position(
29516                                        &snapshot,
29517                                        point,
29518                                        Direction::Prev,
29519                                        true,
29520                                        window,
29521                                        cx,
29522                                    );
29523                                    editor.expand_selected_diff_hunks(cx);
29524                                });
29525                            }
29526                        }),
29527                )
29528            },
29529        )
29530        .into_any_element()
29531}
29532
29533pub fn multibuffer_context_lines(cx: &App) -> u32 {
29534    EditorSettings::try_get(cx)
29535        .map(|settings| settings.excerpt_context_lines)
29536        .unwrap_or(2)
29537        .min(32)
29538}