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, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings,
   65    ShowMinimap,
   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, ExcerptId, 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, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  140        all_language_settings, 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    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  154};
  155use parking_lot::Mutex;
  156use persistence::EditorDb;
  157use project::{
  158    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  159    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  160    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  161    ProjectItem, ProjectPath, ProjectTransaction,
  162    debugger::{
  163        breakpoint_store::{
  164            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  165            BreakpointStore, BreakpointStoreEvent,
  166        },
  167        session::{Session, SessionEvent},
  168    },
  169    git_store::GitStoreEvent,
  170    lsp_store::{
  171        BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger,
  172        LspFormatTarget, OpenLspBufferHandle, RefreshForServer,
  173    },
  174    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  175};
  176use rand::seq::SliceRandom;
  177use regex::Regex;
  178use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  179use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};
  180use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  181use serde::{Deserialize, Serialize};
  182use settings::{
  183    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  184    update_settings_file,
  185};
  186use smallvec::{SmallVec, smallvec};
  187use snippet::Snippet;
  188use std::{
  189    any::{Any, TypeId},
  190    borrow::Cow,
  191    cell::{OnceCell, RefCell},
  192    cmp::{self, Ordering, Reverse},
  193    collections::hash_map,
  194    iter::{self, Peekable},
  195    mem,
  196    num::NonZeroU32,
  197    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  198    path::{Path, PathBuf},
  199    rc::Rc,
  200    sync::Arc,
  201    time::{Duration, Instant},
  202};
  203use task::TaskVariables;
  204use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};
  205use theme::{
  206    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  207    ThemeSettings, observe_buffer_font_size_adjustment,
  208};
  209use ui::{
  210    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  211    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  212    utils::WithRemSize,
  213};
  214use ui_input::ErasedEditor;
  215use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  216use workspace::{
  217    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  218    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  219    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  220    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  221    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  222    searchable::SearchEvent,
  223};
  224pub use zed_actions::editor::RevealInFileManager;
  225use zed_actions::editor::{MoveDown, MoveUp};
  226
  227use crate::{
  228    code_context_menus::CompletionsMenuSource,
  229    editor_settings::MultiCursorModifier,
  230    hover_links::{find_url, find_url_from_range},
  231    inlays::{
  232        InlineValueCache,
  233        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  234    },
  235    runnables::{ResolvedTasks, RunnableData, RunnableTasks},
  236    scroll::{ScrollOffset, ScrollPixelOffset},
  237    selections_collection::resolve_selections_wrapping_blocks,
  238    semantic_tokens::SemanticTokenState,
  239    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  240};
  241
  242pub const FILE_HEADER_HEIGHT: u32 = 2;
  243pub const BUFFER_HEADER_PADDING: Rems = rems(0.25);
  244pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  245const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  246const MAX_LINE_LEN: usize = 1024;
  247const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  248const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  249pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  250#[doc(hidden)]
  251pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  252pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  253
  254pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  255pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  256pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  257pub const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50);
  258
  259pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  260pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  261
  262pub type RenderDiffHunkControlsFn = Arc<
  263    dyn Fn(
  264        u32,
  265        &DiffHunkStatus,
  266        Range<Anchor>,
  267        bool,
  268        Pixels,
  269        &Entity<Editor>,
  270        &mut Window,
  271        &mut App,
  272    ) -> AnyElement,
  273>;
  274
  275enum ReportEditorEvent {
  276    Saved { auto_saved: bool },
  277    EditorOpened,
  278    Closed,
  279}
  280
  281impl ReportEditorEvent {
  282    pub fn event_type(&self) -> &'static str {
  283        match self {
  284            Self::Saved { .. } => "Editor Saved",
  285            Self::EditorOpened => "Editor Opened",
  286            Self::Closed => "Editor Closed",
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293
  294pub enum ConflictsOuter {}
  295pub enum ConflictsOurs {}
  296pub enum ConflictsTheirs {}
  297pub enum ConflictsOursMarker {}
  298pub enum ConflictsTheirsMarker {}
  299
  300pub struct HunkAddedColor;
  301pub struct HunkRemovedColor;
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326        word_diffs: Vec<Range<MultiBufferOffset>>,
  327    },
  328}
  329
  330pub enum HideMouseCursorOrigin {
  331    TypingAction,
  332    MovementAction,
  333}
  334
  335pub fn init(cx: &mut App) {
  336    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  337    cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
  338
  339    workspace::register_project_item::<Editor>(cx);
  340    workspace::FollowableViewRegistry::register::<Editor>(cx);
  341    workspace::register_serializable_item::<Editor>(cx);
  342
  343    cx.observe_new(
  344        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  345            workspace.register_action(Editor::new_file);
  346            workspace.register_action(Editor::new_file_split);
  347            workspace.register_action(Editor::new_file_vertical);
  348            workspace.register_action(Editor::new_file_horizontal);
  349            workspace.register_action(Editor::cancel_language_server_work);
  350            workspace.register_action(Editor::toggle_focus);
  351        },
  352    )
  353    .detach();
  354
  355    cx.on_action(move |_: &workspace::NewFile, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    Editor::new_file(workspace, &Default::default(), window, cx)
  364                },
  365            )
  366            .detach_and_log_err(cx);
  367        }
  368    })
  369    .on_action(move |_: &workspace::NewWindow, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    cx.activate(true);
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach_and_log_err(cx);
  382        }
  383    });
  384    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  385        Arc::new(ErasedEditorImpl(
  386            cx.new(|cx| Editor::single_line(window, cx)),
  387        )) as Arc<dyn ErasedEditor>
  388    });
  389    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  390}
  391
  392pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  393    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  394}
  395
  396pub trait DiagnosticRenderer {
  397    fn render_group(
  398        &self,
  399        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  400        buffer_id: BufferId,
  401        snapshot: EditorSnapshot,
  402        editor: WeakEntity<Editor>,
  403        language_registry: Option<Arc<LanguageRegistry>>,
  404        cx: &mut App,
  405    ) -> Vec<BlockProperties<Anchor>>;
  406
  407    fn render_hover(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  410        range: Range<Point>,
  411        buffer_id: BufferId,
  412        language_registry: Option<Arc<LanguageRegistry>>,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  484pub enum SizingBehavior {
  485    /// The editor will layout itself using `size_full` and will include the vertical
  486    /// scroll margin as requested by user settings.
  487    #[default]
  488    Default,
  489    /// The editor will layout itself using `size_full`, but will not have any
  490    /// vertical overscroll.
  491    ExcludeOverscrollMargin,
  492    /// The editor will request a vertical size according to its content and will be
  493    /// layouted without a vertical scroll margin.
  494    SizeByContent,
  495}
  496
  497#[derive(Clone, PartialEq, Eq, Debug)]
  498pub enum EditorMode {
  499    SingleLine,
  500    AutoHeight {
  501        min_lines: usize,
  502        max_lines: Option<usize>,
  503    },
  504    Full {
  505        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  506        scale_ui_elements_with_buffer_font_size: bool,
  507        /// When set to `true`, the editor will render a background for the active line.
  508        show_active_line_background: bool,
  509        /// Determines the sizing behavior for this editor
  510        sizing_behavior: SizingBehavior,
  511    },
  512    Minimap {
  513        parent: WeakEntity<Editor>,
  514    },
  515}
  516
  517impl EditorMode {
  518    pub fn full() -> Self {
  519        Self::Full {
  520            scale_ui_elements_with_buffer_font_size: true,
  521            show_active_line_background: true,
  522            sizing_behavior: SizingBehavior::Default,
  523        }
  524    }
  525
  526    #[inline]
  527    pub fn is_full(&self) -> bool {
  528        matches!(self, Self::Full { .. })
  529    }
  530
  531    #[inline]
  532    pub fn is_single_line(&self) -> bool {
  533        matches!(self, Self::SingleLine { .. })
  534    }
  535
  536    #[inline]
  537    fn is_minimap(&self) -> bool {
  538        matches!(self, Self::Minimap { .. })
  539    }
  540}
  541
  542#[derive(Copy, Clone, Debug)]
  543pub enum SoftWrap {
  544    /// Prefer not to wrap at all.
  545    ///
  546    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  547    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  548    GitDiff,
  549    /// Prefer a single line generally, unless an overly long line is encountered.
  550    None,
  551    /// Soft wrap lines that exceed the editor width.
  552    EditorWidth,
  553    /// Soft wrap lines at the preferred line length.
  554    Column(u32),
  555    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  556    Bounded(u32),
  557}
  558
  559#[derive(Clone)]
  560pub struct EditorStyle {
  561    pub background: Hsla,
  562    pub border: Hsla,
  563    pub local_player: PlayerColor,
  564    pub text: TextStyle,
  565    pub scrollbar_width: Pixels,
  566    pub syntax: Arc<SyntaxTheme>,
  567    pub status: StatusColors,
  568    pub inlay_hints_style: HighlightStyle,
  569    pub edit_prediction_styles: EditPredictionStyles,
  570    pub unnecessary_code_fade: f32,
  571    pub show_underlines: bool,
  572}
  573
  574impl Default for EditorStyle {
  575    fn default() -> Self {
  576        Self {
  577            background: Hsla::default(),
  578            border: Hsla::default(),
  579            local_player: PlayerColor::default(),
  580            text: TextStyle::default(),
  581            scrollbar_width: Pixels::default(),
  582            syntax: Default::default(),
  583            // HACK: Status colors don't have a real default.
  584            // We should look into removing the status colors from the editor
  585            // style and retrieve them directly from the theme.
  586            status: StatusColors::dark(),
  587            inlay_hints_style: HighlightStyle::default(),
  588            edit_prediction_styles: EditPredictionStyles {
  589                insertion: HighlightStyle::default(),
  590                whitespace: HighlightStyle::default(),
  591            },
  592            unnecessary_code_fade: Default::default(),
  593            show_underlines: true,
  594        }
  595    }
  596}
  597
  598pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  599    let show_background = language_settings::language_settings(None, None, cx)
  600        .inlay_hints
  601        .show_background;
  602
  603    let mut style = cx.theme().syntax().get("hint");
  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        edits: Vec<(Range<Anchor>, Arc<str>)>,
  645        /// Predicted cursor position as (anchor, offset_from_anchor).
  646        /// The anchor is in multibuffer coordinates; after applying edits,
  647        /// resolve the anchor and add the offset to get the final cursor position.
  648        cursor_position: Option<(Anchor, usize)>,
  649        edit_preview: Option<EditPreview>,
  650        display_mode: EditDisplayMode,
  651        snapshot: BufferSnapshot,
  652    },
  653    /// Move to a specific location in the active editor
  654    MoveWithin {
  655        target: Anchor,
  656        snapshot: BufferSnapshot,
  657    },
  658    /// Move to a specific location in a different editor (not the active one)
  659    MoveOutside {
  660        target: language::Anchor,
  661        snapshot: BufferSnapshot,
  662    },
  663}
  664
  665struct EditPredictionState {
  666    inlay_ids: Vec<InlayId>,
  667    completion: EditPrediction,
  668    completion_id: Option<SharedString>,
  669    invalidation_range: Option<Range<Anchor>>,
  670}
  671
  672enum EditPredictionSettings {
  673    Disabled,
  674    Enabled {
  675        show_in_menu: bool,
  676        preview_requires_modifier: bool,
  677    },
  678}
  679
  680#[derive(Debug, Clone)]
  681struct InlineDiagnostic {
  682    message: SharedString,
  683    group_id: usize,
  684    is_primary: bool,
  685    start: Point,
  686    severity: lsp::DiagnosticSeverity,
  687}
  688
  689pub enum MenuEditPredictionsPolicy {
  690    Never,
  691    ByProvider,
  692}
  693
  694pub enum EditPredictionPreview {
  695    /// Modifier is not pressed
  696    Inactive { released_too_fast: bool },
  697    /// Modifier pressed
  698    Active {
  699        since: Instant,
  700        previous_scroll_position: Option<SharedScrollAnchor>,
  701    },
  702}
  703
  704#[derive(Copy, Clone, Eq, PartialEq)]
  705enum EditPredictionKeybindSurface {
  706    Inline,
  707    CursorPopoverCompact,
  708    CursorPopoverExpanded,
  709}
  710
  711#[derive(Copy, Clone, Eq, PartialEq, Debug)]
  712enum EditPredictionKeybindAction {
  713    Accept,
  714    Preview,
  715}
  716
  717struct EditPredictionKeybindDisplay {
  718    #[cfg(test)]
  719    accept_keystroke: Option<gpui::KeybindingKeystroke>,
  720    #[cfg(test)]
  721    preview_keystroke: Option<gpui::KeybindingKeystroke>,
  722    displayed_keystroke: Option<gpui::KeybindingKeystroke>,
  723    action: EditPredictionKeybindAction,
  724    missing_accept_keystroke: bool,
  725    show_hold_label: bool,
  726}
  727
  728impl EditPredictionPreview {
  729    pub fn released_too_fast(&self) -> bool {
  730        match self {
  731            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  732            EditPredictionPreview::Active { .. } => false,
  733        }
  734    }
  735
  736    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  737        if let EditPredictionPreview::Active {
  738            previous_scroll_position,
  739            ..
  740        } = self
  741        {
  742            *previous_scroll_position = scroll_position;
  743        }
  744    }
  745}
  746
  747pub struct ContextMenuOptions {
  748    pub min_entries_visible: usize,
  749    pub max_entries_visible: usize,
  750    pub placement: Option<ContextMenuPlacement>,
  751}
  752
  753#[derive(Debug, Clone, PartialEq, Eq)]
  754pub enum ContextMenuPlacement {
  755    Above,
  756    Below,
  757}
  758
  759#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  760struct EditorActionId(usize);
  761
  762impl EditorActionId {
  763    pub fn post_inc(&mut self) -> Self {
  764        let answer = self.0;
  765
  766        *self = Self(answer + 1);
  767
  768        Self(answer)
  769    }
  770}
  771
  772// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  773// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  774
  775type BackgroundHighlight = (
  776    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  777    Arc<[Range<Anchor>]>,
  778);
  779type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  780
  781#[derive(Default)]
  782struct ScrollbarMarkerState {
  783    scrollbar_size: Size<Pixels>,
  784    dirty: bool,
  785    markers: Arc<[PaintQuad]>,
  786    pending_refresh: Option<Task<Result<()>>>,
  787}
  788
  789impl ScrollbarMarkerState {
  790    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  791        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  792    }
  793}
  794
  795#[derive(Clone, Copy, PartialEq, Eq)]
  796pub enum MinimapVisibility {
  797    Disabled,
  798    Enabled {
  799        /// The configuration currently present in the users settings.
  800        setting_configuration: bool,
  801        /// Whether to override the currently set visibility from the users setting.
  802        toggle_override: bool,
  803    },
  804}
  805
  806impl MinimapVisibility {
  807    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  808        if mode.is_full() {
  809            Self::Enabled {
  810                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  811                toggle_override: false,
  812            }
  813        } else {
  814            Self::Disabled
  815        }
  816    }
  817
  818    fn hidden(&self) -> Self {
  819        match *self {
  820            Self::Enabled {
  821                setting_configuration,
  822                ..
  823            } => Self::Enabled {
  824                setting_configuration,
  825                toggle_override: setting_configuration,
  826            },
  827            Self::Disabled => Self::Disabled,
  828        }
  829    }
  830
  831    fn disabled(&self) -> bool {
  832        matches!(*self, Self::Disabled)
  833    }
  834
  835    fn settings_visibility(&self) -> bool {
  836        match *self {
  837            Self::Enabled {
  838                setting_configuration,
  839                ..
  840            } => setting_configuration,
  841            _ => false,
  842        }
  843    }
  844
  845    fn visible(&self) -> bool {
  846        match *self {
  847            Self::Enabled {
  848                setting_configuration,
  849                toggle_override,
  850            } => setting_configuration ^ toggle_override,
  851            _ => false,
  852        }
  853    }
  854
  855    fn toggle_visibility(&self) -> Self {
  856        match *self {
  857            Self::Enabled {
  858                toggle_override,
  859                setting_configuration,
  860            } => Self::Enabled {
  861                setting_configuration,
  862                toggle_override: !toggle_override,
  863            },
  864            Self::Disabled => Self::Disabled,
  865        }
  866    }
  867}
  868
  869#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  870pub enum BufferSerialization {
  871    All,
  872    NonDirtyBuffers,
  873}
  874
  875impl BufferSerialization {
  876    fn new(restore_unsaved_buffers: bool) -> Self {
  877        if restore_unsaved_buffers {
  878            Self::All
  879        } else {
  880            Self::NonDirtyBuffers
  881        }
  882    }
  883}
  884
  885/// Addons allow storing per-editor state in other crates (e.g. Vim)
  886pub trait Addon: 'static {
  887    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  888
  889    fn render_buffer_header_controls(
  890        &self,
  891        _: &ExcerptInfo,
  892        _: &Window,
  893        _: &App,
  894    ) -> Option<AnyElement> {
  895        None
  896    }
  897
  898    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  899        None
  900    }
  901
  902    fn to_any(&self) -> &dyn std::any::Any;
  903
  904    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  905        None
  906    }
  907}
  908
  909struct ChangeLocation {
  910    current: Option<Vec<Anchor>>,
  911    original: Vec<Anchor>,
  912}
  913impl ChangeLocation {
  914    fn locations(&self) -> &[Anchor] {
  915        self.current.as_ref().unwrap_or(&self.original)
  916    }
  917}
  918
  919/// A set of caret positions, registered when the editor was edited.
  920pub struct ChangeList {
  921    changes: Vec<ChangeLocation>,
  922    /// Currently "selected" change.
  923    position: Option<usize>,
  924}
  925
  926impl ChangeList {
  927    pub fn new() -> Self {
  928        Self {
  929            changes: Vec::new(),
  930            position: None,
  931        }
  932    }
  933
  934    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  935    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  936    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  937        if self.changes.is_empty() {
  938            return None;
  939        }
  940
  941        let prev = self.position.unwrap_or(self.changes.len());
  942        let next = if direction == Direction::Prev {
  943            prev.saturating_sub(count)
  944        } else {
  945            (prev + count).min(self.changes.len() - 1)
  946        };
  947        self.position = Some(next);
  948        self.changes.get(next).map(|change| change.locations())
  949    }
  950
  951    /// Adds a new change to the list, resetting the change list position.
  952    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  953        self.position.take();
  954        if let Some(last) = self.changes.last_mut()
  955            && group
  956        {
  957            last.current = Some(new_positions)
  958        } else {
  959            self.changes.push(ChangeLocation {
  960                original: new_positions,
  961                current: None,
  962            });
  963        }
  964    }
  965
  966    pub fn last(&self) -> Option<&[Anchor]> {
  967        self.changes.last().map(|change| change.locations())
  968    }
  969
  970    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  971        self.changes.last().map(|change| change.original.as_slice())
  972    }
  973
  974    pub fn invert_last_group(&mut self) {
  975        if let Some(last) = self.changes.last_mut()
  976            && let Some(current) = last.current.as_mut()
  977        {
  978            mem::swap(&mut last.original, current);
  979        }
  980    }
  981}
  982
  983#[derive(Clone)]
  984struct InlineBlamePopoverState {
  985    scroll_handle: ScrollHandle,
  986    commit_message: Option<ParsedCommitMessage>,
  987    markdown: Entity<Markdown>,
  988}
  989
  990struct InlineBlamePopover {
  991    position: gpui::Point<Pixels>,
  992    hide_task: Option<Task<()>>,
  993    popover_bounds: Option<Bounds<Pixels>>,
  994    popover_state: InlineBlamePopoverState,
  995    keyboard_grace: bool,
  996}
  997
  998enum SelectionDragState {
  999    /// State when no drag related activity is detected.
 1000    None,
 1001    /// State when the mouse is down on a selection that is about to be dragged.
 1002    ReadyToDrag {
 1003        selection: Selection<Anchor>,
 1004        click_position: gpui::Point<Pixels>,
 1005        mouse_down_time: Instant,
 1006    },
 1007    /// State when the mouse is dragging the selection in the editor.
 1008    Dragging {
 1009        selection: Selection<Anchor>,
 1010        drop_cursor: Selection<Anchor>,
 1011        hide_drop_cursor: bool,
 1012    },
 1013}
 1014
 1015enum ColumnarSelectionState {
 1016    FromMouse {
 1017        selection_tail: Anchor,
 1018        display_point: Option<DisplayPoint>,
 1019    },
 1020    FromSelection {
 1021        selection_tail: Anchor,
 1022    },
 1023}
 1024
 1025/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1026/// a breakpoint on them.
 1027#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1028struct PhantomBreakpointIndicator {
 1029    display_row: DisplayRow,
 1030    /// There's a small debounce between hovering over the line and showing the indicator.
 1031    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1032    is_active: bool,
 1033    collides_with_existing_breakpoint: bool,
 1034}
 1035
 1036/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1037/// in diff view mode.
 1038#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1039pub(crate) struct PhantomDiffReviewIndicator {
 1040    /// The starting anchor of the selection (or the only row if not dragging).
 1041    pub start: Anchor,
 1042    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1043    pub end: Anchor,
 1044    /// There's a small debounce between hovering over the line and showing the indicator.
 1045    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1046    pub is_active: bool,
 1047}
 1048
 1049#[derive(Clone, Debug)]
 1050pub(crate) struct DiffReviewDragState {
 1051    pub start_anchor: Anchor,
 1052    pub current_anchor: Anchor,
 1053}
 1054
 1055impl DiffReviewDragState {
 1056    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1057        let start = self.start_anchor.to_display_point(snapshot).row();
 1058        let current = self.current_anchor.to_display_point(snapshot).row();
 1059
 1060        (start..=current).sorted()
 1061    }
 1062}
 1063
 1064/// Identifies a specific hunk in the diff buffer.
 1065/// Used as a key to group comments by their location.
 1066#[derive(Clone, Debug)]
 1067pub struct DiffHunkKey {
 1068    /// The file path (relative to worktree) this hunk belongs to.
 1069    pub file_path: Arc<util::rel_path::RelPath>,
 1070    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1071    pub hunk_start_anchor: Anchor,
 1072}
 1073
 1074/// A review comment stored locally before being sent to the Agent panel.
 1075#[derive(Clone)]
 1076pub struct StoredReviewComment {
 1077    /// Unique identifier for this comment (for edit/delete operations).
 1078    pub id: usize,
 1079    /// The comment text entered by the user.
 1080    pub comment: String,
 1081    /// Anchors for the code range being reviewed.
 1082    pub range: Range<Anchor>,
 1083    /// Timestamp when the comment was created (for chronological ordering).
 1084    pub created_at: Instant,
 1085    /// Whether this comment is currently being edited inline.
 1086    pub is_editing: bool,
 1087}
 1088
 1089impl StoredReviewComment {
 1090    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1091        Self {
 1092            id,
 1093            comment,
 1094            range: anchor_range,
 1095            created_at: Instant::now(),
 1096            is_editing: false,
 1097        }
 1098    }
 1099}
 1100
 1101/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1102pub(crate) struct DiffReviewOverlay {
 1103    pub anchor_range: Range<Anchor>,
 1104    /// The block ID for the overlay.
 1105    pub block_id: CustomBlockId,
 1106    /// The editor entity for the review input.
 1107    pub prompt_editor: Entity<Editor>,
 1108    /// The hunk key this overlay belongs to.
 1109    pub hunk_key: DiffHunkKey,
 1110    /// Whether the comments section is expanded.
 1111    pub comments_expanded: bool,
 1112    /// Editors for comments currently being edited inline.
 1113    /// Key: comment ID, Value: Editor entity for inline editing.
 1114    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1115    /// Subscriptions for inline edit editors' action handlers.
 1116    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1117    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1118    /// The current user's avatar URI for display in comment rows.
 1119    pub user_avatar_uri: Option<SharedUri>,
 1120    /// Subscription to keep the action handler alive.
 1121    _subscription: Subscription,
 1122}
 1123
 1124/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1125///
 1126/// See the [module level documentation](self) for more information.
 1127pub struct Editor {
 1128    focus_handle: FocusHandle,
 1129    last_focused_descendant: Option<WeakFocusHandle>,
 1130    /// The text buffer being edited
 1131    buffer: Entity<MultiBuffer>,
 1132    /// Map of how text in the buffer should be displayed.
 1133    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1134    pub display_map: Entity<DisplayMap>,
 1135    placeholder_display_map: Option<Entity<DisplayMap>>,
 1136    pub selections: SelectionsCollection,
 1137    pub scroll_manager: ScrollManager,
 1138    /// When inline assist editors are linked, they all render cursors because
 1139    /// typing enters text into each of them, even the ones that aren't focused.
 1140    pub(crate) show_cursor_when_unfocused: bool,
 1141    columnar_selection_state: Option<ColumnarSelectionState>,
 1142    add_selections_state: Option<AddSelectionsState>,
 1143    select_next_state: Option<SelectNextState>,
 1144    select_prev_state: Option<SelectNextState>,
 1145    selection_history: SelectionHistory,
 1146    defer_selection_effects: bool,
 1147    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1148    autoclose_regions: Vec<AutocloseRegion>,
 1149    snippet_stack: InvalidationStack<SnippetState>,
 1150    select_syntax_node_history: SelectSyntaxNodeHistory,
 1151    ime_transaction: Option<TransactionId>,
 1152    pub diagnostics_max_severity: DiagnosticSeverity,
 1153    active_diagnostics: ActiveDiagnostic,
 1154    show_inline_diagnostics: bool,
 1155    inline_diagnostics_update: Task<()>,
 1156    inline_diagnostics_enabled: bool,
 1157    diagnostics_enabled: bool,
 1158    word_completions_enabled: bool,
 1159    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1160    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1161    hard_wrap: Option<usize>,
 1162    project: Option<Entity<Project>>,
 1163    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1164    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1165    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1166    blink_manager: Entity<BlinkManager>,
 1167    show_cursor_names: bool,
 1168    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1169    pub show_local_selections: bool,
 1170    mode: EditorMode,
 1171    show_breadcrumbs: bool,
 1172    show_gutter: bool,
 1173    show_scrollbars: ScrollbarAxes,
 1174    minimap_visibility: MinimapVisibility,
 1175    offset_content: bool,
 1176    disable_expand_excerpt_buttons: bool,
 1177    delegate_expand_excerpts: bool,
 1178    delegate_stage_and_restore: bool,
 1179    delegate_open_excerpts: bool,
 1180    enable_lsp_data: bool,
 1181    enable_runnables: bool,
 1182    show_line_numbers: Option<bool>,
 1183    use_relative_line_numbers: Option<bool>,
 1184    show_git_diff_gutter: Option<bool>,
 1185    show_code_actions: Option<bool>,
 1186    show_runnables: Option<bool>,
 1187    show_breakpoints: Option<bool>,
 1188    show_diff_review_button: bool,
 1189    show_wrap_guides: Option<bool>,
 1190    show_indent_guides: Option<bool>,
 1191    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1192    highlight_order: usize,
 1193    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1194    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1195    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1196    scrollbar_marker_state: ScrollbarMarkerState,
 1197    active_indent_guides_state: ActiveIndentGuidesState,
 1198    nav_history: Option<ItemNavHistory>,
 1199    context_menu: RefCell<Option<CodeContextMenu>>,
 1200    context_menu_options: Option<ContextMenuOptions>,
 1201    mouse_context_menu: Option<MouseContextMenu>,
 1202    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1203    inline_blame_popover: Option<InlineBlamePopover>,
 1204    inline_blame_popover_show_task: Option<Task<()>>,
 1205    signature_help_state: SignatureHelpState,
 1206    auto_signature_help: Option<bool>,
 1207    find_all_references_task_sources: Vec<Anchor>,
 1208    next_completion_id: CompletionId,
 1209    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1210    code_actions_task: Option<Task<Result<()>>>,
 1211    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1212    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1213    debounced_selection_highlight_complete: bool,
 1214    document_highlights_task: Option<Task<()>>,
 1215    linked_editing_range_task: Option<Task<Option<()>>>,
 1216    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1217    pending_rename: Option<RenameState>,
 1218    searchable: bool,
 1219    cursor_shape: CursorShape,
 1220    /// Whether the cursor is offset one character to the left when something is
 1221    /// selected (needed for vim visual mode)
 1222    cursor_offset_on_selection: bool,
 1223    current_line_highlight: Option<CurrentLineHighlight>,
 1224    /// Whether to collapse search match ranges to just their start position.
 1225    /// When true, navigating to a match positions the cursor at the match
 1226    /// without selecting the matched text.
 1227    collapse_matches: bool,
 1228    autoindent_mode: Option<AutoindentMode>,
 1229    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1230    input_enabled: bool,
 1231    expects_character_input: bool,
 1232    use_modal_editing: bool,
 1233    read_only: bool,
 1234    leader_id: Option<CollaboratorId>,
 1235    remote_id: Option<ViewId>,
 1236    pub hover_state: HoverState,
 1237    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1238    prev_pressure_stage: Option<PressureStage>,
 1239    gutter_hovered: bool,
 1240    hovered_link_state: Option<HoveredLinkState>,
 1241    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1242    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1243    active_edit_prediction: Option<EditPredictionState>,
 1244    /// Used to prevent flickering as the user types while the menu is open
 1245    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1246    edit_prediction_settings: EditPredictionSettings,
 1247    edit_predictions_hidden_for_vim_mode: bool,
 1248    show_edit_predictions_override: Option<bool>,
 1249    show_completions_on_input_override: Option<bool>,
 1250    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1251    edit_prediction_preview: EditPredictionPreview,
 1252    in_leading_whitespace: bool,
 1253    next_inlay_id: usize,
 1254    next_color_inlay_id: usize,
 1255    _subscriptions: Vec<Subscription>,
 1256    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1257    gutter_dimensions: GutterDimensions,
 1258    style: Option<EditorStyle>,
 1259    text_style_refinement: Option<TextStyleRefinement>,
 1260    next_editor_action_id: EditorActionId,
 1261    editor_actions: Rc<
 1262        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1263    >,
 1264    use_autoclose: bool,
 1265    use_auto_surround: bool,
 1266    auto_replace_emoji_shortcode: bool,
 1267    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1268    show_git_blame_gutter: bool,
 1269    show_git_blame_inline: bool,
 1270    show_git_blame_inline_delay_task: Option<Task<()>>,
 1271    git_blame_inline_enabled: bool,
 1272    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1273    buffer_serialization: Option<BufferSerialization>,
 1274    show_selection_menu: Option<bool>,
 1275    blame: Option<Entity<GitBlame>>,
 1276    blame_subscription: Option<Subscription>,
 1277    custom_context_menu: Option<
 1278        Box<
 1279            dyn 'static
 1280                + Fn(
 1281                    &mut Self,
 1282                    DisplayPoint,
 1283                    &mut Window,
 1284                    &mut Context<Self>,
 1285                ) -> Option<Entity<ui::ContextMenu>>,
 1286        >,
 1287    >,
 1288    last_bounds: Option<Bounds<Pixels>>,
 1289    last_position_map: Option<Rc<PositionMap>>,
 1290    expect_bounds_change: Option<Bounds<Pixels>>,
 1291    runnables: RunnableData,
 1292    breakpoint_store: Option<Entity<BreakpointStore>>,
 1293    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1294    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1295    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1296    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1297    /// when hunks have comments stored.
 1298    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1299    /// Stored review comments grouped by hunk.
 1300    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1301    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1302    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1303    /// Counter for generating unique comment IDs.
 1304    next_review_comment_id: usize,
 1305    hovered_diff_hunk_row: Option<DisplayRow>,
 1306    pull_diagnostics_task: Task<()>,
 1307    in_project_search: bool,
 1308    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1309    breadcrumb_header: Option<String>,
 1310    focused_block: Option<FocusedBlock>,
 1311    next_scroll_position: NextScrollCursorCenterTopBottom,
 1312    addons: HashMap<TypeId, Box<dyn Addon>>,
 1313    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1314    load_diff_task: Option<Shared<Task<()>>>,
 1315    /// Whether we are temporarily displaying a diff other than git's
 1316    temporary_diff_override: bool,
 1317    selection_mark_mode: bool,
 1318    toggle_fold_multiple_buffers: Task<()>,
 1319    _scroll_cursor_center_top_bottom_task: Task<()>,
 1320    serialize_selections: Task<()>,
 1321    serialize_folds: Task<()>,
 1322    mouse_cursor_hidden: bool,
 1323    minimap: Option<Entity<Self>>,
 1324    hide_mouse_mode: HideMouseMode,
 1325    pub change_list: ChangeList,
 1326    inline_value_cache: InlineValueCache,
 1327    number_deleted_lines: bool,
 1328
 1329    selection_drag_state: SelectionDragState,
 1330    colors: Option<LspColorData>,
 1331    post_scroll_update: Task<()>,
 1332    refresh_colors_task: Task<()>,
 1333    use_document_folding_ranges: bool,
 1334    refresh_folding_ranges_task: Task<()>,
 1335    inlay_hints: Option<LspInlayHintData>,
 1336    folding_newlines: Task<()>,
 1337    select_next_is_case_sensitive: Option<bool>,
 1338    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1339    on_local_selections_changed:
 1340        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1341    suppress_selection_callback: bool,
 1342    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1343    accent_data: Option<AccentData>,
 1344    bracket_fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1345    semantic_token_state: SemanticTokenState,
 1346    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1347    refresh_document_symbols_task: Shared<Task<()>>,
 1348    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1349    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1350    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1351    sticky_headers_task: Task<()>,
 1352    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1353    pub(crate) colorize_brackets_task: Task<()>,
 1354}
 1355
 1356#[derive(Debug, PartialEq)]
 1357struct AccentData {
 1358    colors: AccentColors,
 1359    overrides: Vec<SharedString>,
 1360}
 1361
 1362fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1363    if debounce_ms > 0 {
 1364        Some(Duration::from_millis(debounce_ms))
 1365    } else {
 1366        None
 1367    }
 1368}
 1369
 1370#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1371enum NextScrollCursorCenterTopBottom {
 1372    #[default]
 1373    Center,
 1374    Top,
 1375    Bottom,
 1376}
 1377
 1378impl NextScrollCursorCenterTopBottom {
 1379    fn next(&self) -> Self {
 1380        match self {
 1381            Self::Center => Self::Top,
 1382            Self::Top => Self::Bottom,
 1383            Self::Bottom => Self::Center,
 1384        }
 1385    }
 1386}
 1387
 1388#[derive(Clone)]
 1389pub struct EditorSnapshot {
 1390    pub mode: EditorMode,
 1391    show_gutter: bool,
 1392    offset_content: bool,
 1393    show_line_numbers: Option<bool>,
 1394    number_deleted_lines: bool,
 1395    show_git_diff_gutter: Option<bool>,
 1396    show_code_actions: Option<bool>,
 1397    show_runnables: Option<bool>,
 1398    show_breakpoints: Option<bool>,
 1399    git_blame_gutter_max_author_length: Option<usize>,
 1400    pub display_snapshot: DisplaySnapshot,
 1401    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1402    is_focused: bool,
 1403    scroll_anchor: SharedScrollAnchor,
 1404    ongoing_scroll: OngoingScroll,
 1405    current_line_highlight: CurrentLineHighlight,
 1406    gutter_hovered: bool,
 1407    semantic_tokens_enabled: bool,
 1408}
 1409
 1410#[derive(Default, Debug, Clone, Copy)]
 1411pub struct GutterDimensions {
 1412    pub left_padding: Pixels,
 1413    pub right_padding: Pixels,
 1414    pub width: Pixels,
 1415    pub margin: Pixels,
 1416    pub git_blame_entries_width: Option<Pixels>,
 1417}
 1418
 1419impl GutterDimensions {
 1420    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1421        Self {
 1422            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1423            ..Default::default()
 1424        }
 1425    }
 1426
 1427    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1428        -cx.text_system().descent(font_id, font_size)
 1429    }
 1430    /// The full width of the space taken up by the gutter.
 1431    pub fn full_width(&self) -> Pixels {
 1432        self.margin + self.width
 1433    }
 1434
 1435    /// The width of the space reserved for the fold indicators,
 1436    /// use alongside 'justify_end' and `gutter_width` to
 1437    /// right align content with the line numbers
 1438    pub fn fold_area_width(&self) -> Pixels {
 1439        self.margin + self.right_padding
 1440    }
 1441}
 1442
 1443struct CharacterDimensions {
 1444    em_width: Pixels,
 1445    em_advance: Pixels,
 1446    line_height: Pixels,
 1447}
 1448
 1449#[derive(Debug)]
 1450pub struct RemoteSelection {
 1451    pub replica_id: ReplicaId,
 1452    pub selection: Selection<Anchor>,
 1453    pub cursor_shape: CursorShape,
 1454    pub collaborator_id: CollaboratorId,
 1455    pub line_mode: bool,
 1456    pub user_name: Option<SharedString>,
 1457    pub color: PlayerColor,
 1458}
 1459
 1460#[derive(Clone, Debug)]
 1461struct SelectionHistoryEntry {
 1462    selections: Arc<[Selection<Anchor>]>,
 1463    select_next_state: Option<SelectNextState>,
 1464    select_prev_state: Option<SelectNextState>,
 1465    add_selections_state: Option<AddSelectionsState>,
 1466}
 1467
 1468#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1469enum SelectionHistoryMode {
 1470    #[default]
 1471    Normal,
 1472    Undoing,
 1473    Redoing,
 1474    Skipping,
 1475}
 1476
 1477#[derive(Clone, PartialEq, Eq, Hash)]
 1478struct HoveredCursor {
 1479    replica_id: ReplicaId,
 1480    selection_id: usize,
 1481}
 1482
 1483#[derive(Debug)]
 1484/// SelectionEffects controls the side-effects of updating the selection.
 1485///
 1486/// The default behaviour does "what you mostly want":
 1487/// - it pushes to the nav history if the cursor moved by >10 lines
 1488/// - it re-triggers completion requests
 1489/// - it scrolls to fit
 1490///
 1491/// You might want to modify these behaviours. For example when doing a "jump"
 1492/// like go to definition, we always want to add to nav history; but when scrolling
 1493/// in vim mode we never do.
 1494///
 1495/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1496/// move.
 1497#[derive(Clone)]
 1498pub struct SelectionEffects {
 1499    nav_history: Option<bool>,
 1500    completions: bool,
 1501    scroll: Option<Autoscroll>,
 1502}
 1503
 1504impl Default for SelectionEffects {
 1505    fn default() -> Self {
 1506        Self {
 1507            nav_history: None,
 1508            completions: true,
 1509            scroll: Some(Autoscroll::fit()),
 1510        }
 1511    }
 1512}
 1513impl SelectionEffects {
 1514    pub fn scroll(scroll: Autoscroll) -> Self {
 1515        Self {
 1516            scroll: Some(scroll),
 1517            ..Default::default()
 1518        }
 1519    }
 1520
 1521    pub fn no_scroll() -> Self {
 1522        Self {
 1523            scroll: None,
 1524            ..Default::default()
 1525        }
 1526    }
 1527
 1528    pub fn completions(self, completions: bool) -> Self {
 1529        Self {
 1530            completions,
 1531            ..self
 1532        }
 1533    }
 1534
 1535    pub fn nav_history(self, nav_history: bool) -> Self {
 1536        Self {
 1537            nav_history: Some(nav_history),
 1538            ..self
 1539        }
 1540    }
 1541}
 1542
 1543struct DeferredSelectionEffectsState {
 1544    changed: bool,
 1545    effects: SelectionEffects,
 1546    old_cursor_position: Anchor,
 1547    history_entry: SelectionHistoryEntry,
 1548}
 1549
 1550#[derive(Default)]
 1551struct SelectionHistory {
 1552    #[allow(clippy::type_complexity)]
 1553    selections_by_transaction:
 1554        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1555    mode: SelectionHistoryMode,
 1556    undo_stack: VecDeque<SelectionHistoryEntry>,
 1557    redo_stack: VecDeque<SelectionHistoryEntry>,
 1558}
 1559
 1560impl SelectionHistory {
 1561    #[track_caller]
 1562    fn insert_transaction(
 1563        &mut self,
 1564        transaction_id: TransactionId,
 1565        selections: Arc<[Selection<Anchor>]>,
 1566    ) {
 1567        if selections.is_empty() {
 1568            log::error!(
 1569                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1570                std::panic::Location::caller()
 1571            );
 1572            return;
 1573        }
 1574        self.selections_by_transaction
 1575            .insert(transaction_id, (selections, None));
 1576    }
 1577
 1578    #[allow(clippy::type_complexity)]
 1579    fn transaction(
 1580        &self,
 1581        transaction_id: TransactionId,
 1582    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1583        self.selections_by_transaction.get(&transaction_id)
 1584    }
 1585
 1586    #[allow(clippy::type_complexity)]
 1587    fn transaction_mut(
 1588        &mut self,
 1589        transaction_id: TransactionId,
 1590    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1591        self.selections_by_transaction.get_mut(&transaction_id)
 1592    }
 1593
 1594    fn push(&mut self, entry: SelectionHistoryEntry) {
 1595        if !entry.selections.is_empty() {
 1596            match self.mode {
 1597                SelectionHistoryMode::Normal => {
 1598                    self.push_undo(entry);
 1599                    self.redo_stack.clear();
 1600                }
 1601                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1602                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1603                SelectionHistoryMode::Skipping => {}
 1604            }
 1605        }
 1606    }
 1607
 1608    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1609        if self
 1610            .undo_stack
 1611            .back()
 1612            .is_none_or(|e| e.selections != entry.selections)
 1613        {
 1614            self.undo_stack.push_back(entry);
 1615            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1616                self.undo_stack.pop_front();
 1617            }
 1618        }
 1619    }
 1620
 1621    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1622        if self
 1623            .redo_stack
 1624            .back()
 1625            .is_none_or(|e| e.selections != entry.selections)
 1626        {
 1627            self.redo_stack.push_back(entry);
 1628            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1629                self.redo_stack.pop_front();
 1630            }
 1631        }
 1632    }
 1633}
 1634
 1635#[derive(Clone, Copy)]
 1636pub struct RowHighlightOptions {
 1637    pub autoscroll: bool,
 1638    pub include_gutter: bool,
 1639}
 1640
 1641impl Default for RowHighlightOptions {
 1642    fn default() -> Self {
 1643        Self {
 1644            autoscroll: Default::default(),
 1645            include_gutter: true,
 1646        }
 1647    }
 1648}
 1649
 1650struct RowHighlight {
 1651    index: usize,
 1652    range: Range<Anchor>,
 1653    color: Hsla,
 1654    options: RowHighlightOptions,
 1655    type_id: TypeId,
 1656}
 1657
 1658#[derive(Clone, Debug)]
 1659struct AddSelectionsState {
 1660    groups: Vec<AddSelectionsGroup>,
 1661}
 1662
 1663#[derive(Clone, Debug)]
 1664struct AddSelectionsGroup {
 1665    above: bool,
 1666    stack: Vec<usize>,
 1667}
 1668
 1669#[derive(Clone)]
 1670struct SelectNextState {
 1671    query: AhoCorasick,
 1672    wordwise: bool,
 1673    done: bool,
 1674}
 1675
 1676impl std::fmt::Debug for SelectNextState {
 1677    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1678        f.debug_struct(std::any::type_name::<Self>())
 1679            .field("wordwise", &self.wordwise)
 1680            .field("done", &self.done)
 1681            .finish()
 1682    }
 1683}
 1684
 1685#[derive(Debug)]
 1686struct AutocloseRegion {
 1687    selection_id: usize,
 1688    range: Range<Anchor>,
 1689    pair: BracketPair,
 1690}
 1691
 1692#[derive(Debug)]
 1693struct SnippetState {
 1694    ranges: Vec<Vec<Range<Anchor>>>,
 1695    active_index: usize,
 1696    choices: Vec<Option<Vec<String>>>,
 1697}
 1698
 1699#[doc(hidden)]
 1700pub struct RenameState {
 1701    pub range: Range<Anchor>,
 1702    pub old_name: Arc<str>,
 1703    pub editor: Entity<Editor>,
 1704    block_id: CustomBlockId,
 1705}
 1706
 1707struct InvalidationStack<T>(Vec<T>);
 1708
 1709struct RegisteredEditPredictionDelegate {
 1710    provider: Arc<dyn EditPredictionDelegateHandle>,
 1711    _subscription: Subscription,
 1712}
 1713
 1714#[derive(Debug, PartialEq, Eq)]
 1715pub struct ActiveDiagnosticGroup {
 1716    pub active_range: Range<Anchor>,
 1717    pub active_message: String,
 1718    pub group_id: usize,
 1719    pub blocks: HashSet<CustomBlockId>,
 1720}
 1721
 1722#[derive(Debug, PartialEq, Eq)]
 1723
 1724pub(crate) enum ActiveDiagnostic {
 1725    None,
 1726    All,
 1727    Group(ActiveDiagnosticGroup),
 1728}
 1729
 1730#[derive(Serialize, Deserialize, Clone, Debug)]
 1731pub struct ClipboardSelection {
 1732    /// The number of bytes in this selection.
 1733    pub len: usize,
 1734    /// Whether this was a full-line selection.
 1735    pub is_entire_line: bool,
 1736    /// The indentation of the first line when this content was originally copied.
 1737    pub first_line_indent: u32,
 1738    #[serde(default)]
 1739    pub file_path: Option<PathBuf>,
 1740    #[serde(default)]
 1741    pub line_range: Option<RangeInclusive<u32>>,
 1742}
 1743
 1744impl ClipboardSelection {
 1745    pub fn for_buffer(
 1746        len: usize,
 1747        is_entire_line: bool,
 1748        range: Range<Point>,
 1749        buffer: &MultiBufferSnapshot,
 1750        project: Option<&Entity<Project>>,
 1751        cx: &App,
 1752    ) -> Self {
 1753        let first_line_indent = buffer
 1754            .indent_size_for_line(MultiBufferRow(range.start.row))
 1755            .len;
 1756
 1757        let file_path = util::maybe!({
 1758            let project = project?.read(cx);
 1759            let file = buffer.file_at(range.start)?;
 1760            let project_path = ProjectPath {
 1761                worktree_id: file.worktree_id(cx),
 1762                path: file.path().clone(),
 1763            };
 1764            project.absolute_path(&project_path, cx)
 1765        });
 1766
 1767        let line_range = file_path.as_ref().and_then(|_| {
 1768            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1769            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1770            if start_excerpt_id == end_excerpt_id {
 1771                Some(start_point.row..=end_point.row)
 1772            } else {
 1773                None
 1774            }
 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        excerpt_id: ExcerptId,
 1857        position: Point,
 1858        anchor: text::Anchor,
 1859        line_offset_from_top: u32,
 1860    },
 1861}
 1862
 1863pub enum MultibufferSelectionMode {
 1864    First,
 1865    All,
 1866}
 1867
 1868#[derive(Clone, Copy, Debug, Default)]
 1869pub struct RewrapOptions {
 1870    pub override_language_settings: bool,
 1871    pub preserve_existing_whitespace: bool,
 1872    pub line_length: Option<usize>,
 1873}
 1874
 1875impl Editor {
 1876    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1877        let buffer = cx.new(|cx| Buffer::local("", cx));
 1878        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1879        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1880    }
 1881
 1882    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1883        let buffer = cx.new(|cx| Buffer::local("", cx));
 1884        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1885        Self::new(EditorMode::full(), buffer, None, window, cx)
 1886    }
 1887
 1888    pub fn auto_height(
 1889        min_lines: usize,
 1890        max_lines: usize,
 1891        window: &mut Window,
 1892        cx: &mut Context<Self>,
 1893    ) -> Self {
 1894        let buffer = cx.new(|cx| Buffer::local("", cx));
 1895        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1896        Self::new(
 1897            EditorMode::AutoHeight {
 1898                min_lines,
 1899                max_lines: Some(max_lines),
 1900            },
 1901            buffer,
 1902            None,
 1903            window,
 1904            cx,
 1905        )
 1906    }
 1907
 1908    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1909    /// The editor grows as tall as needed to fit its content.
 1910    pub fn auto_height_unbounded(
 1911        min_lines: usize,
 1912        window: &mut Window,
 1913        cx: &mut Context<Self>,
 1914    ) -> Self {
 1915        let buffer = cx.new(|cx| Buffer::local("", cx));
 1916        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1917        Self::new(
 1918            EditorMode::AutoHeight {
 1919                min_lines,
 1920                max_lines: None,
 1921            },
 1922            buffer,
 1923            None,
 1924            window,
 1925            cx,
 1926        )
 1927    }
 1928
 1929    pub fn for_buffer(
 1930        buffer: Entity<Buffer>,
 1931        project: Option<Entity<Project>>,
 1932        window: &mut Window,
 1933        cx: &mut Context<Self>,
 1934    ) -> Self {
 1935        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1936        Self::new(EditorMode::full(), buffer, project, window, cx)
 1937    }
 1938
 1939    pub fn for_multibuffer(
 1940        buffer: Entity<MultiBuffer>,
 1941        project: Option<Entity<Project>>,
 1942        window: &mut Window,
 1943        cx: &mut Context<Self>,
 1944    ) -> Self {
 1945        Self::new(EditorMode::full(), buffer, project, window, cx)
 1946    }
 1947
 1948    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1949        let mut clone = Self::new(
 1950            self.mode.clone(),
 1951            self.buffer.clone(),
 1952            self.project.clone(),
 1953            window,
 1954            cx,
 1955        );
 1956        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1957            let snapshot = display_map.snapshot(cx);
 1958            clone.display_map.update(cx, |display_map, cx| {
 1959                display_map.set_state(&snapshot, cx);
 1960            });
 1961            snapshot
 1962        });
 1963        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1964        clone.folds_did_change(cx);
 1965        clone.selections.clone_state(&self.selections);
 1966        clone
 1967            .scroll_manager
 1968            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1969        clone.searchable = self.searchable;
 1970        clone.read_only = self.read_only;
 1971        clone.buffers_with_disabled_indent_guides =
 1972            self.buffers_with_disabled_indent_guides.clone();
 1973        clone
 1974    }
 1975
 1976    pub fn new(
 1977        mode: EditorMode,
 1978        buffer: Entity<MultiBuffer>,
 1979        project: Option<Entity<Project>>,
 1980        window: &mut Window,
 1981        cx: &mut Context<Self>,
 1982    ) -> Self {
 1983        Editor::new_internal(mode, buffer, project, None, window, cx)
 1984    }
 1985
 1986    pub fn refresh_sticky_headers(
 1987        &mut self,
 1988        display_snapshot: &DisplaySnapshot,
 1989        cx: &mut Context<Editor>,
 1990    ) {
 1991        if !self.mode.is_full() {
 1992            return;
 1993        }
 1994        let multi_buffer = display_snapshot.buffer_snapshot();
 1995        let scroll_anchor = self
 1996            .scroll_manager
 1997            .native_anchor(display_snapshot, cx)
 1998            .anchor;
 1999        let Some((excerpt_id, _, buffer)) = multi_buffer.as_singleton() else {
 2000            return;
 2001        };
 2002        let buffer = buffer.clone();
 2003
 2004        let buffer_visible_start = scroll_anchor.text_anchor.to_point(&buffer);
 2005        let max_row = buffer.max_point().row;
 2006        let start_row = buffer_visible_start.row.min(max_row);
 2007        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2008
 2009        let syntax = self.style(cx).syntax.clone();
 2010        let background_task = cx.background_spawn(async move {
 2011            buffer
 2012                .outline_items_containing(
 2013                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2014                    true,
 2015                    Some(syntax.as_ref()),
 2016                )
 2017                .into_iter()
 2018                .map(|outline_item| OutlineItem {
 2019                    depth: outline_item.depth,
 2020                    range: Anchor::range_in_buffer(excerpt_id, outline_item.range),
 2021                    source_range_for_text: Anchor::range_in_buffer(
 2022                        excerpt_id,
 2023                        outline_item.source_range_for_text,
 2024                    ),
 2025                    text: outline_item.text,
 2026                    highlight_ranges: outline_item.highlight_ranges,
 2027                    name_ranges: outline_item.name_ranges,
 2028                    body_range: outline_item
 2029                        .body_range
 2030                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2031                    annotation_range: outline_item
 2032                        .annotation_range
 2033                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2034                })
 2035                .collect()
 2036        });
 2037        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2038            let sticky_headers = background_task.await;
 2039            this.update(cx, |this, cx| {
 2040                this.sticky_headers = Some(sticky_headers);
 2041                cx.notify();
 2042            })
 2043            .ok();
 2044        });
 2045    }
 2046
 2047    fn new_internal(
 2048        mode: EditorMode,
 2049        multi_buffer: Entity<MultiBuffer>,
 2050        project: Option<Entity<Project>>,
 2051        display_map: Option<Entity<DisplayMap>>,
 2052        window: &mut Window,
 2053        cx: &mut Context<Self>,
 2054    ) -> Self {
 2055        debug_assert!(
 2056            display_map.is_none() || mode.is_minimap(),
 2057            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2058        );
 2059
 2060        let full_mode = mode.is_full();
 2061        let is_minimap = mode.is_minimap();
 2062        let diagnostics_max_severity = if full_mode {
 2063            EditorSettings::get_global(cx)
 2064                .diagnostics_max_severity
 2065                .unwrap_or(DiagnosticSeverity::Hint)
 2066        } else {
 2067            DiagnosticSeverity::Off
 2068        };
 2069        let style = window.text_style();
 2070        let font_size = style.font_size.to_pixels(window.rem_size());
 2071        let editor = cx.entity().downgrade();
 2072        let fold_placeholder = FoldPlaceholder {
 2073            constrain_width: false,
 2074            render: Arc::new(move |fold_id, fold_range, cx| {
 2075                let editor = editor.clone();
 2076                FoldPlaceholder::fold_element(fold_id, cx)
 2077                    .cursor_pointer()
 2078                    .child("")
 2079                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2080                    .on_click(move |_, _window, cx| {
 2081                        editor
 2082                            .update(cx, |editor, cx| {
 2083                                editor.unfold_ranges(
 2084                                    &[fold_range.start..fold_range.end],
 2085                                    true,
 2086                                    false,
 2087                                    cx,
 2088                                );
 2089                                cx.stop_propagation();
 2090                            })
 2091                            .ok();
 2092                    })
 2093                    .into_any()
 2094            }),
 2095            merge_adjacent: true,
 2096            ..FoldPlaceholder::default()
 2097        };
 2098        let display_map = display_map.unwrap_or_else(|| {
 2099            cx.new(|cx| {
 2100                DisplayMap::new(
 2101                    multi_buffer.clone(),
 2102                    style.font(),
 2103                    font_size,
 2104                    None,
 2105                    FILE_HEADER_HEIGHT,
 2106                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2107                    fold_placeholder,
 2108                    diagnostics_max_severity,
 2109                    cx,
 2110                )
 2111            })
 2112        });
 2113
 2114        let selections = SelectionsCollection::new();
 2115
 2116        let blink_manager = cx.new(|cx| {
 2117            let mut blink_manager = BlinkManager::new(
 2118                CURSOR_BLINK_INTERVAL,
 2119                |cx| EditorSettings::get_global(cx).cursor_blink,
 2120                cx,
 2121            );
 2122            if is_minimap {
 2123                blink_manager.disable(cx);
 2124            }
 2125            blink_manager
 2126        });
 2127
 2128        let soft_wrap_mode_override =
 2129            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2130
 2131        let mut project_subscriptions = Vec::new();
 2132        if full_mode && let Some(project) = project.as_ref() {
 2133            project_subscriptions.push(cx.subscribe_in(
 2134                project,
 2135                window,
 2136                |editor, _, event, window, cx| match event {
 2137                    project::Event::RefreshCodeLens => {
 2138                        // we always query lens with actions, without storing them, always refreshing them
 2139                    }
 2140                    project::Event::RefreshInlayHints {
 2141                        server_id,
 2142                        request_id,
 2143                    } => {
 2144                        editor.refresh_inlay_hints(
 2145                            InlayHintRefreshReason::RefreshRequested {
 2146                                server_id: *server_id,
 2147                                request_id: *request_id,
 2148                            },
 2149                            cx,
 2150                        );
 2151                    }
 2152                    project::Event::RefreshSemanticTokens {
 2153                        server_id,
 2154                        request_id,
 2155                    } => {
 2156                        editor.refresh_semantic_tokens(
 2157                            None,
 2158                            Some(RefreshForServer {
 2159                                server_id: *server_id,
 2160                                request_id: *request_id,
 2161                            }),
 2162                            cx,
 2163                        );
 2164                    }
 2165                    project::Event::LanguageServerRemoved(_) => {
 2166                        editor.registered_buffers.clear();
 2167                        editor.register_visible_buffers(cx);
 2168                        editor.invalidate_semantic_tokens(None);
 2169                        editor.refresh_runnables(None, window, cx);
 2170                        editor.update_lsp_data(None, window, cx);
 2171                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2172                    }
 2173                    project::Event::SnippetEdit(id, snippet_edits) => {
 2174                        // todo(lw): Non singletons
 2175                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2176                            let snapshot = buffer.read(cx).snapshot();
 2177                            let focus_handle = editor.focus_handle(cx);
 2178                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2179                                for (range, snippet) in snippet_edits {
 2180                                    let buffer_range =
 2181                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2182                                    editor
 2183                                        .insert_snippet(
 2184                                            &[MultiBufferOffset(buffer_range.start)
 2185                                                ..MultiBufferOffset(buffer_range.end)],
 2186                                            snippet.clone(),
 2187                                            window,
 2188                                            cx,
 2189                                        )
 2190                                        .ok();
 2191                                }
 2192                            }
 2193                        }
 2194                    }
 2195                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2196                        let buffer_id = *buffer_id;
 2197                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2198                            editor.register_buffer(buffer_id, cx);
 2199                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2200                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2201                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2202                            refresh_linked_ranges(editor, window, cx);
 2203                            editor.refresh_code_actions(window, cx);
 2204                            editor.refresh_document_highlights(cx);
 2205                        }
 2206                    }
 2207
 2208                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2209                        let Some(workspace) = editor.workspace() else {
 2210                            return;
 2211                        };
 2212                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2213                        else {
 2214                            return;
 2215                        };
 2216
 2217                        if active_editor.entity_id() == cx.entity_id() {
 2218                            let entity_id = cx.entity_id();
 2219                            workspace.update(cx, |this, cx| {
 2220                                this.panes_mut()
 2221                                    .iter_mut()
 2222                                    .filter(|pane| pane.entity_id() != entity_id)
 2223                                    .for_each(|p| {
 2224                                        p.update(cx, |pane, _| {
 2225                                            pane.nav_history_mut().rename_item(
 2226                                                entity_id,
 2227                                                project_path.clone(),
 2228                                                abs_path.clone().into(),
 2229                                            );
 2230                                        })
 2231                                    });
 2232                            });
 2233
 2234                            Self::open_transaction_for_hidden_buffers(
 2235                                workspace,
 2236                                transaction.clone(),
 2237                                "Rename".to_string(),
 2238                                window,
 2239                                cx,
 2240                            );
 2241                        }
 2242                    }
 2243
 2244                    project::Event::WorkspaceEditApplied(transaction) => {
 2245                        let Some(workspace) = editor.workspace() else {
 2246                            return;
 2247                        };
 2248                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2249                        else {
 2250                            return;
 2251                        };
 2252
 2253                        if active_editor.entity_id() == cx.entity_id() {
 2254                            Self::open_transaction_for_hidden_buffers(
 2255                                workspace,
 2256                                transaction.clone(),
 2257                                "LSP Edit".to_string(),
 2258                                window,
 2259                                cx,
 2260                            );
 2261                        }
 2262                    }
 2263
 2264                    _ => {}
 2265                },
 2266            ));
 2267            if let Some(task_inventory) = project
 2268                .read(cx)
 2269                .task_store()
 2270                .read(cx)
 2271                .task_inventory()
 2272                .cloned()
 2273            {
 2274                project_subscriptions.push(cx.observe_in(
 2275                    &task_inventory,
 2276                    window,
 2277                    |editor, _, window, cx| {
 2278                        editor.refresh_runnables(None, window, cx);
 2279                    },
 2280                ));
 2281            };
 2282
 2283            project_subscriptions.push(cx.subscribe_in(
 2284                &project.read(cx).breakpoint_store(),
 2285                window,
 2286                |editor, _, event, window, cx| match event {
 2287                    BreakpointStoreEvent::ClearDebugLines => {
 2288                        editor.clear_row_highlights::<ActiveDebugLine>();
 2289                        editor.refresh_inline_values(cx);
 2290                    }
 2291                    BreakpointStoreEvent::SetDebugLine => {
 2292                        if editor.go_to_active_debug_line(window, cx) {
 2293                            cx.stop_propagation();
 2294                        }
 2295
 2296                        editor.refresh_inline_values(cx);
 2297                    }
 2298                    _ => {}
 2299                },
 2300            ));
 2301            let git_store = project.read(cx).git_store().clone();
 2302            let project = project.clone();
 2303            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2304                if let GitStoreEvent::RepositoryAdded = event {
 2305                    this.load_diff_task = Some(
 2306                        update_uncommitted_diff_for_buffer(
 2307                            cx.entity(),
 2308                            &project,
 2309                            this.buffer.read(cx).all_buffers(),
 2310                            this.buffer.clone(),
 2311                            cx,
 2312                        )
 2313                        .shared(),
 2314                    );
 2315                }
 2316            }));
 2317        }
 2318
 2319        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2320
 2321        let inlay_hint_settings =
 2322            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2323        let focus_handle = cx.focus_handle();
 2324        if !is_minimap {
 2325            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2326                .detach();
 2327            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2328                .detach();
 2329            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2330                .detach();
 2331            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2332                .detach();
 2333            cx.observe_pending_input(window, Self::observe_pending_input)
 2334                .detach();
 2335        }
 2336
 2337        let show_indent_guides =
 2338            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2339                Some(false)
 2340            } else {
 2341                None
 2342            };
 2343
 2344        let breakpoint_store = match (&mode, project.as_ref()) {
 2345            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2346            _ => None,
 2347        };
 2348
 2349        let mut code_action_providers = Vec::new();
 2350        let mut load_uncommitted_diff = None;
 2351        if let Some(project) = project.clone() {
 2352            load_uncommitted_diff = Some(
 2353                update_uncommitted_diff_for_buffer(
 2354                    cx.entity(),
 2355                    &project,
 2356                    multi_buffer.read(cx).all_buffers(),
 2357                    multi_buffer.clone(),
 2358                    cx,
 2359                )
 2360                .shared(),
 2361            );
 2362            code_action_providers.push(Rc::new(project) as Rc<_>);
 2363        }
 2364
 2365        let mut editor = Self {
 2366            focus_handle,
 2367            show_cursor_when_unfocused: false,
 2368            last_focused_descendant: None,
 2369            buffer: multi_buffer.clone(),
 2370            display_map: display_map.clone(),
 2371            placeholder_display_map: None,
 2372            selections,
 2373            scroll_manager: ScrollManager::new(cx),
 2374            columnar_selection_state: None,
 2375            add_selections_state: None,
 2376            select_next_state: None,
 2377            select_prev_state: None,
 2378            selection_history: SelectionHistory::default(),
 2379            defer_selection_effects: false,
 2380            deferred_selection_effects_state: None,
 2381            autoclose_regions: Vec::new(),
 2382            snippet_stack: InvalidationStack::default(),
 2383            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2384            ime_transaction: None,
 2385            active_diagnostics: ActiveDiagnostic::None,
 2386            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2387            inline_diagnostics_update: Task::ready(()),
 2388            inline_diagnostics: Vec::new(),
 2389            soft_wrap_mode_override,
 2390            diagnostics_max_severity,
 2391            hard_wrap: None,
 2392            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2393            semantics_provider: project
 2394                .as_ref()
 2395                .map(|project| Rc::new(project.downgrade()) as _),
 2396            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2397            project,
 2398            blink_manager: blink_manager.clone(),
 2399            show_local_selections: true,
 2400            show_scrollbars: ScrollbarAxes {
 2401                horizontal: full_mode,
 2402                vertical: full_mode,
 2403            },
 2404            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2405            offset_content: !matches!(mode, EditorMode::SingleLine),
 2406            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2407            show_gutter: full_mode,
 2408            show_line_numbers: (!full_mode).then_some(false),
 2409            use_relative_line_numbers: None,
 2410            disable_expand_excerpt_buttons: !full_mode,
 2411            delegate_expand_excerpts: false,
 2412            delegate_stage_and_restore: false,
 2413            delegate_open_excerpts: false,
 2414            enable_lsp_data: true,
 2415            enable_runnables: true,
 2416            show_git_diff_gutter: None,
 2417            show_code_actions: None,
 2418            show_runnables: None,
 2419            show_breakpoints: None,
 2420            show_diff_review_button: false,
 2421            show_wrap_guides: None,
 2422            show_indent_guides,
 2423            buffers_with_disabled_indent_guides: HashSet::default(),
 2424            highlight_order: 0,
 2425            highlighted_rows: HashMap::default(),
 2426            background_highlights: HashMap::default(),
 2427            gutter_highlights: HashMap::default(),
 2428            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2429            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2430            nav_history: None,
 2431            context_menu: RefCell::new(None),
 2432            context_menu_options: None,
 2433            mouse_context_menu: None,
 2434            completion_tasks: Vec::new(),
 2435            inline_blame_popover: None,
 2436            inline_blame_popover_show_task: None,
 2437            signature_help_state: SignatureHelpState::default(),
 2438            auto_signature_help: None,
 2439            find_all_references_task_sources: Vec::new(),
 2440            next_completion_id: 0,
 2441            next_inlay_id: 0,
 2442            code_action_providers,
 2443            available_code_actions: None,
 2444            code_actions_task: None,
 2445            quick_selection_highlight_task: None,
 2446            debounced_selection_highlight_task: None,
 2447            debounced_selection_highlight_complete: false,
 2448            document_highlights_task: None,
 2449            linked_editing_range_task: None,
 2450            pending_rename: None,
 2451            searchable: !is_minimap,
 2452            cursor_shape: EditorSettings::get_global(cx)
 2453                .cursor_shape
 2454                .unwrap_or_default(),
 2455            cursor_offset_on_selection: false,
 2456            current_line_highlight: None,
 2457            autoindent_mode: Some(AutoindentMode::EachLine),
 2458            collapse_matches: false,
 2459            workspace: None,
 2460            input_enabled: !is_minimap,
 2461            expects_character_input: !is_minimap,
 2462            use_modal_editing: full_mode,
 2463            read_only: is_minimap,
 2464            use_autoclose: true,
 2465            use_auto_surround: true,
 2466            auto_replace_emoji_shortcode: false,
 2467            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2468            leader_id: None,
 2469            remote_id: None,
 2470            hover_state: HoverState::default(),
 2471            pending_mouse_down: None,
 2472            prev_pressure_stage: None,
 2473            hovered_link_state: None,
 2474            edit_prediction_provider: None,
 2475            active_edit_prediction: None,
 2476            stale_edit_prediction_in_menu: None,
 2477            edit_prediction_preview: EditPredictionPreview::Inactive {
 2478                released_too_fast: false,
 2479            },
 2480            inline_diagnostics_enabled: full_mode,
 2481            diagnostics_enabled: full_mode,
 2482            word_completions_enabled: full_mode,
 2483            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2484            gutter_hovered: false,
 2485            pixel_position_of_newest_cursor: None,
 2486            last_bounds: None,
 2487            last_position_map: None,
 2488            expect_bounds_change: None,
 2489            gutter_dimensions: GutterDimensions::default(),
 2490            style: None,
 2491            show_cursor_names: false,
 2492            hovered_cursors: HashMap::default(),
 2493            next_editor_action_id: EditorActionId::default(),
 2494            editor_actions: Rc::default(),
 2495            edit_predictions_hidden_for_vim_mode: false,
 2496            show_edit_predictions_override: None,
 2497            show_completions_on_input_override: None,
 2498            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2499            edit_prediction_settings: EditPredictionSettings::Disabled,
 2500            in_leading_whitespace: false,
 2501            custom_context_menu: None,
 2502            show_git_blame_gutter: false,
 2503            show_git_blame_inline: false,
 2504            show_selection_menu: None,
 2505            show_git_blame_inline_delay_task: None,
 2506            git_blame_inline_enabled: full_mode
 2507                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2508            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2509            buffer_serialization: is_minimap.not().then(|| {
 2510                BufferSerialization::new(
 2511                    ProjectSettings::get_global(cx)
 2512                        .session
 2513                        .restore_unsaved_buffers,
 2514                )
 2515            }),
 2516            blame: None,
 2517            blame_subscription: None,
 2518
 2519            breakpoint_store,
 2520            gutter_breakpoint_indicator: (None, None),
 2521            gutter_diff_review_indicator: (None, None),
 2522            diff_review_drag_state: None,
 2523            diff_review_overlays: Vec::new(),
 2524            stored_review_comments: Vec::new(),
 2525            next_review_comment_id: 0,
 2526            hovered_diff_hunk_row: None,
 2527            _subscriptions: (!is_minimap)
 2528                .then(|| {
 2529                    vec![
 2530                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2531                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2532                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2533                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2534                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2535                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2536                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2537                        cx.observe_window_activation(window, |editor, window, cx| {
 2538                            let active = window.is_window_active();
 2539                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2540                                if active {
 2541                                    blink_manager.enable(cx);
 2542                                } else {
 2543                                    blink_manager.disable(cx);
 2544                                }
 2545                            });
 2546                            if active {
 2547                                editor.show_mouse_cursor(cx);
 2548                            }
 2549                        }),
 2550                    ]
 2551                })
 2552                .unwrap_or_default(),
 2553            runnables: RunnableData::new(),
 2554            pull_diagnostics_task: Task::ready(()),
 2555            colors: None,
 2556            refresh_colors_task: Task::ready(()),
 2557            use_document_folding_ranges: false,
 2558            refresh_folding_ranges_task: Task::ready(()),
 2559            inlay_hints: None,
 2560            next_color_inlay_id: 0,
 2561            post_scroll_update: Task::ready(()),
 2562            linked_edit_ranges: Default::default(),
 2563            in_project_search: false,
 2564            previous_search_ranges: None,
 2565            breadcrumb_header: None,
 2566            focused_block: None,
 2567            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2568            addons: HashMap::default(),
 2569            registered_buffers: HashMap::default(),
 2570            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2571            selection_mark_mode: false,
 2572            toggle_fold_multiple_buffers: Task::ready(()),
 2573            serialize_selections: Task::ready(()),
 2574            serialize_folds: Task::ready(()),
 2575            text_style_refinement: None,
 2576            load_diff_task: load_uncommitted_diff,
 2577            temporary_diff_override: false,
 2578            mouse_cursor_hidden: false,
 2579            minimap: None,
 2580            hide_mouse_mode: EditorSettings::get_global(cx)
 2581                .hide_mouse
 2582                .unwrap_or_default(),
 2583            change_list: ChangeList::new(),
 2584            mode,
 2585            selection_drag_state: SelectionDragState::None,
 2586            folding_newlines: Task::ready(()),
 2587            lookup_key: None,
 2588            select_next_is_case_sensitive: None,
 2589            on_local_selections_changed: None,
 2590            suppress_selection_callback: false,
 2591            applicable_language_settings: HashMap::default(),
 2592            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2593            accent_data: None,
 2594            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2595            number_deleted_lines: false,
 2596            refresh_matching_bracket_highlights_task: Task::ready(()),
 2597            refresh_document_symbols_task: Task::ready(()).shared(),
 2598            lsp_document_symbols: HashMap::default(),
 2599            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2600            outline_symbols_at_cursor: None,
 2601            sticky_headers_task: Task::ready(()),
 2602            sticky_headers: None,
 2603            colorize_brackets_task: Task::ready(()),
 2604        };
 2605
 2606        if is_minimap {
 2607            return editor;
 2608        }
 2609
 2610        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2611        editor.accent_data = editor.fetch_accent_data(cx);
 2612
 2613        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2614            editor
 2615                ._subscriptions
 2616                .push(cx.observe(breakpoints, |_, _, cx| {
 2617                    cx.notify();
 2618                }));
 2619        }
 2620        editor._subscriptions.extend(project_subscriptions);
 2621
 2622        editor._subscriptions.push(cx.subscribe_in(
 2623            &cx.entity(),
 2624            window,
 2625            |editor, _, e: &EditorEvent, window, cx| match e {
 2626                EditorEvent::ScrollPositionChanged { local, .. } => {
 2627                    if *local {
 2628                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2629                        editor.inline_blame_popover.take();
 2630                        let snapshot = editor.snapshot(window, cx);
 2631                        let new_anchor = editor
 2632                            .scroll_manager
 2633                            .native_anchor(&snapshot.display_snapshot, cx);
 2634                        editor.update_restoration_data(cx, move |data| {
 2635                            data.scroll_position = (
 2636                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2637                                new_anchor.offset,
 2638                            );
 2639                        });
 2640
 2641                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2642                            cx.background_executor()
 2643                                .timer(Duration::from_millis(50))
 2644                                .await;
 2645                            editor
 2646                                .update_in(cx, |editor, window, cx| {
 2647                                    editor.update_data_on_scroll(window, cx)
 2648                                })
 2649                                .ok();
 2650                        });
 2651                    }
 2652                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2653                }
 2654                EditorEvent::Edited { .. } => {
 2655                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2656                        .map(|vim_mode| vim_mode.0)
 2657                        .unwrap_or(false);
 2658                    if !vim_mode {
 2659                        let display_map = editor.display_snapshot(cx);
 2660                        let selections = editor.selections.all_adjusted_display(&display_map);
 2661                        let pop_state = editor
 2662                            .change_list
 2663                            .last()
 2664                            .map(|previous| {
 2665                                previous.len() == selections.len()
 2666                                    && previous.iter().enumerate().all(|(ix, p)| {
 2667                                        p.to_display_point(&display_map).row()
 2668                                            == selections[ix].head().row()
 2669                                    })
 2670                            })
 2671                            .unwrap_or(false);
 2672                        let new_positions = selections
 2673                            .into_iter()
 2674                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2675                            .collect();
 2676                        editor
 2677                            .change_list
 2678                            .push_to_change_list(pop_state, new_positions);
 2679                    }
 2680                }
 2681                _ => (),
 2682            },
 2683        ));
 2684
 2685        if let Some(dap_store) = editor
 2686            .project
 2687            .as_ref()
 2688            .map(|project| project.read(cx).dap_store())
 2689        {
 2690            let weak_editor = cx.weak_entity();
 2691
 2692            editor
 2693                ._subscriptions
 2694                .push(
 2695                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2696                        let session_entity = cx.entity();
 2697                        weak_editor
 2698                            .update(cx, |editor, cx| {
 2699                                editor._subscriptions.push(
 2700                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2701                                );
 2702                            })
 2703                            .ok();
 2704                    }),
 2705                );
 2706
 2707            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2708                editor
 2709                    ._subscriptions
 2710                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2711            }
 2712        }
 2713
 2714        // skip adding the initial selection to selection history
 2715        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2716        editor.end_selection(window, cx);
 2717        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2718
 2719        editor.scroll_manager.show_scrollbars(window, cx);
 2720        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2721
 2722        if full_mode {
 2723            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2724            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2725
 2726            if editor.git_blame_inline_enabled {
 2727                editor.start_git_blame_inline(false, window, cx);
 2728            }
 2729
 2730            editor.go_to_active_debug_line(window, cx);
 2731
 2732            editor.minimap =
 2733                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2734            editor.colors = Some(LspColorData::new(cx));
 2735            editor.use_document_folding_ranges = true;
 2736            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2737
 2738            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2739                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2740            }
 2741            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2742        }
 2743
 2744        editor
 2745    }
 2746
 2747    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2748        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2749    }
 2750
 2751    pub fn deploy_mouse_context_menu(
 2752        &mut self,
 2753        position: gpui::Point<Pixels>,
 2754        context_menu: Entity<ContextMenu>,
 2755        window: &mut Window,
 2756        cx: &mut Context<Self>,
 2757    ) {
 2758        self.mouse_context_menu = Some(MouseContextMenu::new(
 2759            self,
 2760            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2761            context_menu,
 2762            window,
 2763            cx,
 2764        ));
 2765    }
 2766
 2767    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2768        self.mouse_context_menu
 2769            .as_ref()
 2770            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2771    }
 2772
 2773    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2774        if self
 2775            .selections
 2776            .pending_anchor()
 2777            .is_some_and(|pending_selection| {
 2778                let snapshot = self.buffer().read(cx).snapshot(cx);
 2779                pending_selection.range().includes(range, &snapshot)
 2780            })
 2781        {
 2782            return true;
 2783        }
 2784
 2785        self.selections
 2786            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2787            .into_iter()
 2788            .any(|selection| {
 2789                // This is needed to cover a corner case, if we just check for an existing
 2790                // selection in the fold range, having a cursor at the start of the fold
 2791                // marks it as selected. Non-empty selections don't cause this.
 2792                let length = selection.end - selection.start;
 2793                length > 0
 2794            })
 2795    }
 2796
 2797    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2798        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2799    }
 2800
 2801    fn key_context_internal(
 2802        &self,
 2803        has_active_edit_prediction: bool,
 2804        window: &mut Window,
 2805        cx: &mut App,
 2806    ) -> KeyContext {
 2807        let mut key_context = KeyContext::new_with_defaults();
 2808        key_context.add("Editor");
 2809        let mode = match self.mode {
 2810            EditorMode::SingleLine => "single_line",
 2811            EditorMode::AutoHeight { .. } => "auto_height",
 2812            EditorMode::Minimap { .. } => "minimap",
 2813            EditorMode::Full { .. } => "full",
 2814        };
 2815
 2816        if EditorSettings::jupyter_enabled(cx) {
 2817            key_context.add("jupyter");
 2818        }
 2819
 2820        key_context.set("mode", mode);
 2821        if self.pending_rename.is_some() {
 2822            key_context.add("renaming");
 2823        }
 2824
 2825        if let Some(snippet_stack) = self.snippet_stack.last() {
 2826            key_context.add("in_snippet");
 2827
 2828            if snippet_stack.active_index > 0 {
 2829                key_context.add("has_previous_tabstop");
 2830            }
 2831
 2832            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2833                key_context.add("has_next_tabstop");
 2834            }
 2835        }
 2836
 2837        match self.context_menu.borrow().as_ref() {
 2838            Some(CodeContextMenu::Completions(menu)) => {
 2839                if menu.visible() {
 2840                    key_context.add("menu");
 2841                    key_context.add("showing_completions");
 2842                }
 2843            }
 2844            Some(CodeContextMenu::CodeActions(menu)) => {
 2845                if menu.visible() {
 2846                    key_context.add("menu");
 2847                    key_context.add("showing_code_actions")
 2848                }
 2849            }
 2850            None => {}
 2851        }
 2852
 2853        if self.signature_help_state.has_multiple_signatures() {
 2854            key_context.add("showing_signature_help");
 2855        }
 2856
 2857        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2858        if !self.focus_handle(cx).contains_focused(window, cx)
 2859            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2860        {
 2861            for addon in self.addons.values() {
 2862                addon.extend_key_context(&mut key_context, cx)
 2863            }
 2864        }
 2865
 2866        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2867            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2868                Some(
 2869                    file.full_path(cx)
 2870                        .extension()?
 2871                        .to_string_lossy()
 2872                        .to_lowercase(),
 2873                )
 2874            }) {
 2875                key_context.set("extension", extension);
 2876            }
 2877        } else {
 2878            key_context.add("multibuffer");
 2879        }
 2880
 2881        if has_active_edit_prediction {
 2882            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2883            key_context.add("copilot_suggestion");
 2884        }
 2885
 2886        if self.in_leading_whitespace {
 2887            key_context.add("in_leading_whitespace");
 2888        }
 2889        if self.edit_prediction_requires_modifier() {
 2890            key_context.set("edit_prediction_mode", "subtle")
 2891        } else {
 2892            key_context.set("edit_prediction_mode", "eager");
 2893        }
 2894
 2895        if self.selection_mark_mode {
 2896            key_context.add("selection_mode");
 2897        }
 2898
 2899        let disjoint = self.selections.disjoint_anchors();
 2900        if matches!(
 2901            &self.mode,
 2902            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2903        ) && let [selection] = disjoint
 2904            && selection.start == selection.end
 2905        {
 2906            let snapshot = self.snapshot(window, cx);
 2907            let snapshot = snapshot.buffer_snapshot();
 2908            let caret_offset = selection.end.to_offset(snapshot);
 2909
 2910            if caret_offset == MultiBufferOffset(0) {
 2911                key_context.add("start_of_input");
 2912            }
 2913
 2914            if caret_offset == snapshot.len() {
 2915                key_context.add("end_of_input");
 2916            }
 2917        }
 2918
 2919        if self.has_any_expanded_diff_hunks(cx) {
 2920            key_context.add("diffs_expanded");
 2921        }
 2922
 2923        key_context
 2924    }
 2925
 2926    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2927        self.last_bounds.as_ref()
 2928    }
 2929
 2930    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2931        if self.mouse_cursor_hidden {
 2932            self.mouse_cursor_hidden = false;
 2933            cx.notify();
 2934        }
 2935    }
 2936
 2937    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2938        let hide_mouse_cursor = match origin {
 2939            HideMouseCursorOrigin::TypingAction => {
 2940                matches!(
 2941                    self.hide_mouse_mode,
 2942                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2943                )
 2944            }
 2945            HideMouseCursorOrigin::MovementAction => {
 2946                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2947            }
 2948        };
 2949        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2950            self.mouse_cursor_hidden = hide_mouse_cursor;
 2951            cx.notify();
 2952        }
 2953    }
 2954
 2955    fn accept_edit_prediction_keystroke(
 2956        &self,
 2957        granularity: EditPredictionGranularity,
 2958        window: &mut Window,
 2959        cx: &mut App,
 2960    ) -> Option<gpui::KeybindingKeystroke> {
 2961        let key_context = self.key_context_internal(true, window, cx);
 2962
 2963        let bindings =
 2964            match granularity {
 2965                EditPredictionGranularity::Word => window
 2966                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2967                EditPredictionGranularity::Line => window
 2968                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2969                EditPredictionGranularity::Full => {
 2970                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2971                }
 2972            };
 2973
 2974        bindings
 2975            .into_iter()
 2976            .rev()
 2977            .find_map(|binding| match binding.keystrokes() {
 2978                [keystroke, ..] => Some(keystroke.clone()),
 2979                _ => None,
 2980            })
 2981    }
 2982
 2983    fn preview_edit_prediction_keystroke(
 2984        &self,
 2985        window: &mut Window,
 2986        cx: &mut App,
 2987    ) -> Option<gpui::KeybindingKeystroke> {
 2988        let key_context = self.key_context_internal(true, window, cx);
 2989        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 2990        bindings
 2991            .into_iter()
 2992            .rev()
 2993            .find_map(|binding| match binding.keystrokes() {
 2994                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 2995                _ => None,
 2996            })
 2997    }
 2998
 2999    fn edit_prediction_preview_modifiers_held(
 3000        &self,
 3001        modifiers: &Modifiers,
 3002        window: &mut Window,
 3003        cx: &mut App,
 3004    ) -> bool {
 3005        let key_context = self.key_context_internal(true, window, cx);
 3006        let actions: [&dyn Action; 3] = [
 3007            &AcceptEditPrediction,
 3008            &AcceptNextWordEditPrediction,
 3009            &AcceptNextLineEditPrediction,
 3010        ];
 3011
 3012        actions.into_iter().any(|action| {
 3013            window
 3014                .bindings_for_action_in_context(action, key_context.clone())
 3015                .into_iter()
 3016                .rev()
 3017                .any(|binding| {
 3018                    binding.keystrokes().first().is_some_and(|keystroke| {
 3019                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3020                    })
 3021                })
 3022        })
 3023    }
 3024
 3025    fn edit_prediction_cursor_popover_prefers_preview(
 3026        &self,
 3027        completion: &EditPredictionState,
 3028    ) -> bool {
 3029        match &completion.completion {
 3030            EditPrediction::Edit {
 3031                edits, snapshot, ..
 3032            } => {
 3033                let mut start_row: Option<u32> = None;
 3034                let mut end_row: Option<u32> = None;
 3035
 3036                for (range, text) in edits {
 3037                    let edit_start_row = range.start.text_anchor.to_point(snapshot).row;
 3038                    let old_end_row = range.end.text_anchor.to_point(snapshot).row;
 3039                    let inserted_newline_count = text
 3040                        .as_ref()
 3041                        .chars()
 3042                        .filter(|character| *character == '\n')
 3043                        .count() as u32;
 3044                    let deleted_newline_count = old_end_row - edit_start_row;
 3045                    let preview_end_row = edit_start_row + inserted_newline_count;
 3046
 3047                    start_row =
 3048                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3049                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3050
 3051                    if deleted_newline_count > 1 {
 3052                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3053                    }
 3054                }
 3055
 3056                start_row
 3057                    .zip(end_row)
 3058                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3059            }
 3060            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3061        }
 3062    }
 3063
 3064    fn edit_prediction_keybind_display(
 3065        &self,
 3066        surface: EditPredictionKeybindSurface,
 3067        window: &mut Window,
 3068        cx: &mut App,
 3069    ) -> EditPredictionKeybindDisplay {
 3070        let accept_keystroke =
 3071            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3072        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3073
 3074        let action = match surface {
 3075            EditPredictionKeybindSurface::Inline
 3076            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3077                if self.edit_prediction_requires_modifier() {
 3078                    EditPredictionKeybindAction::Preview
 3079                } else {
 3080                    EditPredictionKeybindAction::Accept
 3081                }
 3082            }
 3083            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3084                .active_edit_prediction
 3085                .as_ref()
 3086                .filter(|completion| {
 3087                    self.edit_prediction_cursor_popover_prefers_preview(completion)
 3088                })
 3089                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3090                    EditPredictionKeybindAction::Preview
 3091                }),
 3092        };
 3093        #[cfg(test)]
 3094        let preview_copy = preview_keystroke.clone();
 3095        #[cfg(test)]
 3096        let accept_copy = accept_keystroke.clone();
 3097
 3098        let displayed_keystroke = match surface {
 3099            EditPredictionKeybindSurface::Inline => match action {
 3100                EditPredictionKeybindAction::Accept => accept_keystroke,
 3101                EditPredictionKeybindAction::Preview => preview_keystroke,
 3102            },
 3103            EditPredictionKeybindSurface::CursorPopoverCompact
 3104            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3105                EditPredictionKeybindAction::Accept => accept_keystroke,
 3106                EditPredictionKeybindAction::Preview => {
 3107                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3108                }
 3109            },
 3110        };
 3111
 3112        let missing_accept_keystroke = displayed_keystroke.is_none();
 3113
 3114        EditPredictionKeybindDisplay {
 3115            #[cfg(test)]
 3116            accept_keystroke: accept_copy,
 3117            #[cfg(test)]
 3118            preview_keystroke: preview_copy,
 3119            displayed_keystroke,
 3120            action,
 3121            missing_accept_keystroke,
 3122            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3123                && self.edit_prediction_preview.released_too_fast(),
 3124        }
 3125    }
 3126
 3127    pub fn new_file(
 3128        workspace: &mut Workspace,
 3129        _: &workspace::NewFile,
 3130        window: &mut Window,
 3131        cx: &mut Context<Workspace>,
 3132    ) {
 3133        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3134            "Failed to create buffer",
 3135            window,
 3136            cx,
 3137            |e, _, _| match e.error_code() {
 3138                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3139                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3140                e.error_tag("required").unwrap_or("the latest version")
 3141            )),
 3142                _ => None,
 3143            },
 3144        );
 3145    }
 3146
 3147    pub fn new_in_workspace(
 3148        workspace: &mut Workspace,
 3149        window: &mut Window,
 3150        cx: &mut Context<Workspace>,
 3151    ) -> Task<Result<Entity<Editor>>> {
 3152        let project = workspace.project().clone();
 3153        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3154
 3155        cx.spawn_in(window, async move |workspace, cx| {
 3156            let buffer = create.await?;
 3157            workspace.update_in(cx, |workspace, window, cx| {
 3158                let editor =
 3159                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3160                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3161                editor
 3162            })
 3163        })
 3164    }
 3165
 3166    fn new_file_vertical(
 3167        workspace: &mut Workspace,
 3168        _: &workspace::NewFileSplitVertical,
 3169        window: &mut Window,
 3170        cx: &mut Context<Workspace>,
 3171    ) {
 3172        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3173    }
 3174
 3175    fn new_file_horizontal(
 3176        workspace: &mut Workspace,
 3177        _: &workspace::NewFileSplitHorizontal,
 3178        window: &mut Window,
 3179        cx: &mut Context<Workspace>,
 3180    ) {
 3181        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3182    }
 3183
 3184    fn new_file_split(
 3185        workspace: &mut Workspace,
 3186        action: &workspace::NewFileSplit,
 3187        window: &mut Window,
 3188        cx: &mut Context<Workspace>,
 3189    ) {
 3190        Self::new_file_in_direction(workspace, action.0, window, cx)
 3191    }
 3192
 3193    fn new_file_in_direction(
 3194        workspace: &mut Workspace,
 3195        direction: SplitDirection,
 3196        window: &mut Window,
 3197        cx: &mut Context<Workspace>,
 3198    ) {
 3199        let project = workspace.project().clone();
 3200        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3201
 3202        cx.spawn_in(window, async move |workspace, cx| {
 3203            let buffer = create.await?;
 3204            workspace.update_in(cx, move |workspace, window, cx| {
 3205                workspace.split_item(
 3206                    direction,
 3207                    Box::new(
 3208                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3209                    ),
 3210                    window,
 3211                    cx,
 3212                )
 3213            })?;
 3214            anyhow::Ok(())
 3215        })
 3216        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3217            match e.error_code() {
 3218                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3219                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3220                e.error_tag("required").unwrap_or("the latest version")
 3221            )),
 3222                _ => None,
 3223            }
 3224        });
 3225    }
 3226
 3227    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3228        self.leader_id
 3229    }
 3230
 3231    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3232        &self.buffer
 3233    }
 3234
 3235    pub fn project(&self) -> Option<&Entity<Project>> {
 3236        self.project.as_ref()
 3237    }
 3238
 3239    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3240        self.workspace.as_ref()?.0.upgrade()
 3241    }
 3242
 3243    /// Detaches a task and shows an error notification in the workspace if available,
 3244    /// otherwise just logs the error.
 3245    pub fn detach_and_notify_err<R, E>(
 3246        &self,
 3247        task: Task<Result<R, E>>,
 3248        window: &mut Window,
 3249        cx: &mut App,
 3250    ) where
 3251        E: std::fmt::Debug + std::fmt::Display + 'static,
 3252        R: 'static,
 3253    {
 3254        if let Some(workspace) = self.workspace() {
 3255            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3256        } else {
 3257            task.detach_and_log_err(cx);
 3258        }
 3259    }
 3260
 3261    /// Returns the workspace serialization ID if this editor should be serialized.
 3262    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3263        self.workspace
 3264            .as_ref()
 3265            .filter(|_| self.should_serialize_buffer())
 3266            .and_then(|workspace| workspace.1)
 3267    }
 3268
 3269    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3270        self.buffer().read(cx).title(cx)
 3271    }
 3272
 3273    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3274        let git_blame_gutter_max_author_length = self
 3275            .render_git_blame_gutter(cx)
 3276            .then(|| {
 3277                if let Some(blame) = self.blame.as_ref() {
 3278                    let max_author_length =
 3279                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3280                    Some(max_author_length)
 3281                } else {
 3282                    None
 3283                }
 3284            })
 3285            .flatten();
 3286
 3287        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3288
 3289        EditorSnapshot {
 3290            mode: self.mode.clone(),
 3291            show_gutter: self.show_gutter,
 3292            offset_content: self.offset_content,
 3293            show_line_numbers: self.show_line_numbers,
 3294            number_deleted_lines: self.number_deleted_lines,
 3295            show_git_diff_gutter: self.show_git_diff_gutter,
 3296            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3297            show_code_actions: self.show_code_actions,
 3298            show_runnables: self.show_runnables,
 3299            show_breakpoints: self.show_breakpoints,
 3300            git_blame_gutter_max_author_length,
 3301            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3302            display_snapshot,
 3303            placeholder_display_snapshot: self
 3304                .placeholder_display_map
 3305                .as_ref()
 3306                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3307            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3308            is_focused: self.focus_handle.is_focused(window),
 3309            current_line_highlight: self
 3310                .current_line_highlight
 3311                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3312            gutter_hovered: self.gutter_hovered,
 3313        }
 3314    }
 3315
 3316    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3317        self.buffer.read(cx).language_at(point, cx)
 3318    }
 3319
 3320    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3321        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3322    }
 3323
 3324    pub fn active_excerpt(
 3325        &self,
 3326        cx: &App,
 3327    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3328        self.buffer
 3329            .read(cx)
 3330            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3331    }
 3332
 3333    pub fn mode(&self) -> &EditorMode {
 3334        &self.mode
 3335    }
 3336
 3337    pub fn set_mode(&mut self, mode: EditorMode) {
 3338        self.mode = mode;
 3339    }
 3340
 3341    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3342        self.collaboration_hub.as_deref()
 3343    }
 3344
 3345    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3346        self.collaboration_hub = Some(hub);
 3347    }
 3348
 3349    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3350        self.in_project_search = in_project_search;
 3351    }
 3352
 3353    pub fn set_custom_context_menu(
 3354        &mut self,
 3355        f: impl 'static
 3356        + Fn(
 3357            &mut Self,
 3358            DisplayPoint,
 3359            &mut Window,
 3360            &mut Context<Self>,
 3361        ) -> Option<Entity<ui::ContextMenu>>,
 3362    ) {
 3363        self.custom_context_menu = Some(Box::new(f))
 3364    }
 3365
 3366    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3367        self.completion_provider = provider;
 3368    }
 3369
 3370    #[cfg(any(test, feature = "test-support"))]
 3371    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3372        self.completion_provider.clone()
 3373    }
 3374
 3375    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3376        self.semantics_provider.clone()
 3377    }
 3378
 3379    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3380        self.semantics_provider = provider;
 3381    }
 3382
 3383    pub fn set_edit_prediction_provider<T>(
 3384        &mut self,
 3385        provider: Option<Entity<T>>,
 3386        window: &mut Window,
 3387        cx: &mut Context<Self>,
 3388    ) where
 3389        T: EditPredictionDelegate,
 3390    {
 3391        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3392            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3393                if this.focus_handle.is_focused(window) {
 3394                    this.update_visible_edit_prediction(window, cx);
 3395                }
 3396            }),
 3397            provider: Arc::new(provider),
 3398        });
 3399        self.update_edit_prediction_settings(cx);
 3400        self.refresh_edit_prediction(false, false, window, cx);
 3401    }
 3402
 3403    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3404        self.placeholder_display_map
 3405            .as_ref()
 3406            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3407    }
 3408
 3409    pub fn set_placeholder_text(
 3410        &mut self,
 3411        placeholder_text: &str,
 3412        window: &mut Window,
 3413        cx: &mut Context<Self>,
 3414    ) {
 3415        let multibuffer = cx
 3416            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3417
 3418        let style = window.text_style();
 3419
 3420        self.placeholder_display_map = Some(cx.new(|cx| {
 3421            DisplayMap::new(
 3422                multibuffer,
 3423                style.font(),
 3424                style.font_size.to_pixels(window.rem_size()),
 3425                None,
 3426                FILE_HEADER_HEIGHT,
 3427                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3428                Default::default(),
 3429                DiagnosticSeverity::Off,
 3430                cx,
 3431            )
 3432        }));
 3433        cx.notify();
 3434    }
 3435
 3436    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3437        self.cursor_shape = cursor_shape;
 3438
 3439        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3440        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3441
 3442        cx.notify();
 3443    }
 3444
 3445    pub fn cursor_shape(&self) -> CursorShape {
 3446        self.cursor_shape
 3447    }
 3448
 3449    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3450        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3451    }
 3452
 3453    pub fn set_current_line_highlight(
 3454        &mut self,
 3455        current_line_highlight: Option<CurrentLineHighlight>,
 3456    ) {
 3457        self.current_line_highlight = current_line_highlight;
 3458    }
 3459
 3460    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3461        self.collapse_matches = collapse_matches;
 3462    }
 3463
 3464    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3465        if self.collapse_matches {
 3466            return range.start..range.start;
 3467        }
 3468        range.clone()
 3469    }
 3470
 3471    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3472        self.display_map.read(cx).clip_at_line_ends
 3473    }
 3474
 3475    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3476        if self.display_map.read(cx).clip_at_line_ends != clip {
 3477            self.display_map
 3478                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3479        }
 3480    }
 3481
 3482    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3483        self.input_enabled = input_enabled;
 3484    }
 3485
 3486    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3487        self.expects_character_input = expects_character_input;
 3488    }
 3489
 3490    pub fn set_edit_predictions_hidden_for_vim_mode(
 3491        &mut self,
 3492        hidden: bool,
 3493        window: &mut Window,
 3494        cx: &mut Context<Self>,
 3495    ) {
 3496        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3497            self.edit_predictions_hidden_for_vim_mode = hidden;
 3498            if hidden {
 3499                self.update_visible_edit_prediction(window, cx);
 3500            } else {
 3501                self.refresh_edit_prediction(true, false, window, cx);
 3502            }
 3503        }
 3504    }
 3505
 3506    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3507        self.menu_edit_predictions_policy = value;
 3508    }
 3509
 3510    pub fn set_autoindent(&mut self, autoindent: bool) {
 3511        if autoindent {
 3512            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3513        } else {
 3514            self.autoindent_mode = None;
 3515        }
 3516    }
 3517
 3518    pub fn capability(&self, cx: &App) -> Capability {
 3519        if self.read_only {
 3520            Capability::ReadOnly
 3521        } else {
 3522            self.buffer.read(cx).capability()
 3523        }
 3524    }
 3525
 3526    pub fn read_only(&self, cx: &App) -> bool {
 3527        self.read_only || self.buffer.read(cx).read_only()
 3528    }
 3529
 3530    pub fn set_read_only(&mut self, read_only: bool) {
 3531        self.read_only = read_only;
 3532    }
 3533
 3534    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3535        self.use_autoclose = autoclose;
 3536    }
 3537
 3538    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3539        self.use_auto_surround = auto_surround;
 3540    }
 3541
 3542    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3543        self.auto_replace_emoji_shortcode = auto_replace;
 3544    }
 3545
 3546    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3547        self.buffer_serialization = should_serialize.then(|| {
 3548            BufferSerialization::new(
 3549                ProjectSettings::get_global(cx)
 3550                    .session
 3551                    .restore_unsaved_buffers,
 3552            )
 3553        })
 3554    }
 3555
 3556    fn should_serialize_buffer(&self) -> bool {
 3557        self.buffer_serialization.is_some()
 3558    }
 3559
 3560    pub fn toggle_edit_predictions(
 3561        &mut self,
 3562        _: &ToggleEditPrediction,
 3563        window: &mut Window,
 3564        cx: &mut Context<Self>,
 3565    ) {
 3566        if self.show_edit_predictions_override.is_some() {
 3567            self.set_show_edit_predictions(None, window, cx);
 3568        } else {
 3569            let show_edit_predictions = !self.edit_predictions_enabled();
 3570            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3571        }
 3572    }
 3573
 3574    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3575        self.show_completions_on_input_override = show_completions_on_input;
 3576    }
 3577
 3578    pub fn set_show_edit_predictions(
 3579        &mut self,
 3580        show_edit_predictions: Option<bool>,
 3581        window: &mut Window,
 3582        cx: &mut Context<Self>,
 3583    ) {
 3584        self.show_edit_predictions_override = show_edit_predictions;
 3585        self.update_edit_prediction_settings(cx);
 3586
 3587        if let Some(false) = show_edit_predictions {
 3588            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3589        } else {
 3590            self.refresh_edit_prediction(false, true, window, cx);
 3591        }
 3592    }
 3593
 3594    fn edit_predictions_disabled_in_scope(
 3595        &self,
 3596        buffer: &Entity<Buffer>,
 3597        buffer_position: language::Anchor,
 3598        cx: &App,
 3599    ) -> bool {
 3600        let snapshot = buffer.read(cx).snapshot();
 3601        let settings = snapshot.settings_at(buffer_position, cx);
 3602
 3603        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3604            return false;
 3605        };
 3606
 3607        scope.override_name().is_some_and(|scope_name| {
 3608            settings
 3609                .edit_predictions_disabled_in
 3610                .iter()
 3611                .any(|s| s == scope_name)
 3612        })
 3613    }
 3614
 3615    pub fn set_use_modal_editing(&mut self, to: bool) {
 3616        self.use_modal_editing = to;
 3617    }
 3618
 3619    pub fn use_modal_editing(&self) -> bool {
 3620        self.use_modal_editing
 3621    }
 3622
 3623    fn selections_did_change(
 3624        &mut self,
 3625        local: bool,
 3626        old_cursor_position: &Anchor,
 3627        effects: SelectionEffects,
 3628        window: &mut Window,
 3629        cx: &mut Context<Self>,
 3630    ) {
 3631        window.invalidate_character_coordinates();
 3632
 3633        // Copy selections to primary selection buffer
 3634        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3635        if local {
 3636            let selections = self
 3637                .selections
 3638                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3639            let buffer_handle = self.buffer.read(cx).read(cx);
 3640
 3641            let mut text = String::new();
 3642            for (index, selection) in selections.iter().enumerate() {
 3643                let text_for_selection = buffer_handle
 3644                    .text_for_range(selection.start..selection.end)
 3645                    .collect::<String>();
 3646
 3647                text.push_str(&text_for_selection);
 3648                if index != selections.len() - 1 {
 3649                    text.push('\n');
 3650                }
 3651            }
 3652
 3653            if !text.is_empty() {
 3654                cx.write_to_primary(ClipboardItem::new_string(text));
 3655            }
 3656        }
 3657
 3658        let selection_anchors = self.selections.disjoint_anchors_arc();
 3659
 3660        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3661            self.buffer.update(cx, |buffer, cx| {
 3662                buffer.set_active_selections(
 3663                    &selection_anchors,
 3664                    self.selections.line_mode(),
 3665                    self.cursor_shape,
 3666                    cx,
 3667                )
 3668            });
 3669        }
 3670        let display_map = self
 3671            .display_map
 3672            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3673        let buffer = display_map.buffer_snapshot();
 3674        if self.selections.count() == 1 {
 3675            self.add_selections_state = None;
 3676        }
 3677        self.select_next_state = None;
 3678        self.select_prev_state = None;
 3679        self.select_syntax_node_history.try_clear();
 3680        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3681        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3682        self.take_rename(false, window, cx);
 3683
 3684        let newest_selection = self.selections.newest_anchor();
 3685        let new_cursor_position = newest_selection.head();
 3686        let selection_start = newest_selection.start;
 3687
 3688        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3689            self.push_to_nav_history(
 3690                *old_cursor_position,
 3691                Some(new_cursor_position.to_point(buffer)),
 3692                false,
 3693                effects.nav_history == Some(true),
 3694                cx,
 3695            );
 3696        }
 3697
 3698        if local {
 3699            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3700                self.register_buffer(buffer_id, cx);
 3701            }
 3702
 3703            let mut context_menu = self.context_menu.borrow_mut();
 3704            let completion_menu = match context_menu.as_ref() {
 3705                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3706                Some(CodeContextMenu::CodeActions(_)) => {
 3707                    *context_menu = None;
 3708                    None
 3709                }
 3710                None => None,
 3711            };
 3712            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3713            drop(context_menu);
 3714
 3715            if effects.completions
 3716                && let Some(completion_position) = completion_position
 3717            {
 3718                let start_offset = selection_start.to_offset(buffer);
 3719                let position_matches = start_offset == completion_position.to_offset(buffer);
 3720                let continue_showing = if let Some((snap, ..)) =
 3721                    buffer.point_to_buffer_offset(completion_position)
 3722                    && !snap.capability.editable()
 3723                {
 3724                    false
 3725                } else if position_matches {
 3726                    if self.snippet_stack.is_empty() {
 3727                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3728                            == Some(CharKind::Word)
 3729                    } else {
 3730                        // Snippet choices can be shown even when the cursor is in whitespace.
 3731                        // Dismissing the menu with actions like backspace is handled by
 3732                        // invalidation regions.
 3733                        true
 3734                    }
 3735                } else {
 3736                    false
 3737                };
 3738
 3739                if continue_showing {
 3740                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3741                } else {
 3742                    self.hide_context_menu(window, cx);
 3743                }
 3744            }
 3745
 3746            hide_hover(self, cx);
 3747
 3748            if old_cursor_position.to_display_point(&display_map).row()
 3749                != new_cursor_position.to_display_point(&display_map).row()
 3750            {
 3751                self.available_code_actions.take();
 3752            }
 3753            self.refresh_code_actions(window, cx);
 3754            self.refresh_document_highlights(cx);
 3755            refresh_linked_ranges(self, window, cx);
 3756
 3757            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3758            self.refresh_matching_bracket_highlights(&display_map, cx);
 3759            self.refresh_outline_symbols_at_cursor(cx);
 3760            self.update_visible_edit_prediction(window, cx);
 3761            self.inline_blame_popover.take();
 3762            if self.git_blame_inline_enabled {
 3763                self.start_inline_blame_timer(window, cx);
 3764            }
 3765        }
 3766
 3767        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3768
 3769        if local && !self.suppress_selection_callback {
 3770            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3771                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3772                callback(cursor_position, window, cx);
 3773            }
 3774        }
 3775
 3776        cx.emit(EditorEvent::SelectionsChanged { local });
 3777
 3778        let selections = &self.selections.disjoint_anchors_arc();
 3779        if selections.len() == 1 {
 3780            cx.emit(SearchEvent::ActiveMatchChanged)
 3781        }
 3782        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3783            let inmemory_selections = selections
 3784                .iter()
 3785                .map(|s| {
 3786                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3787                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3788                })
 3789                .collect();
 3790            self.update_restoration_data(cx, |data| {
 3791                data.selections = inmemory_selections;
 3792            });
 3793
 3794            if WorkspaceSettings::get(None, cx).restore_on_startup
 3795                != RestoreOnStartupBehavior::EmptyTab
 3796                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3797            {
 3798                let snapshot = self.buffer().read(cx).snapshot(cx);
 3799                let selections = selections.clone();
 3800                let background_executor = cx.background_executor().clone();
 3801                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3802                let db = EditorDb::global(cx);
 3803                self.serialize_selections = cx.background_spawn(async move {
 3804                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3805                    let db_selections = selections
 3806                        .iter()
 3807                        .map(|selection| {
 3808                            (
 3809                                selection.start.to_offset(&snapshot).0,
 3810                                selection.end.to_offset(&snapshot).0,
 3811                            )
 3812                        })
 3813                        .collect();
 3814
 3815                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3816                        .await
 3817                        .with_context(|| {
 3818                            format!(
 3819                                "persisting editor selections for editor {editor_id}, \
 3820                                workspace {workspace_id:?}"
 3821                            )
 3822                        })
 3823                        .log_err();
 3824                });
 3825            }
 3826        }
 3827
 3828        cx.notify();
 3829    }
 3830
 3831    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3832        use text::ToOffset as _;
 3833        use text::ToPoint as _;
 3834
 3835        if self.mode.is_minimap()
 3836            || WorkspaceSettings::get(None, cx).restore_on_startup
 3837                == RestoreOnStartupBehavior::EmptyTab
 3838        {
 3839            return;
 3840        }
 3841
 3842        if !self.buffer().read(cx).is_singleton() {
 3843            return;
 3844        }
 3845
 3846        let display_snapshot = self
 3847            .display_map
 3848            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3849        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3850            return;
 3851        };
 3852        let inmemory_folds = display_snapshot
 3853            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3854            .map(|fold| {
 3855                fold.range.start.text_anchor.to_point(&snapshot)
 3856                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3857            })
 3858            .collect();
 3859        self.update_restoration_data(cx, |data| {
 3860            data.folds = inmemory_folds;
 3861        });
 3862
 3863        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3864            return;
 3865        };
 3866
 3867        // Get file path for path-based fold storage (survives tab close)
 3868        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3869            project::File::from_dyn(buffer.read(cx).file())
 3870                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3871        }) else {
 3872            return;
 3873        };
 3874
 3875        let background_executor = cx.background_executor().clone();
 3876        const FINGERPRINT_LEN: usize = 32;
 3877        let db_folds = display_snapshot
 3878            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3879            .map(|fold| {
 3880                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3881                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3882
 3883                // Extract fingerprints - content at fold boundaries for validation on restore
 3884                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3885                // content that might change independently.
 3886                // start_fp: first min(32, fold_len) bytes of fold content
 3887                // end_fp: last min(32, fold_len) bytes of fold content
 3888                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3889                let fold_len = end - start;
 3890                let start_fp_end = snapshot
 3891                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3892                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3893                let end_fp_start = snapshot
 3894                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3895                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3896
 3897                (start, end, start_fp, end_fp)
 3898            })
 3899            .collect::<Vec<_>>();
 3900        let db = EditorDb::global(cx);
 3901        self.serialize_folds = cx.background_spawn(async move {
 3902            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3903            if db_folds.is_empty() {
 3904                // No folds - delete any persisted folds for this file
 3905                db.delete_file_folds(workspace_id, file_path)
 3906                    .await
 3907                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3908                    .log_err();
 3909            } else {
 3910                db.save_file_folds(workspace_id, file_path, db_folds)
 3911                    .await
 3912                    .with_context(|| {
 3913                        format!("persisting file folds for workspace {workspace_id:?}")
 3914                    })
 3915                    .log_err();
 3916            }
 3917        });
 3918    }
 3919
 3920    pub fn sync_selections(
 3921        &mut self,
 3922        other: Entity<Editor>,
 3923        cx: &mut Context<Self>,
 3924    ) -> gpui::Subscription {
 3925        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3926        if !other_selections.is_empty() {
 3927            self.selections
 3928                .change_with(&self.display_snapshot(cx), |selections| {
 3929                    selections.select_anchors(other_selections);
 3930                });
 3931        }
 3932
 3933        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3934            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3935                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3936                if other_selections.is_empty() {
 3937                    return;
 3938                }
 3939                let snapshot = this.display_snapshot(cx);
 3940                this.selections.change_with(&snapshot, |selections| {
 3941                    selections.select_anchors(other_selections);
 3942                });
 3943            }
 3944        });
 3945
 3946        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3947            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3948                let these_selections = this.selections.disjoint_anchors().to_vec();
 3949                if these_selections.is_empty() {
 3950                    return;
 3951                }
 3952                other.update(cx, |other_editor, cx| {
 3953                    let snapshot = other_editor.display_snapshot(cx);
 3954                    other_editor
 3955                        .selections
 3956                        .change_with(&snapshot, |selections| {
 3957                            selections.select_anchors(these_selections);
 3958                        })
 3959                });
 3960            }
 3961        });
 3962
 3963        Subscription::join(other_subscription, this_subscription)
 3964    }
 3965
 3966    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3967        if self.buffer().read(cx).is_singleton() {
 3968            return;
 3969        }
 3970        let snapshot = self.buffer.read(cx).snapshot(cx);
 3971        let buffer_ids: HashSet<BufferId> = self
 3972            .selections
 3973            .disjoint_anchor_ranges()
 3974            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3975            .collect();
 3976        for buffer_id in buffer_ids {
 3977            self.unfold_buffer(buffer_id, cx);
 3978        }
 3979    }
 3980
 3981    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3982    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3983    /// effects of selection change occur at the end of the transaction.
 3984    pub fn change_selections<R>(
 3985        &mut self,
 3986        effects: SelectionEffects,
 3987        window: &mut Window,
 3988        cx: &mut Context<Self>,
 3989        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3990    ) -> R {
 3991        let snapshot = self.display_snapshot(cx);
 3992        if let Some(state) = &mut self.deferred_selection_effects_state {
 3993            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3994            state.effects.completions = effects.completions;
 3995            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3996            let (changed, result) = self.selections.change_with(&snapshot, change);
 3997            state.changed |= changed;
 3998            return result;
 3999        }
 4000        let mut state = DeferredSelectionEffectsState {
 4001            changed: false,
 4002            effects,
 4003            old_cursor_position: self.selections.newest_anchor().head(),
 4004            history_entry: SelectionHistoryEntry {
 4005                selections: self.selections.disjoint_anchors_arc(),
 4006                select_next_state: self.select_next_state.clone(),
 4007                select_prev_state: self.select_prev_state.clone(),
 4008                add_selections_state: self.add_selections_state.clone(),
 4009            },
 4010        };
 4011        let (changed, result) = self.selections.change_with(&snapshot, change);
 4012        state.changed = state.changed || changed;
 4013        if self.defer_selection_effects {
 4014            self.deferred_selection_effects_state = Some(state);
 4015        } else {
 4016            self.apply_selection_effects(state, window, cx);
 4017        }
 4018        result
 4019    }
 4020
 4021    /// Defers the effects of selection change, so that the effects of multiple calls to
 4022    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4023    /// to selection history and the state of popovers based on selection position aren't
 4024    /// erroneously updated.
 4025    pub fn with_selection_effects_deferred<R>(
 4026        &mut self,
 4027        window: &mut Window,
 4028        cx: &mut Context<Self>,
 4029        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4030    ) -> R {
 4031        let already_deferred = self.defer_selection_effects;
 4032        self.defer_selection_effects = true;
 4033        let result = update(self, window, cx);
 4034        if !already_deferred {
 4035            self.defer_selection_effects = false;
 4036            if let Some(state) = self.deferred_selection_effects_state.take() {
 4037                self.apply_selection_effects(state, window, cx);
 4038            }
 4039        }
 4040        result
 4041    }
 4042
 4043    fn apply_selection_effects(
 4044        &mut self,
 4045        state: DeferredSelectionEffectsState,
 4046        window: &mut Window,
 4047        cx: &mut Context<Self>,
 4048    ) {
 4049        if state.changed {
 4050            self.selection_history.push(state.history_entry);
 4051
 4052            if let Some(autoscroll) = state.effects.scroll {
 4053                self.request_autoscroll(autoscroll, cx);
 4054            }
 4055
 4056            let old_cursor_position = &state.old_cursor_position;
 4057
 4058            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4059
 4060            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4061                self.show_signature_help_auto(window, cx);
 4062            }
 4063        }
 4064    }
 4065
 4066    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4067    where
 4068        I: IntoIterator<Item = (Range<S>, T)>,
 4069        S: ToOffset,
 4070        T: Into<Arc<str>>,
 4071    {
 4072        if self.read_only(cx) {
 4073            return;
 4074        }
 4075
 4076        self.buffer
 4077            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4078    }
 4079
 4080    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4081    where
 4082        I: IntoIterator<Item = (Range<S>, T)>,
 4083        S: ToOffset,
 4084        T: Into<Arc<str>>,
 4085    {
 4086        if self.read_only(cx) {
 4087            return;
 4088        }
 4089
 4090        self.buffer.update(cx, |buffer, cx| {
 4091            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4092        });
 4093    }
 4094
 4095    pub fn edit_with_block_indent<I, S, T>(
 4096        &mut self,
 4097        edits: I,
 4098        original_indent_columns: Vec<Option<u32>>,
 4099        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(
 4111                edits,
 4112                Some(AutoindentMode::Block {
 4113                    original_indent_columns,
 4114                }),
 4115                cx,
 4116            )
 4117        });
 4118    }
 4119
 4120    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4121        self.hide_context_menu(window, cx);
 4122
 4123        match phase {
 4124            SelectPhase::Begin {
 4125                position,
 4126                add,
 4127                click_count,
 4128            } => self.begin_selection(position, add, click_count, window, cx),
 4129            SelectPhase::BeginColumnar {
 4130                position,
 4131                goal_column,
 4132                reset,
 4133                mode,
 4134            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4135            SelectPhase::Extend {
 4136                position,
 4137                click_count,
 4138            } => self.extend_selection(position, click_count, window, cx),
 4139            SelectPhase::Update {
 4140                position,
 4141                goal_column,
 4142                scroll_delta,
 4143            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4144            SelectPhase::End => self.end_selection(window, cx),
 4145        }
 4146    }
 4147
 4148    fn extend_selection(
 4149        &mut self,
 4150        position: DisplayPoint,
 4151        click_count: usize,
 4152        window: &mut Window,
 4153        cx: &mut Context<Self>,
 4154    ) {
 4155        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4156        let tail = self
 4157            .selections
 4158            .newest::<MultiBufferOffset>(&display_map)
 4159            .tail();
 4160        let click_count = click_count.max(match self.selections.select_mode() {
 4161            SelectMode::Character => 1,
 4162            SelectMode::Word(_) => 2,
 4163            SelectMode::Line(_) => 3,
 4164            SelectMode::All => 4,
 4165        });
 4166        self.begin_selection(position, false, click_count, window, cx);
 4167
 4168        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4169
 4170        let current_selection = match self.selections.select_mode() {
 4171            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4172            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4173        };
 4174
 4175        let mut pending_selection = self
 4176            .selections
 4177            .pending_anchor()
 4178            .cloned()
 4179            .expect("extend_selection not called with pending selection");
 4180
 4181        if pending_selection
 4182            .start
 4183            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4184            == Ordering::Greater
 4185        {
 4186            pending_selection.start = current_selection.start;
 4187        }
 4188        if pending_selection
 4189            .end
 4190            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4191            == Ordering::Less
 4192        {
 4193            pending_selection.end = current_selection.end;
 4194            pending_selection.reversed = true;
 4195        }
 4196
 4197        let mut pending_mode = self.selections.pending_mode().unwrap();
 4198        match &mut pending_mode {
 4199            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4200            _ => {}
 4201        }
 4202
 4203        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4204            SelectionEffects::scroll(Autoscroll::fit())
 4205        } else {
 4206            SelectionEffects::no_scroll()
 4207        };
 4208
 4209        self.change_selections(effects, window, cx, |s| {
 4210            s.set_pending(pending_selection.clone(), pending_mode);
 4211            s.set_is_extending(true);
 4212        });
 4213    }
 4214
 4215    fn begin_selection(
 4216        &mut self,
 4217        position: DisplayPoint,
 4218        add: bool,
 4219        click_count: usize,
 4220        window: &mut Window,
 4221        cx: &mut Context<Self>,
 4222    ) {
 4223        if !self.focus_handle.is_focused(window) {
 4224            self.last_focused_descendant = None;
 4225            window.focus(&self.focus_handle, cx);
 4226        }
 4227
 4228        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4229        let buffer = display_map.buffer_snapshot();
 4230        let position = display_map.clip_point(position, Bias::Left);
 4231
 4232        let start;
 4233        let end;
 4234        let mode;
 4235        let mut auto_scroll;
 4236        match click_count {
 4237            1 => {
 4238                start = buffer.anchor_before(position.to_point(&display_map));
 4239                end = start;
 4240                mode = SelectMode::Character;
 4241                auto_scroll = true;
 4242            }
 4243            2 => {
 4244                let position = display_map
 4245                    .clip_point(position, Bias::Left)
 4246                    .to_offset(&display_map, Bias::Left);
 4247                let (range, _) = buffer.surrounding_word(position, None);
 4248                start = buffer.anchor_before(range.start);
 4249                end = buffer.anchor_before(range.end);
 4250                mode = SelectMode::Word(start..end);
 4251                auto_scroll = true;
 4252            }
 4253            3 => {
 4254                let position = display_map
 4255                    .clip_point(position, Bias::Left)
 4256                    .to_point(&display_map);
 4257                let line_start = display_map.prev_line_boundary(position).0;
 4258                let next_line_start = buffer.clip_point(
 4259                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4260                    Bias::Left,
 4261                );
 4262                start = buffer.anchor_before(line_start);
 4263                end = buffer.anchor_before(next_line_start);
 4264                mode = SelectMode::Line(start..end);
 4265                auto_scroll = true;
 4266            }
 4267            _ => {
 4268                start = buffer.anchor_before(MultiBufferOffset(0));
 4269                end = buffer.anchor_before(buffer.len());
 4270                mode = SelectMode::All;
 4271                auto_scroll = false;
 4272            }
 4273        }
 4274        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4275
 4276        let point_to_delete: Option<usize> = {
 4277            let selected_points: Vec<Selection<Point>> =
 4278                self.selections.disjoint_in_range(start..end, &display_map);
 4279
 4280            if !add || click_count > 1 {
 4281                None
 4282            } else if !selected_points.is_empty() {
 4283                Some(selected_points[0].id)
 4284            } else {
 4285                let clicked_point_already_selected =
 4286                    self.selections.disjoint_anchors().iter().find(|selection| {
 4287                        selection.start.to_point(buffer) == start.to_point(buffer)
 4288                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4289                    });
 4290
 4291                clicked_point_already_selected.map(|selection| selection.id)
 4292            }
 4293        };
 4294
 4295        let selections_count = self.selections.count();
 4296        let effects = if auto_scroll {
 4297            SelectionEffects::default()
 4298        } else {
 4299            SelectionEffects::no_scroll()
 4300        };
 4301
 4302        self.change_selections(effects, window, cx, |s| {
 4303            if let Some(point_to_delete) = point_to_delete {
 4304                s.delete(point_to_delete);
 4305
 4306                if selections_count == 1 {
 4307                    s.set_pending_anchor_range(start..end, mode);
 4308                }
 4309            } else {
 4310                if !add {
 4311                    s.clear_disjoint();
 4312                }
 4313
 4314                s.set_pending_anchor_range(start..end, mode);
 4315            }
 4316        });
 4317    }
 4318
 4319    fn begin_columnar_selection(
 4320        &mut self,
 4321        position: DisplayPoint,
 4322        goal_column: u32,
 4323        reset: bool,
 4324        mode: ColumnarMode,
 4325        window: &mut Window,
 4326        cx: &mut Context<Self>,
 4327    ) {
 4328        if !self.focus_handle.is_focused(window) {
 4329            self.last_focused_descendant = None;
 4330            window.focus(&self.focus_handle, cx);
 4331        }
 4332
 4333        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4334
 4335        if reset {
 4336            let pointer_position = display_map
 4337                .buffer_snapshot()
 4338                .anchor_before(position.to_point(&display_map));
 4339
 4340            self.change_selections(
 4341                SelectionEffects::scroll(Autoscroll::newest()),
 4342                window,
 4343                cx,
 4344                |s| {
 4345                    s.clear_disjoint();
 4346                    s.set_pending_anchor_range(
 4347                        pointer_position..pointer_position,
 4348                        SelectMode::Character,
 4349                    );
 4350                },
 4351            );
 4352        };
 4353
 4354        let tail = self.selections.newest::<Point>(&display_map).tail();
 4355        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4356        self.columnar_selection_state = match mode {
 4357            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4358                selection_tail: selection_anchor,
 4359                display_point: if reset {
 4360                    if position.column() != goal_column {
 4361                        Some(DisplayPoint::new(position.row(), goal_column))
 4362                    } else {
 4363                        None
 4364                    }
 4365                } else {
 4366                    None
 4367                },
 4368            }),
 4369            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4370                selection_tail: selection_anchor,
 4371            }),
 4372        };
 4373
 4374        if !reset {
 4375            self.select_columns(position, goal_column, &display_map, window, cx);
 4376        }
 4377    }
 4378
 4379    fn update_selection(
 4380        &mut self,
 4381        position: DisplayPoint,
 4382        goal_column: u32,
 4383        scroll_delta: gpui::Point<f32>,
 4384        window: &mut Window,
 4385        cx: &mut Context<Self>,
 4386    ) {
 4387        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4388
 4389        if self.columnar_selection_state.is_some() {
 4390            self.select_columns(position, goal_column, &display_map, window, cx);
 4391        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4392            let buffer = display_map.buffer_snapshot();
 4393            let head;
 4394            let tail;
 4395            let mode = self.selections.pending_mode().unwrap();
 4396            match &mode {
 4397                SelectMode::Character => {
 4398                    head = position.to_point(&display_map);
 4399                    tail = pending.tail().to_point(buffer);
 4400                }
 4401                SelectMode::Word(original_range) => {
 4402                    let offset = display_map
 4403                        .clip_point(position, Bias::Left)
 4404                        .to_offset(&display_map, Bias::Left);
 4405                    let original_range = original_range.to_offset(buffer);
 4406
 4407                    let head_offset = if buffer.is_inside_word(offset, None)
 4408                        || original_range.contains(&offset)
 4409                    {
 4410                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4411                        if word_range.start < original_range.start {
 4412                            word_range.start
 4413                        } else {
 4414                            word_range.end
 4415                        }
 4416                    } else {
 4417                        offset
 4418                    };
 4419
 4420                    head = head_offset.to_point(buffer);
 4421                    if head_offset <= original_range.start {
 4422                        tail = original_range.end.to_point(buffer);
 4423                    } else {
 4424                        tail = original_range.start.to_point(buffer);
 4425                    }
 4426                }
 4427                SelectMode::Line(original_range) => {
 4428                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4429
 4430                    let position = display_map
 4431                        .clip_point(position, Bias::Left)
 4432                        .to_point(&display_map);
 4433                    let line_start = display_map.prev_line_boundary(position).0;
 4434                    let next_line_start = buffer.clip_point(
 4435                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4436                        Bias::Left,
 4437                    );
 4438
 4439                    if line_start < original_range.start {
 4440                        head = line_start
 4441                    } else {
 4442                        head = next_line_start
 4443                    }
 4444
 4445                    if head <= original_range.start {
 4446                        tail = original_range.end;
 4447                    } else {
 4448                        tail = original_range.start;
 4449                    }
 4450                }
 4451                SelectMode::All => {
 4452                    return;
 4453                }
 4454            };
 4455
 4456            if head < tail {
 4457                pending.start = buffer.anchor_before(head);
 4458                pending.end = buffer.anchor_before(tail);
 4459                pending.reversed = true;
 4460            } else {
 4461                pending.start = buffer.anchor_before(tail);
 4462                pending.end = buffer.anchor_before(head);
 4463                pending.reversed = false;
 4464            }
 4465
 4466            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4467                s.set_pending(pending.clone(), mode);
 4468            });
 4469        } else {
 4470            log::error!("update_selection dispatched with no pending selection");
 4471            return;
 4472        }
 4473
 4474        self.apply_scroll_delta(scroll_delta, window, cx);
 4475        cx.notify();
 4476    }
 4477
 4478    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4479        self.columnar_selection_state.take();
 4480        if let Some(pending_mode) = self.selections.pending_mode() {
 4481            let selections = self
 4482                .selections
 4483                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4484            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4485                s.select(selections);
 4486                s.clear_pending();
 4487                if s.is_extending() {
 4488                    s.set_is_extending(false);
 4489                } else {
 4490                    s.set_select_mode(pending_mode);
 4491                }
 4492            });
 4493        }
 4494    }
 4495
 4496    fn select_columns(
 4497        &mut self,
 4498        head: DisplayPoint,
 4499        goal_column: u32,
 4500        display_map: &DisplaySnapshot,
 4501        window: &mut Window,
 4502        cx: &mut Context<Self>,
 4503    ) {
 4504        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4505            return;
 4506        };
 4507
 4508        let tail = match columnar_state {
 4509            ColumnarSelectionState::FromMouse {
 4510                selection_tail,
 4511                display_point,
 4512            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4513            ColumnarSelectionState::FromSelection { selection_tail } => {
 4514                selection_tail.to_display_point(display_map)
 4515            }
 4516        };
 4517
 4518        let start_row = cmp::min(tail.row(), head.row());
 4519        let end_row = cmp::max(tail.row(), head.row());
 4520        let start_column = cmp::min(tail.column(), goal_column);
 4521        let end_column = cmp::max(tail.column(), goal_column);
 4522        let reversed = start_column < tail.column();
 4523
 4524        let selection_ranges = (start_row.0..=end_row.0)
 4525            .map(DisplayRow)
 4526            .filter_map(|row| {
 4527                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4528                    || start_column <= display_map.line_len(row))
 4529                    && !display_map.is_block_line(row)
 4530                {
 4531                    let start = display_map
 4532                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4533                        .to_point(display_map);
 4534                    let end = display_map
 4535                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4536                        .to_point(display_map);
 4537                    if reversed {
 4538                        Some(end..start)
 4539                    } else {
 4540                        Some(start..end)
 4541                    }
 4542                } else {
 4543                    None
 4544                }
 4545            })
 4546            .collect::<Vec<_>>();
 4547        if selection_ranges.is_empty() {
 4548            return;
 4549        }
 4550
 4551        let ranges = match columnar_state {
 4552            ColumnarSelectionState::FromMouse { .. } => {
 4553                let mut non_empty_ranges = selection_ranges
 4554                    .iter()
 4555                    .filter(|selection_range| selection_range.start != selection_range.end)
 4556                    .peekable();
 4557                if non_empty_ranges.peek().is_some() {
 4558                    non_empty_ranges.cloned().collect()
 4559                } else {
 4560                    selection_ranges
 4561                }
 4562            }
 4563            _ => selection_ranges,
 4564        };
 4565
 4566        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4567            s.select_ranges(ranges);
 4568        });
 4569        cx.notify();
 4570    }
 4571
 4572    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4573        self.selections
 4574            .all_adjusted(snapshot)
 4575            .iter()
 4576            .any(|selection| !selection.is_empty())
 4577    }
 4578
 4579    pub fn has_pending_nonempty_selection(&self) -> bool {
 4580        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4581            Some(Selection { start, end, .. }) => start != end,
 4582            None => false,
 4583        };
 4584
 4585        pending_nonempty_selection
 4586            || (self.columnar_selection_state.is_some()
 4587                && self.selections.disjoint_anchors().len() > 1)
 4588    }
 4589
 4590    pub fn has_pending_selection(&self) -> bool {
 4591        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4592    }
 4593
 4594    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4595        self.selection_mark_mode = false;
 4596        self.selection_drag_state = SelectionDragState::None;
 4597
 4598        if self.dismiss_menus_and_popups(true, window, cx) {
 4599            cx.notify();
 4600            return;
 4601        }
 4602        if self.clear_expanded_diff_hunks(cx) {
 4603            cx.notify();
 4604            return;
 4605        }
 4606        if self.show_git_blame_gutter {
 4607            self.show_git_blame_gutter = false;
 4608            cx.notify();
 4609            return;
 4610        }
 4611
 4612        if self.mode.is_full()
 4613            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4614        {
 4615            cx.notify();
 4616            return;
 4617        }
 4618
 4619        cx.propagate();
 4620    }
 4621
 4622    pub fn dismiss_menus_and_popups(
 4623        &mut self,
 4624        is_user_requested: bool,
 4625        window: &mut Window,
 4626        cx: &mut Context<Self>,
 4627    ) -> bool {
 4628        let mut dismissed = false;
 4629
 4630        dismissed |= self.take_rename(false, window, cx).is_some();
 4631        dismissed |= self.hide_blame_popover(true, cx);
 4632        dismissed |= hide_hover(self, cx);
 4633        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4634        dismissed |= self.hide_context_menu(window, cx).is_some();
 4635        dismissed |= self.mouse_context_menu.take().is_some();
 4636        dismissed |= is_user_requested
 4637            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4638        dismissed |= self.snippet_stack.pop().is_some();
 4639        if self.diff_review_drag_state.is_some() {
 4640            self.cancel_diff_review_drag(cx);
 4641            dismissed = true;
 4642        }
 4643        if !self.diff_review_overlays.is_empty() {
 4644            self.dismiss_all_diff_review_overlays(cx);
 4645            dismissed = true;
 4646        }
 4647
 4648        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4649            self.dismiss_diagnostics(cx);
 4650            dismissed = true;
 4651        }
 4652
 4653        dismissed
 4654    }
 4655
 4656    fn linked_editing_ranges_for(
 4657        &self,
 4658        selection: Range<text::Anchor>,
 4659        cx: &App,
 4660    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4661        if self.linked_edit_ranges.is_empty() {
 4662            return None;
 4663        }
 4664        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4665            selection.end.buffer_id.and_then(|end_buffer_id| {
 4666                if selection.start.buffer_id != Some(end_buffer_id) {
 4667                    return None;
 4668                }
 4669                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4670                let snapshot = buffer.read(cx).snapshot();
 4671                self.linked_edit_ranges
 4672                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4673                    .map(|ranges| (ranges, snapshot, buffer))
 4674            })?;
 4675        use text::ToOffset as TO;
 4676        // find offset from the start of current range to current cursor position
 4677        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4678
 4679        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4680        let start_difference = start_offset - start_byte_offset;
 4681        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4682        let end_difference = end_offset - start_byte_offset;
 4683
 4684        // Current range has associated linked ranges.
 4685        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4686        for range in linked_ranges.iter() {
 4687            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4688            let end_offset = start_offset + end_difference;
 4689            let start_offset = start_offset + start_difference;
 4690            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4691                continue;
 4692            }
 4693            if self.selections.disjoint_anchor_ranges().any(|s| {
 4694                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4695                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4696                {
 4697                    return false;
 4698                }
 4699                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4700                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4701            }) {
 4702                continue;
 4703            }
 4704            let start = buffer_snapshot.anchor_after(start_offset);
 4705            let end = buffer_snapshot.anchor_after(end_offset);
 4706            linked_edits
 4707                .entry(buffer.clone())
 4708                .or_default()
 4709                .push(start..end);
 4710        }
 4711        Some(linked_edits)
 4712    }
 4713
 4714    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4715        let text: Arc<str> = text.into();
 4716
 4717        if self.read_only(cx) {
 4718            return;
 4719        }
 4720
 4721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4722
 4723        self.unfold_buffers_with_selections(cx);
 4724
 4725        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4726        let mut bracket_inserted = false;
 4727        let mut edits = Vec::new();
 4728        let mut linked_edits = LinkedEdits::new();
 4729        let mut new_selections = Vec::with_capacity(selections.len());
 4730        let mut new_autoclose_regions = Vec::new();
 4731        let snapshot = self.buffer.read(cx).read(cx);
 4732        let mut clear_linked_edit_ranges = false;
 4733        let mut all_selections_read_only = true;
 4734        let mut has_adjacent_edits = false;
 4735        let mut in_adjacent_group = false;
 4736
 4737        let mut regions = self
 4738            .selections_with_autoclose_regions(selections, &snapshot)
 4739            .peekable();
 4740
 4741        while let Some((selection, autoclose_region)) = regions.next() {
 4742            if snapshot
 4743                .point_to_buffer_point(selection.head())
 4744                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4745            {
 4746                continue;
 4747            }
 4748            if snapshot
 4749                .point_to_buffer_point(selection.tail())
 4750                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4751            {
 4752                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4753                continue;
 4754            }
 4755            all_selections_read_only = false;
 4756
 4757            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4758                // Determine if the inserted text matches the opening or closing
 4759                // bracket of any of this language's bracket pairs.
 4760                let mut bracket_pair = None;
 4761                let mut is_bracket_pair_start = false;
 4762                let mut is_bracket_pair_end = false;
 4763                if !text.is_empty() {
 4764                    let mut bracket_pair_matching_end = None;
 4765                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4766                    //  and they are removing the character that triggered IME popup.
 4767                    for (pair, enabled) in scope.brackets() {
 4768                        if !pair.close && !pair.surround {
 4769                            continue;
 4770                        }
 4771
 4772                        if enabled && pair.start.ends_with(text.as_ref()) {
 4773                            let prefix_len = pair.start.len() - text.len();
 4774                            let preceding_text_matches_prefix = prefix_len == 0
 4775                                || (selection.start.column >= (prefix_len as u32)
 4776                                    && snapshot.contains_str_at(
 4777                                        Point::new(
 4778                                            selection.start.row,
 4779                                            selection.start.column - (prefix_len as u32),
 4780                                        ),
 4781                                        &pair.start[..prefix_len],
 4782                                    ));
 4783                            if preceding_text_matches_prefix {
 4784                                bracket_pair = Some(pair.clone());
 4785                                is_bracket_pair_start = true;
 4786                                break;
 4787                            }
 4788                        }
 4789                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4790                        {
 4791                            // take first bracket pair matching end, but don't break in case a later bracket
 4792                            // pair matches start
 4793                            bracket_pair_matching_end = Some(pair.clone());
 4794                        }
 4795                    }
 4796                    if let Some(end) = bracket_pair_matching_end
 4797                        && bracket_pair.is_none()
 4798                    {
 4799                        bracket_pair = Some(end);
 4800                        is_bracket_pair_end = true;
 4801                    }
 4802                }
 4803
 4804                if let Some(bracket_pair) = bracket_pair {
 4805                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4806                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4807                    let auto_surround =
 4808                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4809                    if selection.is_empty() {
 4810                        if is_bracket_pair_start {
 4811                            // If the inserted text is a suffix of an opening bracket and the
 4812                            // selection is preceded by the rest of the opening bracket, then
 4813                            // insert the closing bracket.
 4814                            let following_text_allows_autoclose = snapshot
 4815                                .chars_at(selection.start)
 4816                                .next()
 4817                                .is_none_or(|c| scope.should_autoclose_before(c));
 4818
 4819                            let preceding_text_allows_autoclose = selection.start.column == 0
 4820                                || snapshot
 4821                                    .reversed_chars_at(selection.start)
 4822                                    .next()
 4823                                    .is_none_or(|c| {
 4824                                        bracket_pair.start != bracket_pair.end
 4825                                            || !snapshot
 4826                                                .char_classifier_at(selection.start)
 4827                                                .is_word(c)
 4828                                    });
 4829
 4830                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4831                                && bracket_pair.start.len() == 1
 4832                            {
 4833                                let target = bracket_pair.start.chars().next().unwrap();
 4834                                let mut byte_offset = 0u32;
 4835                                let current_line_count = snapshot
 4836                                    .reversed_chars_at(selection.start)
 4837                                    .take_while(|&c| c != '\n')
 4838                                    .filter(|c| {
 4839                                        byte_offset += c.len_utf8() as u32;
 4840                                        if *c != target {
 4841                                            return false;
 4842                                        }
 4843
 4844                                        let point = Point::new(
 4845                                            selection.start.row,
 4846                                            selection.start.column.saturating_sub(byte_offset),
 4847                                        );
 4848
 4849                                        let is_enabled = snapshot
 4850                                            .language_scope_at(point)
 4851                                            .and_then(|scope| {
 4852                                                scope
 4853                                                    .brackets()
 4854                                                    .find(|(pair, _)| {
 4855                                                        pair.start == bracket_pair.start
 4856                                                    })
 4857                                                    .map(|(_, enabled)| enabled)
 4858                                            })
 4859                                            .unwrap_or(true);
 4860
 4861                                        let is_delimiter = snapshot
 4862                                            .language_scope_at(Point::new(
 4863                                                point.row,
 4864                                                point.column + 1,
 4865                                            ))
 4866                                            .and_then(|scope| {
 4867                                                scope
 4868                                                    .brackets()
 4869                                                    .find(|(pair, _)| {
 4870                                                        pair.start == bracket_pair.start
 4871                                                    })
 4872                                                    .map(|(_, enabled)| !enabled)
 4873                                            })
 4874                                            .unwrap_or(false);
 4875
 4876                                        is_enabled && !is_delimiter
 4877                                    })
 4878                                    .count();
 4879                                current_line_count % 2 == 1
 4880                            } else {
 4881                                false
 4882                            };
 4883
 4884                            if autoclose
 4885                                && bracket_pair.close
 4886                                && following_text_allows_autoclose
 4887                                && preceding_text_allows_autoclose
 4888                                && !is_closing_quote
 4889                            {
 4890                                let anchor = snapshot.anchor_before(selection.end);
 4891                                new_selections.push((selection.map(|_| anchor), text.len()));
 4892                                new_autoclose_regions.push((
 4893                                    anchor,
 4894                                    text.len(),
 4895                                    selection.id,
 4896                                    bracket_pair.clone(),
 4897                                ));
 4898                                edits.push((
 4899                                    selection.range(),
 4900                                    format!("{}{}", text, bracket_pair.end).into(),
 4901                                ));
 4902                                bracket_inserted = true;
 4903                                continue;
 4904                            }
 4905                        }
 4906
 4907                        if let Some(region) = autoclose_region {
 4908                            // If the selection is followed by an auto-inserted closing bracket,
 4909                            // then don't insert that closing bracket again; just move the selection
 4910                            // past the closing bracket.
 4911                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4912                                && text.as_ref() == region.pair.end.as_str()
 4913                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4914                            if should_skip {
 4915                                let anchor = snapshot.anchor_after(selection.end);
 4916                                new_selections
 4917                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4918                                continue;
 4919                            }
 4920                        }
 4921
 4922                        let always_treat_brackets_as_autoclosed = snapshot
 4923                            .language_settings_at(selection.start, cx)
 4924                            .always_treat_brackets_as_autoclosed;
 4925                        if always_treat_brackets_as_autoclosed
 4926                            && is_bracket_pair_end
 4927                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4928                        {
 4929                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4930                            // and the inserted text is a closing bracket and the selection is followed
 4931                            // by the closing bracket then move the selection past the closing bracket.
 4932                            let anchor = snapshot.anchor_after(selection.end);
 4933                            new_selections.push((selection.map(|_| anchor), text.len()));
 4934                            continue;
 4935                        }
 4936                    }
 4937                    // If an opening bracket is 1 character long and is typed while
 4938                    // text is selected, then surround that text with the bracket pair.
 4939                    else if auto_surround
 4940                        && bracket_pair.surround
 4941                        && is_bracket_pair_start
 4942                        && bracket_pair.start.chars().count() == 1
 4943                    {
 4944                        edits.push((selection.start..selection.start, text.clone()));
 4945                        edits.push((
 4946                            selection.end..selection.end,
 4947                            bracket_pair.end.as_str().into(),
 4948                        ));
 4949                        bracket_inserted = true;
 4950                        new_selections.push((
 4951                            Selection {
 4952                                id: selection.id,
 4953                                start: snapshot.anchor_after(selection.start),
 4954                                end: snapshot.anchor_before(selection.end),
 4955                                reversed: selection.reversed,
 4956                                goal: selection.goal,
 4957                            },
 4958                            0,
 4959                        ));
 4960                        continue;
 4961                    }
 4962                }
 4963            }
 4964
 4965            if self.auto_replace_emoji_shortcode
 4966                && selection.is_empty()
 4967                && text.as_ref().ends_with(':')
 4968                && let Some(possible_emoji_short_code) =
 4969                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4970                && !possible_emoji_short_code.is_empty()
 4971                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4972            {
 4973                let emoji_shortcode_start = Point::new(
 4974                    selection.start.row,
 4975                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4976                );
 4977
 4978                // Remove shortcode from buffer
 4979                edits.push((
 4980                    emoji_shortcode_start..selection.start,
 4981                    "".to_string().into(),
 4982                ));
 4983                new_selections.push((
 4984                    Selection {
 4985                        id: selection.id,
 4986                        start: snapshot.anchor_after(emoji_shortcode_start),
 4987                        end: snapshot.anchor_before(selection.start),
 4988                        reversed: selection.reversed,
 4989                        goal: selection.goal,
 4990                    },
 4991                    0,
 4992                ));
 4993
 4994                // Insert emoji
 4995                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4996                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4997                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4998
 4999                continue;
 5000            }
 5001
 5002            let next_is_adjacent = regions
 5003                .peek()
 5004                .is_some_and(|(next, _)| selection.end == next.start);
 5005
 5006            // If not handling any auto-close operation, then just replace the selected
 5007            // text with the given input and move the selection to the end of the
 5008            // newly inserted text.
 5009            let anchor = if in_adjacent_group || next_is_adjacent {
 5010                // After edits the right bias would shift those anchor to the next visible fragment
 5011                // but we want to resolve to the previous one
 5012                snapshot.anchor_before(selection.end)
 5013            } else {
 5014                snapshot.anchor_after(selection.end)
 5015            };
 5016
 5017            if !self.linked_edit_ranges.is_empty() {
 5018                let start_anchor = snapshot.anchor_before(selection.start);
 5019
 5020                let is_word_char = text.chars().next().is_none_or(|char| {
 5021                    let classifier = snapshot
 5022                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 5023                        .scope_context(Some(CharScopeContext::LinkedEdit));
 5024                    classifier.is_word(char)
 5025                });
 5026                let is_dot = text.as_ref() == ".";
 5027                let should_apply_linked_edit = is_word_char || is_dot;
 5028
 5029                if should_apply_linked_edit {
 5030                    let anchor_range = start_anchor.text_anchor..anchor.text_anchor;
 5031                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 5032                } else {
 5033                    clear_linked_edit_ranges = true;
 5034                }
 5035            }
 5036
 5037            new_selections.push((selection.map(|_| anchor), 0));
 5038            edits.push((selection.start..selection.end, text.clone()));
 5039
 5040            has_adjacent_edits |= next_is_adjacent;
 5041            in_adjacent_group = next_is_adjacent;
 5042        }
 5043
 5044        if all_selections_read_only {
 5045            return;
 5046        }
 5047
 5048        drop(regions);
 5049        drop(snapshot);
 5050
 5051        self.transact(window, cx, |this, window, cx| {
 5052            if clear_linked_edit_ranges {
 5053                this.linked_edit_ranges.clear();
 5054            }
 5055            let initial_buffer_versions =
 5056                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5057
 5058            this.buffer.update(cx, |buffer, cx| {
 5059                if has_adjacent_edits {
 5060                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5061                } else {
 5062                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5063                }
 5064            });
 5065            linked_edits.apply(cx);
 5066            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5067            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5068            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5069            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5070                new_anchor_selections,
 5071                &map,
 5072            )
 5073            .zip(new_selection_deltas)
 5074            .map(|(selection, delta)| Selection {
 5075                id: selection.id,
 5076                start: selection.start + delta,
 5077                end: selection.end + delta,
 5078                reversed: selection.reversed,
 5079                goal: SelectionGoal::None,
 5080            })
 5081            .collect::<Vec<_>>();
 5082
 5083            let mut i = 0;
 5084            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5085                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5086                let start = map.buffer_snapshot().anchor_before(position);
 5087                let end = map.buffer_snapshot().anchor_after(position);
 5088                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5089                    match existing_state
 5090                        .range
 5091                        .start
 5092                        .cmp(&start, map.buffer_snapshot())
 5093                    {
 5094                        Ordering::Less => i += 1,
 5095                        Ordering::Greater => break,
 5096                        Ordering::Equal => {
 5097                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5098                                Ordering::Less => i += 1,
 5099                                Ordering::Equal => break,
 5100                                Ordering::Greater => break,
 5101                            }
 5102                        }
 5103                    }
 5104                }
 5105                this.autoclose_regions.insert(
 5106                    i,
 5107                    AutocloseRegion {
 5108                        selection_id,
 5109                        range: start..end,
 5110                        pair,
 5111                    },
 5112                );
 5113            }
 5114
 5115            let had_active_edit_prediction = this.has_active_edit_prediction();
 5116            this.change_selections(
 5117                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5118                window,
 5119                cx,
 5120                |s| s.select(new_selections),
 5121            );
 5122
 5123            if !bracket_inserted
 5124                && let Some(on_type_format_task) =
 5125                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5126            {
 5127                on_type_format_task.detach_and_log_err(cx);
 5128            }
 5129
 5130            let editor_settings = EditorSettings::get_global(cx);
 5131            if bracket_inserted
 5132                && (editor_settings.auto_signature_help
 5133                    || editor_settings.show_signature_help_after_edits)
 5134            {
 5135                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5136            }
 5137
 5138            let trigger_in_words =
 5139                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5140            if this.hard_wrap.is_some() {
 5141                let latest: Range<Point> = this.selections.newest(&map).range();
 5142                if latest.is_empty()
 5143                    && this
 5144                        .buffer()
 5145                        .read(cx)
 5146                        .snapshot(cx)
 5147                        .line_len(MultiBufferRow(latest.start.row))
 5148                        == latest.start.column
 5149                {
 5150                    this.rewrap_impl(
 5151                        RewrapOptions {
 5152                            override_language_settings: true,
 5153                            preserve_existing_whitespace: true,
 5154                            line_length: None,
 5155                        },
 5156                        cx,
 5157                    )
 5158                }
 5159            }
 5160            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5161            refresh_linked_ranges(this, window, cx);
 5162            this.refresh_edit_prediction(true, false, window, cx);
 5163            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5164        });
 5165    }
 5166
 5167    fn find_possible_emoji_shortcode_at_position(
 5168        snapshot: &MultiBufferSnapshot,
 5169        position: Point,
 5170    ) -> Option<String> {
 5171        let mut chars = Vec::new();
 5172        let mut found_colon = false;
 5173        for char in snapshot.reversed_chars_at(position).take(100) {
 5174            // Found a possible emoji shortcode in the middle of the buffer
 5175            if found_colon {
 5176                if char.is_whitespace() {
 5177                    chars.reverse();
 5178                    return Some(chars.iter().collect());
 5179                }
 5180                // If the previous character is not a whitespace, we are in the middle of a word
 5181                // and we only want to complete the shortcode if the word is made up of other emojis
 5182                let mut containing_word = String::new();
 5183                for ch in snapshot
 5184                    .reversed_chars_at(position)
 5185                    .skip(chars.len() + 1)
 5186                    .take(100)
 5187                {
 5188                    if ch.is_whitespace() {
 5189                        break;
 5190                    }
 5191                    containing_word.push(ch);
 5192                }
 5193                let containing_word = containing_word.chars().rev().collect::<String>();
 5194                if util::word_consists_of_emojis(containing_word.as_str()) {
 5195                    chars.reverse();
 5196                    return Some(chars.iter().collect());
 5197                }
 5198            }
 5199
 5200            if char.is_whitespace() || !char.is_ascii() {
 5201                return None;
 5202            }
 5203            if char == ':' {
 5204                found_colon = true;
 5205            } else {
 5206                chars.push(char);
 5207            }
 5208        }
 5209        // Found a possible emoji shortcode at the beginning of the buffer
 5210        chars.reverse();
 5211        Some(chars.iter().collect())
 5212    }
 5213
 5214    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5215        if self.read_only(cx) {
 5216            return;
 5217        }
 5218
 5219        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5220        self.transact(window, cx, |this, window, cx| {
 5221            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5222                let selections = this
 5223                    .selections
 5224                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5225                let multi_buffer = this.buffer.read(cx);
 5226                let buffer = multi_buffer.snapshot(cx);
 5227                selections
 5228                    .iter()
 5229                    .map(|selection| {
 5230                        let start_point = selection.start.to_point(&buffer);
 5231                        let mut existing_indent =
 5232                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5233                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5234                        let start = selection.start;
 5235                        let end = selection.end;
 5236                        let selection_is_empty = start == end;
 5237                        let language_scope = buffer.language_scope_at(start);
 5238                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5239                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5240                                &buffer,
 5241                                start..end,
 5242                                language,
 5243                            )
 5244                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5245                                    &buffer,
 5246                                    start..end,
 5247                                );
 5248
 5249                            let mut newline_config = NewlineConfig::Newline {
 5250                                additional_indent: IndentSize::spaces(0),
 5251                                extra_line_additional_indent: if needs_extra_newline {
 5252                                    Some(IndentSize::spaces(0))
 5253                                } else {
 5254                                    None
 5255                                },
 5256                                prevent_auto_indent: false,
 5257                            };
 5258
 5259                            let comment_delimiter = maybe!({
 5260                                if !selection_is_empty {
 5261                                    return None;
 5262                                }
 5263
 5264                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5265                                    return None;
 5266                                }
 5267
 5268                                return comment_delimiter_for_newline(
 5269                                    &start_point,
 5270                                    &buffer,
 5271                                    language,
 5272                                );
 5273                            });
 5274
 5275                            let doc_delimiter = maybe!({
 5276                                if !selection_is_empty {
 5277                                    return None;
 5278                                }
 5279
 5280                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5281                                    return None;
 5282                                }
 5283
 5284                                return documentation_delimiter_for_newline(
 5285                                    &start_point,
 5286                                    &buffer,
 5287                                    language,
 5288                                    &mut newline_config,
 5289                                );
 5290                            });
 5291
 5292                            let list_delimiter = maybe!({
 5293                                if !selection_is_empty {
 5294                                    return None;
 5295                                }
 5296
 5297                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5298                                    return None;
 5299                                }
 5300
 5301                                return list_delimiter_for_newline(
 5302                                    &start_point,
 5303                                    &buffer,
 5304                                    language,
 5305                                    &mut newline_config,
 5306                                );
 5307                            });
 5308
 5309                            (
 5310                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5311                                newline_config,
 5312                            )
 5313                        } else {
 5314                            (
 5315                                None,
 5316                                NewlineConfig::Newline {
 5317                                    additional_indent: IndentSize::spaces(0),
 5318                                    extra_line_additional_indent: None,
 5319                                    prevent_auto_indent: false,
 5320                                },
 5321                            )
 5322                        };
 5323
 5324                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5325                            NewlineConfig::ClearCurrentLine => {
 5326                                let row_start =
 5327                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5328                                (row_start, String::new(), false)
 5329                            }
 5330                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5331                                let row_start =
 5332                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5333                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5334                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5335                                let reduced_indent =
 5336                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5337                                let mut new_text = String::new();
 5338                                new_text.extend(reduced_indent.chars());
 5339                                new_text.push_str(continuation);
 5340                                (row_start, new_text, true)
 5341                            }
 5342                            NewlineConfig::Newline {
 5343                                additional_indent,
 5344                                extra_line_additional_indent,
 5345                                prevent_auto_indent,
 5346                            } => {
 5347                                let auto_indent_mode =
 5348                                    buffer.language_settings_at(start, cx).auto_indent;
 5349                                let preserve_indent =
 5350                                    auto_indent_mode != language::AutoIndentMode::None;
 5351                                let apply_syntax_indent =
 5352                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5353                                let capacity_for_delimiter =
 5354                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5355                                let existing_indent_len = if preserve_indent {
 5356                                    existing_indent.len as usize
 5357                                } else {
 5358                                    0
 5359                                };
 5360                                let extra_line_len = extra_line_additional_indent
 5361                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5362                                    .unwrap_or(0);
 5363                                let mut new_text = String::with_capacity(
 5364                                    1 + capacity_for_delimiter
 5365                                        + existing_indent_len
 5366                                        + additional_indent.len as usize
 5367                                        + extra_line_len,
 5368                                );
 5369                                new_text.push('\n');
 5370                                if preserve_indent {
 5371                                    new_text.extend(existing_indent.chars());
 5372                                }
 5373                                new_text.extend(additional_indent.chars());
 5374                                if let Some(delimiter) = &delimiter {
 5375                                    new_text.push_str(delimiter);
 5376                                }
 5377                                if let Some(extra_indent) = extra_line_additional_indent {
 5378                                    new_text.push('\n');
 5379                                    if preserve_indent {
 5380                                        new_text.extend(existing_indent.chars());
 5381                                    }
 5382                                    new_text.extend(extra_indent.chars());
 5383                                }
 5384                                (
 5385                                    start,
 5386                                    new_text,
 5387                                    *prevent_auto_indent || !apply_syntax_indent,
 5388                                )
 5389                            }
 5390                        };
 5391
 5392                        let anchor = buffer.anchor_after(end);
 5393                        let new_selection = selection.map(|_| anchor);
 5394                        (
 5395                            ((edit_start..end, new_text), prevent_auto_indent),
 5396                            (newline_config.has_extra_line(), new_selection),
 5397                        )
 5398                    })
 5399                    .unzip()
 5400            };
 5401
 5402            let mut auto_indent_edits = Vec::new();
 5403            let mut edits = Vec::new();
 5404            for (edit, prevent_auto_indent) in edits_with_flags {
 5405                if prevent_auto_indent {
 5406                    edits.push(edit);
 5407                } else {
 5408                    auto_indent_edits.push(edit);
 5409                }
 5410            }
 5411            if !edits.is_empty() {
 5412                this.edit(edits, cx);
 5413            }
 5414            if !auto_indent_edits.is_empty() {
 5415                this.edit_with_autoindent(auto_indent_edits, cx);
 5416            }
 5417
 5418            let buffer = this.buffer.read(cx).snapshot(cx);
 5419            let new_selections = selection_info
 5420                .into_iter()
 5421                .map(|(extra_newline_inserted, new_selection)| {
 5422                    let mut cursor = new_selection.end.to_point(&buffer);
 5423                    if extra_newline_inserted {
 5424                        cursor.row -= 1;
 5425                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5426                    }
 5427                    new_selection.map(|_| cursor)
 5428                })
 5429                .collect();
 5430
 5431            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5432            this.refresh_edit_prediction(true, false, window, cx);
 5433            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5434                task.detach_and_log_err(cx);
 5435            }
 5436        });
 5437    }
 5438
 5439    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5440        if self.read_only(cx) {
 5441            return;
 5442        }
 5443
 5444        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5445
 5446        let buffer = self.buffer.read(cx);
 5447        let snapshot = buffer.snapshot(cx);
 5448
 5449        let mut edits = Vec::new();
 5450        let mut rows = Vec::new();
 5451
 5452        for (rows_inserted, selection) in self
 5453            .selections
 5454            .all_adjusted(&self.display_snapshot(cx))
 5455            .into_iter()
 5456            .enumerate()
 5457        {
 5458            let cursor = selection.head();
 5459            let row = cursor.row;
 5460
 5461            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5462
 5463            let newline = "\n".to_string();
 5464            edits.push((start_of_line..start_of_line, newline));
 5465
 5466            rows.push(row + rows_inserted as u32);
 5467        }
 5468
 5469        self.transact(window, cx, |editor, window, cx| {
 5470            editor.edit(edits, cx);
 5471
 5472            editor.change_selections(Default::default(), window, cx, |s| {
 5473                let mut index = 0;
 5474                s.move_cursors_with(&mut |map, _, _| {
 5475                    let row = rows[index];
 5476                    index += 1;
 5477
 5478                    let point = Point::new(row, 0);
 5479                    let boundary = map.next_line_boundary(point).1;
 5480                    let clipped = map.clip_point(boundary, Bias::Left);
 5481
 5482                    (clipped, SelectionGoal::None)
 5483                });
 5484            });
 5485
 5486            let mut indent_edits = Vec::new();
 5487            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5488            for row in rows {
 5489                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5490                for (row, indent) in indents {
 5491                    if indent.len == 0 {
 5492                        continue;
 5493                    }
 5494
 5495                    let text = match indent.kind {
 5496                        IndentKind::Space => " ".repeat(indent.len as usize),
 5497                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5498                    };
 5499                    let point = Point::new(row.0, 0);
 5500                    indent_edits.push((point..point, text));
 5501                }
 5502            }
 5503            editor.edit(indent_edits, cx);
 5504            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5505                format.detach_and_log_err(cx);
 5506            }
 5507        });
 5508    }
 5509
 5510    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5511        if self.read_only(cx) {
 5512            return;
 5513        }
 5514
 5515        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5516
 5517        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5518        let mut rows = Vec::new();
 5519        let mut rows_inserted = 0;
 5520
 5521        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5522            let cursor = selection.head();
 5523            let row = cursor.row;
 5524
 5525            let point = Point::new(row, 0);
 5526            let Some((buffer_handle, buffer_point, _)) =
 5527                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5528            else {
 5529                continue;
 5530            };
 5531
 5532            buffer_edits
 5533                .entry(buffer_handle.entity_id())
 5534                .or_insert_with(|| (buffer_handle, Vec::new()))
 5535                .1
 5536                .push(buffer_point);
 5537
 5538            rows_inserted += 1;
 5539            rows.push(row + rows_inserted);
 5540        }
 5541
 5542        self.transact(window, cx, |editor, window, cx| {
 5543            for (_, (buffer_handle, points)) in &buffer_edits {
 5544                buffer_handle.update(cx, |buffer, cx| {
 5545                    let edits: Vec<_> = points
 5546                        .iter()
 5547                        .map(|point| {
 5548                            let target = Point::new(point.row + 1, 0);
 5549                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5550                            (start_of_line..start_of_line, "\n")
 5551                        })
 5552                        .collect();
 5553                    buffer.edit(edits, None, cx);
 5554                });
 5555            }
 5556
 5557            editor.change_selections(Default::default(), window, cx, |s| {
 5558                let mut index = 0;
 5559                s.move_cursors_with(&mut |map, _, _| {
 5560                    let row = rows[index];
 5561                    index += 1;
 5562
 5563                    let point = Point::new(row, 0);
 5564                    let boundary = map.next_line_boundary(point).1;
 5565                    let clipped = map.clip_point(boundary, Bias::Left);
 5566
 5567                    (clipped, SelectionGoal::None)
 5568                });
 5569            });
 5570
 5571            let mut indent_edits = Vec::new();
 5572            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5573            for row in rows {
 5574                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5575                for (row, indent) in indents {
 5576                    if indent.len == 0 {
 5577                        continue;
 5578                    }
 5579
 5580                    let text = match indent.kind {
 5581                        IndentKind::Space => " ".repeat(indent.len as usize),
 5582                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5583                    };
 5584                    let point = Point::new(row.0, 0);
 5585                    indent_edits.push((point..point, text));
 5586                }
 5587            }
 5588            editor.edit(indent_edits, cx);
 5589            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5590                format.detach_and_log_err(cx);
 5591            }
 5592        });
 5593    }
 5594
 5595    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5596        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5597            original_indent_columns: Vec::new(),
 5598        });
 5599        self.replace_selections(text, autoindent, window, cx, false);
 5600    }
 5601
 5602    /// Replaces the editor's selections with the provided `text`, applying the
 5603    /// given `autoindent_mode` (`None` will skip autoindentation).
 5604    ///
 5605    /// Early returns if the editor is in read-only mode, without applying any
 5606    /// edits.
 5607    fn replace_selections(
 5608        &mut self,
 5609        text: &str,
 5610        autoindent_mode: Option<AutoindentMode>,
 5611        window: &mut Window,
 5612        cx: &mut Context<Self>,
 5613        apply_linked_edits: bool,
 5614    ) {
 5615        if self.read_only(cx) {
 5616            return;
 5617        }
 5618
 5619        let text: Arc<str> = text.into();
 5620        self.transact(window, cx, |this, window, cx| {
 5621            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5622            let linked_edits = if apply_linked_edits {
 5623                this.linked_edits_for_selections(text.clone(), cx)
 5624            } else {
 5625                LinkedEdits::new()
 5626            };
 5627
 5628            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5629                let anchors = {
 5630                    let snapshot = buffer.read(cx);
 5631                    old_selections
 5632                        .iter()
 5633                        .map(|s| {
 5634                            let anchor = snapshot.anchor_after(s.head());
 5635                            s.map(|_| anchor)
 5636                        })
 5637                        .collect::<Vec<_>>()
 5638                };
 5639                buffer.edit(
 5640                    old_selections
 5641                        .iter()
 5642                        .map(|s| (s.start..s.end, text.clone())),
 5643                    autoindent_mode,
 5644                    cx,
 5645                );
 5646                anchors
 5647            });
 5648
 5649            linked_edits.apply(cx);
 5650
 5651            this.change_selections(Default::default(), window, cx, |s| {
 5652                s.select_anchors(selection_anchors);
 5653            });
 5654
 5655            if apply_linked_edits {
 5656                refresh_linked_ranges(this, window, cx);
 5657            }
 5658
 5659            cx.notify();
 5660        });
 5661    }
 5662
 5663    /// Collects linked edits for the current selections, pairing each linked
 5664    /// range with `text`.
 5665    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5666        let mut linked_edits = LinkedEdits::new();
 5667        if !self.linked_edit_ranges.is_empty() {
 5668            for selection in self.selections.disjoint_anchors() {
 5669                let start = selection.start.text_anchor;
 5670                let end = selection.end.text_anchor;
 5671                linked_edits.push(self, start..end, text.clone(), cx);
 5672            }
 5673        }
 5674        linked_edits
 5675    }
 5676
 5677    /// Deletes the content covered by the current selections and applies
 5678    /// linked edits.
 5679    pub fn delete_selections_with_linked_edits(
 5680        &mut self,
 5681        window: &mut Window,
 5682        cx: &mut Context<Self>,
 5683    ) {
 5684        self.replace_selections("", None, window, cx, true);
 5685    }
 5686
 5687    #[cfg(any(test, feature = "test-support"))]
 5688    pub fn set_linked_edit_ranges_for_testing(
 5689        &mut self,
 5690        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5691        cx: &mut Context<Self>,
 5692    ) -> Option<()> {
 5693        let Some((buffer, _)) = self
 5694            .buffer
 5695            .read(cx)
 5696            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5697        else {
 5698            return None;
 5699        };
 5700        let buffer = buffer.read(cx);
 5701        let buffer_id = buffer.remote_id();
 5702        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5703        for (base_range, linked_ranges_points) in ranges {
 5704            let base_anchor =
 5705                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5706            let linked_anchors = linked_ranges_points
 5707                .into_iter()
 5708                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5709                .collect();
 5710            linked_ranges.push((base_anchor, linked_anchors));
 5711        }
 5712        let mut map = HashMap::default();
 5713        map.insert(buffer_id, linked_ranges);
 5714        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5715        Some(())
 5716    }
 5717
 5718    fn trigger_completion_on_input(
 5719        &mut self,
 5720        text: &str,
 5721        trigger_in_words: bool,
 5722        window: &mut Window,
 5723        cx: &mut Context<Self>,
 5724    ) {
 5725        let completions_source = self
 5726            .context_menu
 5727            .borrow()
 5728            .as_ref()
 5729            .and_then(|menu| match menu {
 5730                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5731                CodeContextMenu::CodeActions(_) => None,
 5732            });
 5733
 5734        match completions_source {
 5735            Some(CompletionsMenuSource::Words { .. }) => {
 5736                self.open_or_update_completions_menu(
 5737                    Some(CompletionsMenuSource::Words {
 5738                        ignore_threshold: false,
 5739                    }),
 5740                    None,
 5741                    trigger_in_words,
 5742                    window,
 5743                    cx,
 5744                );
 5745            }
 5746            _ => self.open_or_update_completions_menu(
 5747                None,
 5748                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5749                true,
 5750                window,
 5751                cx,
 5752            ),
 5753        }
 5754    }
 5755
 5756    /// If any empty selections is touching the start of its innermost containing autoclose
 5757    /// region, expand it to select the brackets.
 5758    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5759        let selections = self
 5760            .selections
 5761            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5762        let buffer = self.buffer.read(cx).read(cx);
 5763        let new_selections = self
 5764            .selections_with_autoclose_regions(selections, &buffer)
 5765            .map(|(mut selection, region)| {
 5766                if !selection.is_empty() {
 5767                    return selection;
 5768                }
 5769
 5770                if let Some(region) = region {
 5771                    let mut range = region.range.to_offset(&buffer);
 5772                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5773                        range.start -= region.pair.start.len();
 5774                        if buffer.contains_str_at(range.start, &region.pair.start)
 5775                            && buffer.contains_str_at(range.end, &region.pair.end)
 5776                        {
 5777                            range.end += region.pair.end.len();
 5778                            selection.start = range.start;
 5779                            selection.end = range.end;
 5780
 5781                            return selection;
 5782                        }
 5783                    }
 5784                }
 5785
 5786                let always_treat_brackets_as_autoclosed = buffer
 5787                    .language_settings_at(selection.start, cx)
 5788                    .always_treat_brackets_as_autoclosed;
 5789
 5790                if !always_treat_brackets_as_autoclosed {
 5791                    return selection;
 5792                }
 5793
 5794                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5795                    for (pair, enabled) in scope.brackets() {
 5796                        if !enabled || !pair.close {
 5797                            continue;
 5798                        }
 5799
 5800                        if buffer.contains_str_at(selection.start, &pair.end) {
 5801                            let pair_start_len = pair.start.len();
 5802                            if buffer.contains_str_at(
 5803                                selection.start.saturating_sub_usize(pair_start_len),
 5804                                &pair.start,
 5805                            ) {
 5806                                selection.start -= pair_start_len;
 5807                                selection.end += pair.end.len();
 5808
 5809                                return selection;
 5810                            }
 5811                        }
 5812                    }
 5813                }
 5814
 5815                selection
 5816            })
 5817            .collect();
 5818
 5819        drop(buffer);
 5820        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5821            selections.select(new_selections)
 5822        });
 5823    }
 5824
 5825    /// Iterate the given selections, and for each one, find the smallest surrounding
 5826    /// autoclose region. This uses the ordering of the selections and the autoclose
 5827    /// regions to avoid repeated comparisons.
 5828    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5829        &'a self,
 5830        selections: impl IntoIterator<Item = Selection<D>>,
 5831        buffer: &'a MultiBufferSnapshot,
 5832    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5833        let mut i = 0;
 5834        let mut regions = self.autoclose_regions.as_slice();
 5835        selections.into_iter().map(move |selection| {
 5836            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5837
 5838            let mut enclosing = None;
 5839            while let Some(pair_state) = regions.get(i) {
 5840                if pair_state.range.end.to_offset(buffer) < range.start {
 5841                    regions = &regions[i + 1..];
 5842                    i = 0;
 5843                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5844                    break;
 5845                } else {
 5846                    if pair_state.selection_id == selection.id {
 5847                        enclosing = Some(pair_state);
 5848                    }
 5849                    i += 1;
 5850                }
 5851            }
 5852
 5853            (selection, enclosing)
 5854        })
 5855    }
 5856
 5857    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5858    fn invalidate_autoclose_regions(
 5859        &mut self,
 5860        mut selections: &[Selection<Anchor>],
 5861        buffer: &MultiBufferSnapshot,
 5862    ) {
 5863        self.autoclose_regions.retain(|state| {
 5864            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5865                return false;
 5866            }
 5867
 5868            let mut i = 0;
 5869            while let Some(selection) = selections.get(i) {
 5870                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5871                    selections = &selections[1..];
 5872                    continue;
 5873                }
 5874                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5875                    break;
 5876                }
 5877                if selection.id == state.selection_id {
 5878                    return true;
 5879                } else {
 5880                    i += 1;
 5881                }
 5882            }
 5883            false
 5884        });
 5885    }
 5886
 5887    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5888        let offset = position.to_offset(buffer);
 5889        let (word_range, kind) =
 5890            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5891        if offset > word_range.start && kind == Some(CharKind::Word) {
 5892            Some(
 5893                buffer
 5894                    .text_for_range(word_range.start..offset)
 5895                    .collect::<String>(),
 5896            )
 5897        } else {
 5898            None
 5899        }
 5900    }
 5901
 5902    pub fn visible_excerpts(
 5903        &self,
 5904        lsp_related_only: bool,
 5905        cx: &mut Context<Editor>,
 5906    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5907        let project = self.project().cloned();
 5908        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5909        let multi_buffer = self.buffer().read(cx);
 5910        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5911        multi_buffer_snapshot
 5912            .range_to_buffer_ranges(
 5913                self.multi_buffer_visible_range(&display_snapshot, cx)
 5914                    .to_inclusive(),
 5915            )
 5916            .into_iter()
 5917            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5918            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5919                if !lsp_related_only {
 5920                    return Some((
 5921                        excerpt_id,
 5922                        (
 5923                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5924                            buffer.version().clone(),
 5925                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5926                        ),
 5927                    ));
 5928                }
 5929
 5930                let project = project.as_ref()?.read(cx);
 5931                let buffer_file = project::File::from_dyn(buffer.file())?;
 5932                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5933                let worktree_entry = buffer_worktree
 5934                    .read(cx)
 5935                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5936                if worktree_entry.is_ignored {
 5937                    None
 5938                } else {
 5939                    Some((
 5940                        excerpt_id,
 5941                        (
 5942                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5943                            buffer.version().clone(),
 5944                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5945                        ),
 5946                    ))
 5947                }
 5948            })
 5949            .collect()
 5950    }
 5951
 5952    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5953        TextLayoutDetails {
 5954            text_system: window.text_system().clone(),
 5955            editor_style: self.style.clone().unwrap(),
 5956            rem_size: window.rem_size(),
 5957            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 5958            visible_rows: self.visible_line_count(),
 5959            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5960        }
 5961    }
 5962
 5963    fn trigger_on_type_formatting(
 5964        &self,
 5965        input: String,
 5966        window: &mut Window,
 5967        cx: &mut Context<Self>,
 5968    ) -> Option<Task<Result<()>>> {
 5969        if input.chars().count() != 1 {
 5970            return None;
 5971        }
 5972
 5973        let project = self.project()?;
 5974        let position = self.selections.newest_anchor().head();
 5975        let (buffer, buffer_position) = self
 5976            .buffer
 5977            .read(cx)
 5978            .text_anchor_for_position(position, cx)?;
 5979
 5980        let settings = language_settings::language_settings(
 5981            buffer
 5982                .read(cx)
 5983                .language_at(buffer_position)
 5984                .map(|l| l.name()),
 5985            buffer.read(cx).file(),
 5986            cx,
 5987        );
 5988        if !settings.use_on_type_format {
 5989            return None;
 5990        }
 5991
 5992        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5993        // hence we do LSP request & edit on host side only — add formats to host's history.
 5994        let push_to_lsp_host_history = true;
 5995        // If this is not the host, append its history with new edits.
 5996        let push_to_client_history = project.read(cx).is_via_collab();
 5997
 5998        let on_type_formatting = project.update(cx, |project, cx| {
 5999            project.on_type_format(
 6000                buffer.clone(),
 6001                buffer_position,
 6002                input,
 6003                push_to_lsp_host_history,
 6004                cx,
 6005            )
 6006        });
 6007        Some(cx.spawn_in(window, async move |editor, cx| {
 6008            if let Some(transaction) = on_type_formatting.await? {
 6009                if push_to_client_history {
 6010                    buffer.update(cx, |buffer, _| {
 6011                        buffer.push_transaction(transaction, Instant::now());
 6012                        buffer.finalize_last_transaction();
 6013                    });
 6014                }
 6015                editor.update(cx, |editor, cx| {
 6016                    editor.refresh_document_highlights(cx);
 6017                })?;
 6018            }
 6019            Ok(())
 6020        }))
 6021    }
 6022
 6023    pub fn show_word_completions(
 6024        &mut self,
 6025        _: &ShowWordCompletions,
 6026        window: &mut Window,
 6027        cx: &mut Context<Self>,
 6028    ) {
 6029        self.open_or_update_completions_menu(
 6030            Some(CompletionsMenuSource::Words {
 6031                ignore_threshold: true,
 6032            }),
 6033            None,
 6034            false,
 6035            window,
 6036            cx,
 6037        );
 6038    }
 6039
 6040    pub fn show_completions(
 6041        &mut self,
 6042        _: &ShowCompletions,
 6043        window: &mut Window,
 6044        cx: &mut Context<Self>,
 6045    ) {
 6046        self.open_or_update_completions_menu(None, None, false, window, cx);
 6047    }
 6048
 6049    fn open_or_update_completions_menu(
 6050        &mut self,
 6051        requested_source: Option<CompletionsMenuSource>,
 6052        trigger: Option<String>,
 6053        trigger_in_words: bool,
 6054        window: &mut Window,
 6055        cx: &mut Context<Self>,
 6056    ) {
 6057        if self.pending_rename.is_some() {
 6058            return;
 6059        }
 6060
 6061        let completions_source = self
 6062            .context_menu
 6063            .borrow()
 6064            .as_ref()
 6065            .and_then(|menu| match menu {
 6066                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6067                CodeContextMenu::CodeActions(_) => None,
 6068            });
 6069
 6070        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6071
 6072        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6073        // inserted and selected. To handle that case, the start of the selection is used so that
 6074        // the menu starts with all choices.
 6075        let position = self
 6076            .selections
 6077            .newest_anchor()
 6078            .start
 6079            .bias_right(&multibuffer_snapshot);
 6080        if position.diff_base_anchor.is_some() {
 6081            return;
 6082        }
 6083        let buffer_position = multibuffer_snapshot.anchor_before(position);
 6084        let Some(buffer) = buffer_position
 6085            .text_anchor
 6086            .buffer_id
 6087            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 6088        else {
 6089            return;
 6090        };
 6091        let buffer_snapshot = buffer.read(cx).snapshot();
 6092
 6093        let menu_is_open = matches!(
 6094            self.context_menu.borrow().as_ref(),
 6095            Some(CodeContextMenu::Completions(_))
 6096        );
 6097
 6098        let language = buffer_snapshot
 6099            .language_at(buffer_position.text_anchor)
 6100            .map(|language| language.name());
 6101
 6102        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 6103        let completion_settings = language_settings.completions.clone();
 6104
 6105        let show_completions_on_input = self
 6106            .show_completions_on_input_override
 6107            .unwrap_or(language_settings.show_completions_on_input);
 6108        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6109            return;
 6110        }
 6111
 6112        let query: Option<Arc<String>> =
 6113            Self::completion_query(&multibuffer_snapshot, buffer_position)
 6114                .map(|query| query.into());
 6115
 6116        drop(multibuffer_snapshot);
 6117
 6118        // Hide the current completions menu when query is empty. Without this, cached
 6119        // completions from before the trigger char may be reused (#32774).
 6120        if query.is_none() && menu_is_open {
 6121            self.hide_context_menu(window, cx);
 6122        }
 6123
 6124        let mut ignore_word_threshold = false;
 6125        let provider = match requested_source {
 6126            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6127            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6128                ignore_word_threshold = ignore_threshold;
 6129                None
 6130            }
 6131            Some(CompletionsMenuSource::SnippetChoices)
 6132            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6133                log::error!("bug: SnippetChoices requested_source is not handled");
 6134                None
 6135            }
 6136        };
 6137
 6138        let sort_completions = provider
 6139            .as_ref()
 6140            .is_some_and(|provider| provider.sort_completions());
 6141
 6142        let filter_completions = provider
 6143            .as_ref()
 6144            .is_none_or(|provider| provider.filter_completions());
 6145
 6146        let was_snippets_only = matches!(
 6147            completions_source,
 6148            Some(CompletionsMenuSource::SnippetsOnly)
 6149        );
 6150
 6151        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6152            if filter_completions {
 6153                menu.filter(
 6154                    query.clone().unwrap_or_default(),
 6155                    buffer_position.text_anchor,
 6156                    &buffer,
 6157                    provider.clone(),
 6158                    window,
 6159                    cx,
 6160                );
 6161            }
 6162            // When `is_incomplete` is false, no need to re-query completions when the current query
 6163            // is a suffix of the initial query.
 6164            let was_complete = !menu.is_incomplete;
 6165            if was_complete && !was_snippets_only {
 6166                // If the new query is a suffix of the old query (typing more characters) and
 6167                // the previous result was complete, the existing completions can be filtered.
 6168                //
 6169                // Note that snippet completions are always complete.
 6170                let query_matches = match (&menu.initial_query, &query) {
 6171                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6172                    (None, _) => true,
 6173                    _ => false,
 6174                };
 6175                if query_matches {
 6176                    let position_matches = if menu.initial_position == position {
 6177                        true
 6178                    } else {
 6179                        let snapshot = self.buffer.read(cx).read(cx);
 6180                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6181                    };
 6182                    if position_matches {
 6183                        return;
 6184                    }
 6185                }
 6186            }
 6187        };
 6188
 6189        let Anchor {
 6190            excerpt_id: buffer_excerpt_id,
 6191            text_anchor: buffer_position,
 6192            ..
 6193        } = buffer_position;
 6194
 6195        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6196            buffer_snapshot.surrounding_word(buffer_position, None)
 6197        {
 6198            let word_to_exclude = buffer_snapshot
 6199                .text_for_range(word_range.clone())
 6200                .collect::<String>();
 6201            (
 6202                buffer_snapshot.anchor_before(word_range.start)
 6203                    ..buffer_snapshot.anchor_after(buffer_position),
 6204                Some(word_to_exclude),
 6205            )
 6206        } else {
 6207            (buffer_position..buffer_position, None)
 6208        };
 6209
 6210        let show_completion_documentation = buffer_snapshot
 6211            .settings_at(buffer_position, cx)
 6212            .show_completion_documentation;
 6213
 6214        // The document can be large, so stay in reasonable bounds when searching for words,
 6215        // otherwise completion pop-up might be slow to appear.
 6216        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6217        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6218        let min_word_search = buffer_snapshot.clip_point(
 6219            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6220            Bias::Left,
 6221        );
 6222        let max_word_search = buffer_snapshot.clip_point(
 6223            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6224            Bias::Right,
 6225        );
 6226        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6227            ..buffer_snapshot.point_to_offset(max_word_search);
 6228
 6229        let skip_digits = query
 6230            .as_ref()
 6231            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6232
 6233        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6234            trigger.as_ref().is_none_or(|trigger| {
 6235                provider.is_completion_trigger(
 6236                    &buffer,
 6237                    position.text_anchor,
 6238                    trigger,
 6239                    trigger_in_words,
 6240                    cx,
 6241                )
 6242            })
 6243        });
 6244
 6245        let provider_responses = if let Some(provider) = &provider
 6246            && load_provider_completions
 6247        {
 6248            let trigger_character =
 6249                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6250            let completion_context = CompletionContext {
 6251                trigger_kind: match &trigger_character {
 6252                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6253                    None => CompletionTriggerKind::INVOKED,
 6254                },
 6255                trigger_character,
 6256            };
 6257
 6258            provider.completions(
 6259                buffer_excerpt_id,
 6260                &buffer,
 6261                buffer_position,
 6262                completion_context,
 6263                window,
 6264                cx,
 6265            )
 6266        } else {
 6267            Task::ready(Ok(Vec::new()))
 6268        };
 6269
 6270        let load_word_completions = if !self.word_completions_enabled {
 6271            false
 6272        } else if requested_source
 6273            == Some(CompletionsMenuSource::Words {
 6274                ignore_threshold: true,
 6275            })
 6276        {
 6277            true
 6278        } else {
 6279            load_provider_completions
 6280                && completion_settings.words != WordsCompletionMode::Disabled
 6281                && (ignore_word_threshold || {
 6282                    let words_min_length = completion_settings.words_min_length;
 6283                    // check whether word has at least `words_min_length` characters
 6284                    let query_chars = query.iter().flat_map(|q| q.chars());
 6285                    query_chars.take(words_min_length).count() == words_min_length
 6286                })
 6287        };
 6288
 6289        let mut words = if load_word_completions {
 6290            cx.background_spawn({
 6291                let buffer_snapshot = buffer_snapshot.clone();
 6292                async move {
 6293                    buffer_snapshot.words_in_range(WordsQuery {
 6294                        fuzzy_contents: None,
 6295                        range: word_search_range,
 6296                        skip_digits,
 6297                    })
 6298                }
 6299            })
 6300        } else {
 6301            Task::ready(BTreeMap::default())
 6302        };
 6303
 6304        let snippets = if let Some(provider) = &provider
 6305            && provider.show_snippets()
 6306            && let Some(project) = self.project()
 6307        {
 6308            let char_classifier = buffer_snapshot
 6309                .char_classifier_at(buffer_position)
 6310                .scope_context(Some(CharScopeContext::Completion));
 6311            project.update(cx, |project, cx| {
 6312                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6313            })
 6314        } else {
 6315            Task::ready(Ok(CompletionResponse {
 6316                completions: Vec::new(),
 6317                display_options: Default::default(),
 6318                is_incomplete: false,
 6319            }))
 6320        };
 6321
 6322        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6323
 6324        let id = post_inc(&mut self.next_completion_id);
 6325        let task = cx.spawn_in(window, async move |editor, cx| {
 6326            let Ok(()) = editor.update(cx, |this, _| {
 6327                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6328            }) else {
 6329                return;
 6330            };
 6331
 6332            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6333            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6334            let mut completions = Vec::new();
 6335            let mut is_incomplete = false;
 6336            let mut display_options: Option<CompletionDisplayOptions> = None;
 6337            if let Some(provider_responses) = provider_responses.await.log_err()
 6338                && !provider_responses.is_empty()
 6339            {
 6340                for response in provider_responses {
 6341                    completions.extend(response.completions);
 6342                    is_incomplete = is_incomplete || response.is_incomplete;
 6343                    match display_options.as_mut() {
 6344                        None => {
 6345                            display_options = Some(response.display_options);
 6346                        }
 6347                        Some(options) => options.merge(&response.display_options),
 6348                    }
 6349                }
 6350                if completion_settings.words == WordsCompletionMode::Fallback {
 6351                    words = Task::ready(BTreeMap::default());
 6352                }
 6353            }
 6354            let display_options = display_options.unwrap_or_default();
 6355
 6356            let mut words = words.await;
 6357            if let Some(word_to_exclude) = &word_to_exclude {
 6358                words.remove(word_to_exclude);
 6359            }
 6360            for lsp_completion in &completions {
 6361                words.remove(&lsp_completion.new_text);
 6362            }
 6363            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6364                replace_range: word_replace_range.clone(),
 6365                new_text: word.clone(),
 6366                label: CodeLabel::plain(word, None),
 6367                match_start: None,
 6368                snippet_deduplication_key: None,
 6369                icon_path: None,
 6370                documentation: None,
 6371                source: CompletionSource::BufferWord {
 6372                    word_range,
 6373                    resolved: false,
 6374                },
 6375                insert_text_mode: Some(InsertTextMode::AS_IS),
 6376                confirm: None,
 6377            }));
 6378
 6379            completions.extend(
 6380                snippets
 6381                    .await
 6382                    .into_iter()
 6383                    .flat_map(|response| response.completions),
 6384            );
 6385
 6386            let menu = if completions.is_empty() {
 6387                None
 6388            } else {
 6389                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6390                    let languages = editor
 6391                        .workspace
 6392                        .as_ref()
 6393                        .and_then(|(workspace, _)| workspace.upgrade())
 6394                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6395                    let menu = CompletionsMenu::new(
 6396                        id,
 6397                        requested_source.unwrap_or(if load_provider_completions {
 6398                            CompletionsMenuSource::Normal
 6399                        } else {
 6400                            CompletionsMenuSource::SnippetsOnly
 6401                        }),
 6402                        sort_completions,
 6403                        show_completion_documentation,
 6404                        position,
 6405                        query.clone(),
 6406                        is_incomplete,
 6407                        buffer.clone(),
 6408                        completions.into(),
 6409                        editor
 6410                            .context_menu()
 6411                            .borrow_mut()
 6412                            .as_ref()
 6413                            .map(|menu| menu.primary_scroll_handle()),
 6414                        display_options,
 6415                        snippet_sort_order,
 6416                        languages,
 6417                        language,
 6418                        cx,
 6419                    );
 6420
 6421                    let query = if filter_completions { query } else { None };
 6422                    let matches_task = menu.do_async_filtering(
 6423                        query.unwrap_or_default(),
 6424                        buffer_position,
 6425                        &buffer,
 6426                        cx,
 6427                    );
 6428                    (menu, matches_task)
 6429                }) else {
 6430                    return;
 6431                };
 6432
 6433                let matches = matches_task.await;
 6434
 6435                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6436                    // Newer menu already set, so exit.
 6437                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6438                        editor.context_menu.borrow().as_ref()
 6439                        && prev_menu.id > id
 6440                    {
 6441                        return;
 6442                    };
 6443
 6444                    // Only valid to take prev_menu because either the new menu is immediately set
 6445                    // below, or the menu is hidden.
 6446                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6447                        editor.context_menu.borrow_mut().take()
 6448                    {
 6449                        let position_matches =
 6450                            if prev_menu.initial_position == menu.initial_position {
 6451                                true
 6452                            } else {
 6453                                let snapshot = editor.buffer.read(cx).read(cx);
 6454                                prev_menu.initial_position.to_offset(&snapshot)
 6455                                    == menu.initial_position.to_offset(&snapshot)
 6456                            };
 6457                        if position_matches {
 6458                            // Preserve markdown cache before `set_filter_results` because it will
 6459                            // try to populate the documentation cache.
 6460                            menu.preserve_markdown_cache(prev_menu);
 6461                        }
 6462                    };
 6463
 6464                    menu.set_filter_results(matches, provider, window, cx);
 6465                }) else {
 6466                    return;
 6467                };
 6468
 6469                menu.visible().then_some(menu)
 6470            };
 6471
 6472            editor
 6473                .update_in(cx, |editor, window, cx| {
 6474                    if editor.focus_handle.is_focused(window)
 6475                        && let Some(menu) = menu
 6476                    {
 6477                        *editor.context_menu.borrow_mut() =
 6478                            Some(CodeContextMenu::Completions(menu));
 6479
 6480                        crate::hover_popover::hide_hover(editor, cx);
 6481                        if editor.show_edit_predictions_in_menu() {
 6482                            editor.update_visible_edit_prediction(window, cx);
 6483                        } else {
 6484                            editor
 6485                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6486                        }
 6487
 6488                        cx.notify();
 6489                        return;
 6490                    }
 6491
 6492                    if editor.completion_tasks.len() <= 1 {
 6493                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6494                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6495                        // If it was already hidden and we don't show edit predictions in the menu,
 6496                        // we should also show the edit prediction when available.
 6497                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6498                            editor.update_visible_edit_prediction(window, cx);
 6499                        }
 6500                    }
 6501                })
 6502                .ok();
 6503        });
 6504
 6505        self.completion_tasks.push((id, task));
 6506    }
 6507
 6508    #[cfg(any(test, feature = "test-support"))]
 6509    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6510        let menu = self.context_menu.borrow();
 6511        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6512            let completions = menu.completions.borrow();
 6513            Some(completions.to_vec())
 6514        } else {
 6515            None
 6516        }
 6517    }
 6518
 6519    pub fn with_completions_menu_matching_id<R>(
 6520        &self,
 6521        id: CompletionId,
 6522        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6523    ) -> R {
 6524        let mut context_menu = self.context_menu.borrow_mut();
 6525        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6526            return f(None);
 6527        };
 6528        if completions_menu.id != id {
 6529            return f(None);
 6530        }
 6531        f(Some(completions_menu))
 6532    }
 6533
 6534    pub fn confirm_completion(
 6535        &mut self,
 6536        action: &ConfirmCompletion,
 6537        window: &mut Window,
 6538        cx: &mut Context<Self>,
 6539    ) -> Option<Task<Result<()>>> {
 6540        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6541        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6542    }
 6543
 6544    pub fn confirm_completion_insert(
 6545        &mut self,
 6546        _: &ConfirmCompletionInsert,
 6547        window: &mut Window,
 6548        cx: &mut Context<Self>,
 6549    ) -> Option<Task<Result<()>>> {
 6550        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6551        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6552    }
 6553
 6554    pub fn confirm_completion_replace(
 6555        &mut self,
 6556        _: &ConfirmCompletionReplace,
 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(None, CompletionIntent::CompleteWithReplace, window, cx)
 6562    }
 6563
 6564    pub fn compose_completion(
 6565        &mut self,
 6566        action: &ComposeCompletion,
 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(action.item_ix, CompletionIntent::Compose, window, cx)
 6572    }
 6573
 6574    fn do_completion(
 6575        &mut self,
 6576        item_ix: Option<usize>,
 6577        intent: CompletionIntent,
 6578        window: &mut Window,
 6579        cx: &mut Context<Editor>,
 6580    ) -> Option<Task<Result<()>>> {
 6581        use language::ToOffset as _;
 6582
 6583        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6584        else {
 6585            return None;
 6586        };
 6587
 6588        let candidate_id = {
 6589            let entries = completions_menu.entries.borrow();
 6590            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6591            if self.show_edit_predictions_in_menu() {
 6592                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6593            }
 6594            mat.candidate_id
 6595        };
 6596
 6597        let completion = completions_menu
 6598            .completions
 6599            .borrow()
 6600            .get(candidate_id)?
 6601            .clone();
 6602        cx.stop_propagation();
 6603
 6604        let buffer_handle = completions_menu.buffer.clone();
 6605
 6606        let CompletionEdit {
 6607            new_text,
 6608            snippet,
 6609            replace_range,
 6610        } = process_completion_for_edit(
 6611            &completion,
 6612            intent,
 6613            &buffer_handle,
 6614            &completions_menu.initial_position.text_anchor,
 6615            cx,
 6616        );
 6617
 6618        let buffer = buffer_handle.read(cx);
 6619        let snapshot = self.buffer.read(cx).snapshot(cx);
 6620        let newest_anchor = self.selections.newest_anchor();
 6621        let replace_range_multibuffer = {
 6622            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6623            excerpt.map_range_from_buffer(replace_range.clone())
 6624        };
 6625        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6626            return None;
 6627        }
 6628
 6629        let old_text = buffer
 6630            .text_for_range(replace_range.clone())
 6631            .collect::<String>();
 6632        let lookbehind = newest_anchor
 6633            .start
 6634            .text_anchor
 6635            .to_offset(buffer)
 6636            .saturating_sub(replace_range.start.0);
 6637        let lookahead = replace_range
 6638            .end
 6639            .0
 6640            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6641        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6642        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6643
 6644        let selections = self
 6645            .selections
 6646            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6647        let mut ranges = Vec::new();
 6648        let mut all_commit_ranges = Vec::new();
 6649        let mut linked_edits = LinkedEdits::new();
 6650
 6651        let text: Arc<str> = new_text.clone().into();
 6652        for selection in &selections {
 6653            let range = if selection.id == newest_anchor.id {
 6654                replace_range_multibuffer.clone()
 6655            } else {
 6656                let mut range = selection.range();
 6657
 6658                // if prefix is present, don't duplicate it
 6659                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6660                    range.start = range.start.saturating_sub_usize(lookbehind);
 6661
 6662                    // if suffix is also present, mimic the newest cursor and replace it
 6663                    if selection.id != newest_anchor.id
 6664                        && snapshot.contains_str_at(range.end, suffix)
 6665                    {
 6666                        range.end += lookahead;
 6667                    }
 6668                }
 6669                range
 6670            };
 6671
 6672            ranges.push(range.clone());
 6673
 6674            let start_anchor = snapshot.anchor_before(range.start);
 6675            let end_anchor = snapshot.anchor_after(range.end);
 6676            let anchor_range = start_anchor.text_anchor..end_anchor.text_anchor;
 6677            all_commit_ranges.push(anchor_range.clone());
 6678
 6679            if !self.linked_edit_ranges.is_empty() {
 6680                linked_edits.push(&self, anchor_range, text.clone(), cx);
 6681            }
 6682        }
 6683
 6684        let common_prefix_len = old_text
 6685            .chars()
 6686            .zip(new_text.chars())
 6687            .take_while(|(a, b)| a == b)
 6688            .map(|(a, _)| a.len_utf8())
 6689            .sum::<usize>();
 6690
 6691        cx.emit(EditorEvent::InputHandled {
 6692            utf16_range_to_replace: None,
 6693            text: new_text[common_prefix_len..].into(),
 6694        });
 6695
 6696        self.transact(window, cx, |editor, window, cx| {
 6697            if let Some(mut snippet) = snippet {
 6698                snippet.text = new_text.to_string();
 6699                editor
 6700                    .insert_snippet(&ranges, snippet, window, cx)
 6701                    .log_err();
 6702            } else {
 6703                editor.buffer.update(cx, |multi_buffer, cx| {
 6704                    let auto_indent = match completion.insert_text_mode {
 6705                        Some(InsertTextMode::AS_IS) => None,
 6706                        _ => editor.autoindent_mode.clone(),
 6707                    };
 6708                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6709                    multi_buffer.edit(edits, auto_indent, cx);
 6710                });
 6711            }
 6712            linked_edits.apply(cx);
 6713            editor.refresh_edit_prediction(true, false, window, cx);
 6714        });
 6715        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6716
 6717        let show_new_completions_on_confirm = completion
 6718            .confirm
 6719            .as_ref()
 6720            .is_some_and(|confirm| confirm(intent, window, cx));
 6721        if show_new_completions_on_confirm {
 6722            self.open_or_update_completions_menu(None, None, false, window, cx);
 6723        }
 6724
 6725        let provider = self.completion_provider.as_ref()?;
 6726
 6727        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6728        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6729            let CompletionSource::Lsp {
 6730                lsp_completion,
 6731                server_id,
 6732                ..
 6733            } = &completion.source
 6734            else {
 6735                return None;
 6736            };
 6737            let lsp_command = lsp_completion.command.as_ref()?;
 6738            let available_commands = lsp_store
 6739                .read(cx)
 6740                .lsp_server_capabilities
 6741                .get(server_id)
 6742                .and_then(|server_capabilities| {
 6743                    server_capabilities
 6744                        .execute_command_provider
 6745                        .as_ref()
 6746                        .map(|options| options.commands.as_slice())
 6747                })?;
 6748            if available_commands.contains(&lsp_command.command) {
 6749                Some(CodeAction {
 6750                    server_id: *server_id,
 6751                    range: language::Anchor::MIN..language::Anchor::MIN,
 6752                    lsp_action: LspAction::Command(lsp_command.clone()),
 6753                    resolved: false,
 6754                })
 6755            } else {
 6756                None
 6757            }
 6758        });
 6759
 6760        drop(completion);
 6761        let apply_edits = provider.apply_additional_edits_for_completion(
 6762            buffer_handle.clone(),
 6763            completions_menu.completions.clone(),
 6764            candidate_id,
 6765            true,
 6766            all_commit_ranges,
 6767            cx,
 6768        );
 6769
 6770        let editor_settings = EditorSettings::get_global(cx);
 6771        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6772            // After the code completion is finished, users often want to know what signatures are needed.
 6773            // so we should automatically call signature_help
 6774            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6775        }
 6776
 6777        Some(cx.spawn_in(window, async move |editor, cx| {
 6778            apply_edits.await?;
 6779
 6780            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6781                let title = command.lsp_action.title().to_owned();
 6782                let project_transaction = lsp_store
 6783                    .update(cx, |lsp_store, cx| {
 6784                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6785                    })
 6786                    .await
 6787                    .context("applying post-completion command")?;
 6788                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6789                    Self::open_project_transaction(
 6790                        &editor,
 6791                        workspace.downgrade(),
 6792                        project_transaction,
 6793                        title,
 6794                        cx,
 6795                    )
 6796                    .await?;
 6797                }
 6798            }
 6799
 6800            Ok(())
 6801        }))
 6802    }
 6803
 6804    pub fn toggle_code_actions(
 6805        &mut self,
 6806        action: &ToggleCodeActions,
 6807        window: &mut Window,
 6808        cx: &mut Context<Self>,
 6809    ) {
 6810        let quick_launch = action.quick_launch;
 6811        let mut context_menu = self.context_menu.borrow_mut();
 6812        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6813            if code_actions.deployed_from == action.deployed_from {
 6814                // Toggle if we're selecting the same one
 6815                *context_menu = None;
 6816                cx.notify();
 6817                return;
 6818            } else {
 6819                // Otherwise, clear it and start a new one
 6820                *context_menu = None;
 6821                cx.notify();
 6822            }
 6823        }
 6824        drop(context_menu);
 6825        let snapshot = self.snapshot(window, cx);
 6826        let deployed_from = action.deployed_from.clone();
 6827        let action = action.clone();
 6828        self.completion_tasks.clear();
 6829        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6830
 6831        let multibuffer_point = match &action.deployed_from {
 6832            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6833                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6834            }
 6835            _ => self
 6836                .selections
 6837                .newest::<Point>(&snapshot.display_snapshot)
 6838                .head(),
 6839        };
 6840        let Some((buffer, buffer_row)) = snapshot
 6841            .buffer_snapshot()
 6842            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6843            .and_then(|(buffer_snapshot, range)| {
 6844                self.buffer()
 6845                    .read(cx)
 6846                    .buffer(buffer_snapshot.remote_id())
 6847                    .map(|buffer| (buffer, range.start.row))
 6848            })
 6849        else {
 6850            return;
 6851        };
 6852        let buffer_id = buffer.read(cx).remote_id();
 6853        let tasks = self
 6854            .runnables
 6855            .runnables((buffer_id, buffer_row))
 6856            .map(|t| Arc::new(t.to_owned()));
 6857
 6858        if !self.focus_handle.is_focused(window) {
 6859            return;
 6860        }
 6861        let project = self.project.clone();
 6862
 6863        let code_actions_task = match deployed_from {
 6864            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6865            _ => self.code_actions(buffer_row, window, cx),
 6866        };
 6867
 6868        let runnable_task = match deployed_from {
 6869            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6870            _ => {
 6871                let mut task_context_task = Task::ready(None);
 6872                if let Some(tasks) = &tasks
 6873                    && let Some(project) = project
 6874                {
 6875                    task_context_task =
 6876                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6877                }
 6878
 6879                cx.spawn_in(window, {
 6880                    let buffer = buffer.clone();
 6881                    async move |editor, cx| {
 6882                        let task_context = task_context_task.await;
 6883
 6884                        let resolved_tasks =
 6885                            tasks
 6886                                .zip(task_context.clone())
 6887                                .map(|(tasks, task_context)| ResolvedTasks {
 6888                                    templates: tasks.resolve(&task_context).collect(),
 6889                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6890                                        multibuffer_point.row,
 6891                                        tasks.column,
 6892                                    )),
 6893                                });
 6894                        let debug_scenarios = editor
 6895                            .update(cx, |editor, cx| {
 6896                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6897                            })?
 6898                            .await;
 6899                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6900                    }
 6901                })
 6902            }
 6903        };
 6904
 6905        cx.spawn_in(window, async move |editor, cx| {
 6906            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6907            let code_actions = code_actions_task.await;
 6908            let spawn_straight_away = quick_launch
 6909                && resolved_tasks
 6910                    .as_ref()
 6911                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6912                && code_actions
 6913                    .as_ref()
 6914                    .is_none_or(|actions| actions.is_empty())
 6915                && debug_scenarios.is_empty();
 6916
 6917            editor.update_in(cx, |editor, window, cx| {
 6918                crate::hover_popover::hide_hover(editor, cx);
 6919                let actions = CodeActionContents::new(
 6920                    resolved_tasks,
 6921                    code_actions,
 6922                    debug_scenarios,
 6923                    task_context.unwrap_or_default(),
 6924                );
 6925
 6926                // Don't show the menu if there are no actions available
 6927                if actions.is_empty() {
 6928                    cx.notify();
 6929                    return Task::ready(Ok(()));
 6930                }
 6931
 6932                *editor.context_menu.borrow_mut() =
 6933                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6934                        buffer,
 6935                        actions,
 6936                        selected_item: Default::default(),
 6937                        scroll_handle: UniformListScrollHandle::default(),
 6938                        deployed_from,
 6939                    }));
 6940                cx.notify();
 6941                if spawn_straight_away
 6942                    && let Some(task) = editor.confirm_code_action(
 6943                        &ConfirmCodeAction { item_ix: Some(0) },
 6944                        window,
 6945                        cx,
 6946                    )
 6947                {
 6948                    return task;
 6949                }
 6950
 6951                Task::ready(Ok(()))
 6952            })
 6953        })
 6954        .detach_and_log_err(cx);
 6955    }
 6956
 6957    fn debug_scenarios(
 6958        &mut self,
 6959        resolved_tasks: &Option<ResolvedTasks>,
 6960        buffer: &Entity<Buffer>,
 6961        cx: &mut App,
 6962    ) -> Task<Vec<task::DebugScenario>> {
 6963        maybe!({
 6964            let project = self.project()?;
 6965            let dap_store = project.read(cx).dap_store();
 6966            let mut scenarios = vec![];
 6967            let resolved_tasks = resolved_tasks.as_ref()?;
 6968            let buffer = buffer.read(cx);
 6969            let language = buffer.language()?;
 6970            let file = buffer.file();
 6971            let debug_adapter = language_settings(language.name().into(), file, cx)
 6972                .debuggers
 6973                .first()
 6974                .map(SharedString::from)
 6975                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6976
 6977            dap_store.update(cx, |dap_store, cx| {
 6978                for (_, task) in &resolved_tasks.templates {
 6979                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6980                        task.original_task().clone(),
 6981                        debug_adapter.clone().into(),
 6982                        task.display_label().to_owned().into(),
 6983                        cx,
 6984                    );
 6985                    scenarios.push(maybe_scenario);
 6986                }
 6987            });
 6988            Some(cx.background_spawn(async move {
 6989                futures::future::join_all(scenarios)
 6990                    .await
 6991                    .into_iter()
 6992                    .flatten()
 6993                    .collect::<Vec<_>>()
 6994            }))
 6995        })
 6996        .unwrap_or_else(|| Task::ready(vec![]))
 6997    }
 6998
 6999    fn code_actions(
 7000        &mut self,
 7001        buffer_row: u32,
 7002        window: &mut Window,
 7003        cx: &mut Context<Self>,
 7004    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 7005        let mut task = self.code_actions_task.take();
 7006        cx.spawn_in(window, async move |editor, cx| {
 7007            while let Some(prev_task) = task {
 7008                prev_task.await.log_err();
 7009                task = editor
 7010                    .update(cx, |this, _| this.code_actions_task.take())
 7011                    .ok()?;
 7012            }
 7013
 7014            editor
 7015                .update(cx, |editor, cx| {
 7016                    editor
 7017                        .available_code_actions
 7018                        .clone()
 7019                        .and_then(|(location, code_actions)| {
 7020                            let snapshot = location.buffer.read(cx).snapshot();
 7021                            let point_range = location.range.to_point(&snapshot);
 7022                            let point_range = point_range.start.row..=point_range.end.row;
 7023                            if point_range.contains(&buffer_row) {
 7024                                Some(code_actions)
 7025                            } else {
 7026                                None
 7027                            }
 7028                        })
 7029                })
 7030                .ok()
 7031                .flatten()
 7032        })
 7033    }
 7034
 7035    pub fn confirm_code_action(
 7036        &mut self,
 7037        action: &ConfirmCodeAction,
 7038        window: &mut Window,
 7039        cx: &mut Context<Self>,
 7040    ) -> Option<Task<Result<()>>> {
 7041        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7042
 7043        let actions_menu =
 7044            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7045                menu
 7046            } else {
 7047                return None;
 7048            };
 7049
 7050        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7051        let action = actions_menu.actions.get(action_ix)?;
 7052        let title = action.label();
 7053        let buffer = actions_menu.buffer;
 7054        let workspace = self.workspace()?;
 7055
 7056        match action {
 7057            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7058                workspace.update(cx, |workspace, cx| {
 7059                    workspace.schedule_resolved_task(
 7060                        task_source_kind,
 7061                        resolved_task,
 7062                        false,
 7063                        window,
 7064                        cx,
 7065                    );
 7066
 7067                    Some(Task::ready(Ok(())))
 7068                })
 7069            }
 7070            CodeActionsItem::CodeAction {
 7071                excerpt_id,
 7072                action,
 7073                provider,
 7074            } => {
 7075                let apply_code_action =
 7076                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 7077                let workspace = workspace.downgrade();
 7078                Some(cx.spawn_in(window, async move |editor, cx| {
 7079                    let project_transaction = apply_code_action.await?;
 7080                    Self::open_project_transaction(
 7081                        &editor,
 7082                        workspace,
 7083                        project_transaction,
 7084                        title,
 7085                        cx,
 7086                    )
 7087                    .await
 7088                }))
 7089            }
 7090            CodeActionsItem::DebugScenario(scenario) => {
 7091                let context = actions_menu.actions.context.into();
 7092
 7093                workspace.update(cx, |workspace, cx| {
 7094                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7095                    workspace.start_debug_session(
 7096                        scenario,
 7097                        context,
 7098                        Some(buffer),
 7099                        None,
 7100                        window,
 7101                        cx,
 7102                    );
 7103                });
 7104                Some(Task::ready(Ok(())))
 7105            }
 7106        }
 7107    }
 7108
 7109    fn open_transaction_for_hidden_buffers(
 7110        workspace: Entity<Workspace>,
 7111        transaction: ProjectTransaction,
 7112        title: String,
 7113        window: &mut Window,
 7114        cx: &mut Context<Self>,
 7115    ) {
 7116        if transaction.0.is_empty() {
 7117            return;
 7118        }
 7119
 7120        let edited_buffers_already_open = {
 7121            let other_editors: Vec<Entity<Editor>> = workspace
 7122                .read(cx)
 7123                .panes()
 7124                .iter()
 7125                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7126                .filter(|editor| editor.entity_id() != cx.entity_id())
 7127                .collect();
 7128
 7129            transaction.0.keys().all(|buffer| {
 7130                other_editors.iter().any(|editor| {
 7131                    let multi_buffer = editor.read(cx).buffer();
 7132                    multi_buffer.read(cx).is_singleton()
 7133                        && multi_buffer
 7134                            .read(cx)
 7135                            .as_singleton()
 7136                            .map_or(false, |singleton| {
 7137                                singleton.entity_id() == buffer.entity_id()
 7138                            })
 7139                })
 7140            })
 7141        };
 7142        if !edited_buffers_already_open {
 7143            let workspace = workspace.downgrade();
 7144            cx.defer_in(window, move |_, window, cx| {
 7145                cx.spawn_in(window, async move |editor, cx| {
 7146                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7147                        .await
 7148                        .ok()
 7149                })
 7150                .detach();
 7151            });
 7152        }
 7153    }
 7154
 7155    pub async fn open_project_transaction(
 7156        editor: &WeakEntity<Editor>,
 7157        workspace: WeakEntity<Workspace>,
 7158        transaction: ProjectTransaction,
 7159        title: String,
 7160        cx: &mut AsyncWindowContext,
 7161    ) -> Result<()> {
 7162        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7163        cx.update(|_, cx| {
 7164            entries.sort_unstable_by_key(|(buffer, _)| {
 7165                buffer.read(cx).file().map(|f| f.path().clone())
 7166            });
 7167        })?;
 7168        if entries.is_empty() {
 7169            return Ok(());
 7170        }
 7171
 7172        // If the project transaction's edits are all contained within this editor, then
 7173        // avoid opening a new editor to display them.
 7174
 7175        if let [(buffer, transaction)] = &*entries {
 7176            let excerpt = editor.update(cx, |editor, cx| {
 7177                editor
 7178                    .buffer()
 7179                    .read(cx)
 7180                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 7181            })?;
 7182            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 7183                && excerpted_buffer == *buffer
 7184            {
 7185                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7186                    let excerpt_range = excerpt_range.to_offset(buffer);
 7187                    buffer
 7188                        .edited_ranges_for_transaction::<usize>(transaction)
 7189                        .all(|range| {
 7190                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7191                        })
 7192                });
 7193
 7194                if all_edits_within_excerpt {
 7195                    return Ok(());
 7196                }
 7197            }
 7198        }
 7199
 7200        let mut ranges_to_highlight = Vec::new();
 7201        let excerpt_buffer = cx.new(|cx| {
 7202            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7203            for (buffer_handle, transaction) in &entries {
 7204                let edited_ranges = buffer_handle
 7205                    .read(cx)
 7206                    .edited_ranges_for_transaction::<Point>(transaction)
 7207                    .collect::<Vec<_>>();
 7208                let (ranges, _) = multibuffer.set_excerpts_for_path(
 7209                    PathKey::for_buffer(buffer_handle, cx),
 7210                    buffer_handle.clone(),
 7211                    edited_ranges,
 7212                    multibuffer_context_lines(cx),
 7213                    cx,
 7214                );
 7215
 7216                ranges_to_highlight.extend(ranges);
 7217            }
 7218            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7219            multibuffer
 7220        });
 7221
 7222        workspace.update_in(cx, |workspace, window, cx| {
 7223            let project = workspace.project().clone();
 7224            let editor =
 7225                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7226            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7227            editor.update(cx, |editor, cx| {
 7228                editor.highlight_background(
 7229                    HighlightKey::Editor,
 7230                    &ranges_to_highlight,
 7231                    |_, theme| theme.colors().editor_highlighted_line_background,
 7232                    cx,
 7233                );
 7234            });
 7235        })?;
 7236
 7237        Ok(())
 7238    }
 7239
 7240    pub fn clear_code_action_providers(&mut self) {
 7241        self.code_action_providers.clear();
 7242        self.available_code_actions.take();
 7243    }
 7244
 7245    pub fn add_code_action_provider(
 7246        &mut self,
 7247        provider: Rc<dyn CodeActionProvider>,
 7248        window: &mut Window,
 7249        cx: &mut Context<Self>,
 7250    ) {
 7251        if self
 7252            .code_action_providers
 7253            .iter()
 7254            .any(|existing_provider| existing_provider.id() == provider.id())
 7255        {
 7256            return;
 7257        }
 7258
 7259        self.code_action_providers.push(provider);
 7260        self.refresh_code_actions(window, cx);
 7261    }
 7262
 7263    pub fn remove_code_action_provider(
 7264        &mut self,
 7265        id: Arc<str>,
 7266        window: &mut Window,
 7267        cx: &mut Context<Self>,
 7268    ) {
 7269        self.code_action_providers
 7270            .retain(|provider| provider.id() != id);
 7271        self.refresh_code_actions(window, cx);
 7272    }
 7273
 7274    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7275        !self.code_action_providers.is_empty()
 7276            && EditorSettings::get_global(cx).toolbar.code_actions
 7277    }
 7278
 7279    pub fn has_available_code_actions(&self) -> bool {
 7280        self.available_code_actions
 7281            .as_ref()
 7282            .is_some_and(|(_, actions)| !actions.is_empty())
 7283    }
 7284
 7285    fn render_inline_code_actions(
 7286        &self,
 7287        icon_size: ui::IconSize,
 7288        display_row: DisplayRow,
 7289        is_active: bool,
 7290        cx: &mut Context<Self>,
 7291    ) -> AnyElement {
 7292        let show_tooltip = !self.context_menu_visible();
 7293        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7294            .icon_size(icon_size)
 7295            .shape(ui::IconButtonShape::Square)
 7296            .icon_color(ui::Color::Hidden)
 7297            .toggle_state(is_active)
 7298            .when(show_tooltip, |this| {
 7299                this.tooltip({
 7300                    let focus_handle = self.focus_handle.clone();
 7301                    move |_window, cx| {
 7302                        Tooltip::for_action_in(
 7303                            "Toggle Code Actions",
 7304                            &ToggleCodeActions {
 7305                                deployed_from: None,
 7306                                quick_launch: false,
 7307                            },
 7308                            &focus_handle,
 7309                            cx,
 7310                        )
 7311                    }
 7312                })
 7313            })
 7314            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7315                window.focus(&editor.focus_handle(cx), cx);
 7316                editor.toggle_code_actions(
 7317                    &crate::actions::ToggleCodeActions {
 7318                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7319                            display_row,
 7320                        )),
 7321                        quick_launch: false,
 7322                    },
 7323                    window,
 7324                    cx,
 7325                );
 7326            }))
 7327            .into_any_element()
 7328    }
 7329
 7330    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7331        &self.context_menu
 7332    }
 7333
 7334    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7335        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7336            cx.background_executor()
 7337                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7338                .await;
 7339
 7340            let (start_buffer, start, _, end, newest_selection) = this
 7341                .update(cx, |this, cx| {
 7342                    let newest_selection = this.selections.newest_anchor().clone();
 7343                    if newest_selection.head().diff_base_anchor.is_some() {
 7344                        return None;
 7345                    }
 7346                    let display_snapshot = this.display_snapshot(cx);
 7347                    let newest_selection_adjusted =
 7348                        this.selections.newest_adjusted(&display_snapshot);
 7349                    let buffer = this.buffer.read(cx);
 7350
 7351                    let (start_buffer, start) =
 7352                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7353                    let (end_buffer, end) =
 7354                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7355
 7356                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7357                })?
 7358                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7359                .context(
 7360                    "Expected selection to lie in a single buffer when refreshing code actions",
 7361                )?;
 7362            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7363                let providers = this.code_action_providers.clone();
 7364                let tasks = this
 7365                    .code_action_providers
 7366                    .iter()
 7367                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7368                    .collect::<Vec<_>>();
 7369                (providers, tasks)
 7370            })?;
 7371
 7372            let mut actions = Vec::new();
 7373            for (provider, provider_actions) in
 7374                providers.into_iter().zip(future::join_all(tasks).await)
 7375            {
 7376                if let Some(provider_actions) = provider_actions.log_err() {
 7377                    actions.extend(provider_actions.into_iter().map(|action| {
 7378                        AvailableCodeAction {
 7379                            excerpt_id: newest_selection.start.excerpt_id,
 7380                            action,
 7381                            provider: provider.clone(),
 7382                        }
 7383                    }));
 7384                }
 7385            }
 7386
 7387            this.update(cx, |this, cx| {
 7388                this.available_code_actions = if actions.is_empty() {
 7389                    None
 7390                } else {
 7391                    Some((
 7392                        Location {
 7393                            buffer: start_buffer,
 7394                            range: start..end,
 7395                        },
 7396                        actions.into(),
 7397                    ))
 7398                };
 7399                cx.notify();
 7400            })
 7401        }));
 7402    }
 7403
 7404    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7405        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7406            self.show_git_blame_inline = false;
 7407
 7408            self.show_git_blame_inline_delay_task =
 7409                Some(cx.spawn_in(window, async move |this, cx| {
 7410                    cx.background_executor().timer(delay).await;
 7411
 7412                    this.update(cx, |this, cx| {
 7413                        this.show_git_blame_inline = true;
 7414                        cx.notify();
 7415                    })
 7416                    .log_err();
 7417                }));
 7418        }
 7419    }
 7420
 7421    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7422        let snapshot = self.snapshot(window, cx);
 7423        let cursor = self
 7424            .selections
 7425            .newest::<Point>(&snapshot.display_snapshot)
 7426            .head();
 7427        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7428        else {
 7429            return;
 7430        };
 7431
 7432        if self.blame.is_none() {
 7433            self.start_git_blame(true, window, cx);
 7434        }
 7435        let Some(blame) = self.blame.as_ref() else {
 7436            return;
 7437        };
 7438
 7439        let row_info = RowInfo {
 7440            buffer_id: Some(buffer.remote_id()),
 7441            buffer_row: Some(point.row),
 7442            ..Default::default()
 7443        };
 7444        let Some((buffer, blame_entry)) = blame
 7445            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7446            .flatten()
 7447        else {
 7448            return;
 7449        };
 7450
 7451        let anchor = self.selections.newest_anchor().head();
 7452        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7453        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7454            self.show_blame_popover(
 7455                buffer,
 7456                &blame_entry,
 7457                position + last_bounds.origin,
 7458                true,
 7459                cx,
 7460            );
 7461        };
 7462    }
 7463
 7464    fn show_blame_popover(
 7465        &mut self,
 7466        buffer: BufferId,
 7467        blame_entry: &BlameEntry,
 7468        position: gpui::Point<Pixels>,
 7469        ignore_timeout: bool,
 7470        cx: &mut Context<Self>,
 7471    ) {
 7472        if let Some(state) = &mut self.inline_blame_popover {
 7473            state.hide_task.take();
 7474        } else {
 7475            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7476            let blame_entry = blame_entry.clone();
 7477            let show_task = cx.spawn(async move |editor, cx| {
 7478                if !ignore_timeout {
 7479                    cx.background_executor()
 7480                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7481                        .await;
 7482                }
 7483                editor
 7484                    .update(cx, |editor, cx| {
 7485                        editor.inline_blame_popover_show_task.take();
 7486                        let Some(blame) = editor.blame.as_ref() else {
 7487                            return;
 7488                        };
 7489                        let blame = blame.read(cx);
 7490                        let details = blame.details_for_entry(buffer, &blame_entry);
 7491                        let markdown = cx.new(|cx| {
 7492                            Markdown::new(
 7493                                details
 7494                                    .as_ref()
 7495                                    .map(|message| message.message.clone())
 7496                                    .unwrap_or_default(),
 7497                                None,
 7498                                None,
 7499                                cx,
 7500                            )
 7501                        });
 7502                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7503                            position,
 7504                            hide_task: None,
 7505                            popover_bounds: None,
 7506                            popover_state: InlineBlamePopoverState {
 7507                                scroll_handle: ScrollHandle::new(),
 7508                                commit_message: details,
 7509                                markdown,
 7510                            },
 7511                            keyboard_grace: ignore_timeout,
 7512                        });
 7513                        cx.notify();
 7514                    })
 7515                    .ok();
 7516            });
 7517            self.inline_blame_popover_show_task = Some(show_task);
 7518        }
 7519    }
 7520
 7521    pub fn has_mouse_context_menu(&self) -> bool {
 7522        self.mouse_context_menu.is_some()
 7523    }
 7524
 7525    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7526        self.inline_blame_popover_show_task.take();
 7527        if let Some(state) = &mut self.inline_blame_popover {
 7528            let hide_task = cx.spawn(async move |editor, cx| {
 7529                if !ignore_timeout {
 7530                    cx.background_executor()
 7531                        .timer(std::time::Duration::from_millis(100))
 7532                        .await;
 7533                }
 7534                editor
 7535                    .update(cx, |editor, cx| {
 7536                        editor.inline_blame_popover.take();
 7537                        cx.notify();
 7538                    })
 7539                    .ok();
 7540            });
 7541            state.hide_task = Some(hide_task);
 7542            true
 7543        } else {
 7544            false
 7545        }
 7546    }
 7547
 7548    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7549        if self.pending_rename.is_some() {
 7550            return None;
 7551        }
 7552
 7553        let provider = self.semantics_provider.clone()?;
 7554        let buffer = self.buffer.read(cx);
 7555        let newest_selection = self.selections.newest_anchor().clone();
 7556        let cursor_position = newest_selection.head();
 7557        let (cursor_buffer, cursor_buffer_position) =
 7558            buffer.text_anchor_for_position(cursor_position, cx)?;
 7559        let (tail_buffer, tail_buffer_position) =
 7560            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7561        if cursor_buffer != tail_buffer {
 7562            return None;
 7563        }
 7564
 7565        let snapshot = cursor_buffer.read(cx).snapshot();
 7566        let word_ranges = cx.background_spawn(async move {
 7567            // this might look odd to put on the background thread, but
 7568            // `surrounding_word` can be quite expensive as it calls into
 7569            // tree-sitter language scopes
 7570            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7571            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7572            (start_word_range, end_word_range)
 7573        });
 7574
 7575        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7576        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7577            let (start_word_range, end_word_range) = word_ranges.await;
 7578            if start_word_range != end_word_range {
 7579                this.update(cx, |this, cx| {
 7580                    this.document_highlights_task.take();
 7581                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7582                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7583                })
 7584                .ok();
 7585                return;
 7586            }
 7587            cx.background_executor()
 7588                .timer(Duration::from_millis(debounce))
 7589                .await;
 7590
 7591            let highlights = if let Some(highlights) = cx.update(|cx| {
 7592                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7593            }) {
 7594                highlights.await.log_err()
 7595            } else {
 7596                None
 7597            };
 7598
 7599            if let Some(highlights) = highlights {
 7600                this.update(cx, |this, cx| {
 7601                    if this.pending_rename.is_some() {
 7602                        return;
 7603                    }
 7604
 7605                    let buffer = this.buffer.read(cx);
 7606                    if buffer
 7607                        .text_anchor_for_position(cursor_position, cx)
 7608                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7609                    {
 7610                        return;
 7611                    }
 7612
 7613                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7614                    let mut write_ranges = Vec::new();
 7615                    let mut read_ranges = Vec::new();
 7616                    for highlight in highlights {
 7617                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7618                        for (excerpt_id, _, excerpt_range) in
 7619                            buffer.excerpts_for_buffer(buffer_id, cx)
 7620                        {
 7621                            let start = highlight
 7622                                .range
 7623                                .start
 7624                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7625                            let end = highlight
 7626                                .range
 7627                                .end
 7628                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7629                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7630                                continue;
 7631                            }
 7632
 7633                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7634                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7635                                write_ranges.push(range);
 7636                            } else {
 7637                                read_ranges.push(range);
 7638                            }
 7639                        }
 7640                    }
 7641
 7642                    this.highlight_background(
 7643                        HighlightKey::DocumentHighlightRead,
 7644                        &read_ranges,
 7645                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7646                        cx,
 7647                    );
 7648                    this.highlight_background(
 7649                        HighlightKey::DocumentHighlightWrite,
 7650                        &write_ranges,
 7651                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7652                        cx,
 7653                    );
 7654                    cx.notify();
 7655                })
 7656                .log_err();
 7657            }
 7658        }));
 7659        None
 7660    }
 7661
 7662    fn prepare_highlight_query_from_selection(
 7663        &mut self,
 7664        snapshot: &DisplaySnapshot,
 7665        cx: &mut Context<Editor>,
 7666    ) -> Option<(String, Range<Anchor>)> {
 7667        if matches!(self.mode, EditorMode::SingleLine) {
 7668            return None;
 7669        }
 7670        if !EditorSettings::get_global(cx).selection_highlight {
 7671            return None;
 7672        }
 7673        if self.selections.count() != 1 || self.selections.line_mode() {
 7674            return None;
 7675        }
 7676        let selection = self.selections.newest::<Point>(&snapshot);
 7677        // If the selection spans multiple rows OR it is empty
 7678        if selection.start.row != selection.end.row
 7679            || selection.start.column == selection.end.column
 7680        {
 7681            return None;
 7682        }
 7683        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7684        let query = snapshot
 7685            .buffer_snapshot()
 7686            .text_for_range(selection_anchor_range.clone())
 7687            .collect::<String>();
 7688        if query.trim().is_empty() {
 7689            return None;
 7690        }
 7691        Some((query, selection_anchor_range))
 7692    }
 7693
 7694    #[ztracing::instrument(skip_all)]
 7695    fn update_selection_occurrence_highlights(
 7696        &mut self,
 7697        multi_buffer_snapshot: MultiBufferSnapshot,
 7698        query_text: String,
 7699        query_range: Range<Anchor>,
 7700        multi_buffer_range_to_query: Range<Point>,
 7701        use_debounce: bool,
 7702        window: &mut Window,
 7703        cx: &mut Context<Editor>,
 7704    ) -> Task<()> {
 7705        cx.spawn_in(window, async move |editor, cx| {
 7706            if use_debounce {
 7707                cx.background_executor()
 7708                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7709                    .await;
 7710            }
 7711            let match_task = cx.background_spawn(async move {
 7712                let buffer_ranges = multi_buffer_snapshot
 7713                    .range_to_buffer_ranges(
 7714                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7715                    )
 7716                    .into_iter()
 7717                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7718                let mut match_ranges = Vec::new();
 7719                let Ok(regex) = project::search::SearchQuery::text(
 7720                    query_text,
 7721                    false,
 7722                    false,
 7723                    false,
 7724                    Default::default(),
 7725                    Default::default(),
 7726                    false,
 7727                    None,
 7728                ) else {
 7729                    return Vec::default();
 7730                };
 7731                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7732                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7733                    match_ranges.extend(
 7734                        regex
 7735                            .search(
 7736                                buffer_snapshot,
 7737                                Some(search_range.start.0..search_range.end.0),
 7738                            )
 7739                            .await
 7740                            .into_iter()
 7741                            .filter_map(|match_range| {
 7742                                let match_start = buffer_snapshot
 7743                                    .anchor_after(search_range.start + match_range.start);
 7744                                let match_end = buffer_snapshot
 7745                                    .anchor_before(search_range.start + match_range.end);
 7746                                let match_anchor_range =
 7747                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7748                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7749                            }),
 7750                    );
 7751                }
 7752                match_ranges
 7753            });
 7754            let match_ranges = match_task.await;
 7755            editor
 7756                .update_in(cx, |editor, _, cx| {
 7757                    if use_debounce {
 7758                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7759                        editor.debounced_selection_highlight_complete = true;
 7760                    } else if editor.debounced_selection_highlight_complete {
 7761                        return;
 7762                    }
 7763                    if !match_ranges.is_empty() {
 7764                        editor.highlight_background(
 7765                            HighlightKey::SelectedTextHighlight,
 7766                            &match_ranges,
 7767                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7768                            cx,
 7769                        )
 7770                    }
 7771                })
 7772                .log_err();
 7773        })
 7774    }
 7775
 7776    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7777        struct NewlineFold;
 7778        let type_id = std::any::TypeId::of::<NewlineFold>();
 7779        if !self.mode.is_single_line() {
 7780            return;
 7781        }
 7782        let snapshot = self.snapshot(window, cx);
 7783        if snapshot.buffer_snapshot().max_point().row == 0 {
 7784            return;
 7785        }
 7786        let task = cx.background_spawn(async move {
 7787            let new_newlines = snapshot
 7788                .buffer_chars_at(MultiBufferOffset(0))
 7789                .filter_map(|(c, i)| {
 7790                    if c == '\n' {
 7791                        Some(
 7792                            snapshot.buffer_snapshot().anchor_after(i)
 7793                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7794                        )
 7795                    } else {
 7796                        None
 7797                    }
 7798                })
 7799                .collect::<Vec<_>>();
 7800            let existing_newlines = snapshot
 7801                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7802                .filter_map(|fold| {
 7803                    if fold.placeholder.type_tag == Some(type_id) {
 7804                        Some(fold.range.start..fold.range.end)
 7805                    } else {
 7806                        None
 7807                    }
 7808                })
 7809                .collect::<Vec<_>>();
 7810
 7811            (new_newlines, existing_newlines)
 7812        });
 7813        self.folding_newlines = cx.spawn(async move |this, cx| {
 7814            let (new_newlines, existing_newlines) = task.await;
 7815            if new_newlines == existing_newlines {
 7816                return;
 7817            }
 7818            let placeholder = FoldPlaceholder {
 7819                render: Arc::new(move |_, _, cx| {
 7820                    div()
 7821                        .bg(cx.theme().status().hint_background)
 7822                        .border_b_1()
 7823                        .size_full()
 7824                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7825                        .border_color(cx.theme().status().hint)
 7826                        .child("\\n")
 7827                        .into_any()
 7828                }),
 7829                constrain_width: false,
 7830                merge_adjacent: false,
 7831                type_tag: Some(type_id),
 7832                collapsed_text: None,
 7833            };
 7834            let creases = new_newlines
 7835                .into_iter()
 7836                .map(|range| Crease::simple(range, placeholder.clone()))
 7837                .collect();
 7838            this.update(cx, |this, cx| {
 7839                this.display_map.update(cx, |display_map, cx| {
 7840                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7841                    display_map.fold(creases, cx);
 7842                });
 7843            })
 7844            .ok();
 7845        });
 7846    }
 7847
 7848    #[ztracing::instrument(skip_all)]
 7849    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7850        if !self.lsp_data_enabled() {
 7851            return;
 7852        }
 7853        let cursor = self.selections.newest_anchor().head();
 7854        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7855
 7856        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7857            self.outline_symbols_at_cursor =
 7858                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7859            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7860            cx.notify();
 7861        } else {
 7862            let syntax = cx.theme().syntax().clone();
 7863            let background_task = cx.background_spawn(async move {
 7864                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7865            });
 7866            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7867                cx.spawn(async move |this, cx| {
 7868                    let symbols = background_task.await;
 7869                    this.update(cx, |this, cx| {
 7870                        this.outline_symbols_at_cursor = symbols;
 7871                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7872                        cx.notify();
 7873                    })
 7874                    .ok();
 7875                });
 7876        }
 7877    }
 7878
 7879    #[ztracing::instrument(skip_all)]
 7880    fn refresh_selected_text_highlights(
 7881        &mut self,
 7882        snapshot: &DisplaySnapshot,
 7883        on_buffer_edit: bool,
 7884        window: &mut Window,
 7885        cx: &mut Context<Editor>,
 7886    ) {
 7887        let Some((query_text, query_range)) =
 7888            self.prepare_highlight_query_from_selection(snapshot, cx)
 7889        else {
 7890            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7891            self.quick_selection_highlight_task.take();
 7892            self.debounced_selection_highlight_task.take();
 7893            self.debounced_selection_highlight_complete = false;
 7894            return;
 7895        };
 7896        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7897        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7898        let query_changed = self
 7899            .quick_selection_highlight_task
 7900            .as_ref()
 7901            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7902        if query_changed {
 7903            self.debounced_selection_highlight_complete = false;
 7904        }
 7905        if on_buffer_edit || query_changed {
 7906            self.quick_selection_highlight_task = Some((
 7907                query_range.clone(),
 7908                self.update_selection_occurrence_highlights(
 7909                    snapshot.buffer.clone(),
 7910                    query_text.clone(),
 7911                    query_range.clone(),
 7912                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7913                    false,
 7914                    window,
 7915                    cx,
 7916                ),
 7917            ));
 7918        }
 7919        if on_buffer_edit
 7920            || self
 7921                .debounced_selection_highlight_task
 7922                .as_ref()
 7923                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7924        {
 7925            let multi_buffer_start = multi_buffer_snapshot
 7926                .anchor_before(MultiBufferOffset(0))
 7927                .to_point(&multi_buffer_snapshot);
 7928            let multi_buffer_end = multi_buffer_snapshot
 7929                .anchor_after(multi_buffer_snapshot.len())
 7930                .to_point(&multi_buffer_snapshot);
 7931            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7932            self.debounced_selection_highlight_task = Some((
 7933                query_range.clone(),
 7934                self.update_selection_occurrence_highlights(
 7935                    snapshot.buffer.clone(),
 7936                    query_text,
 7937                    query_range,
 7938                    multi_buffer_full_range,
 7939                    true,
 7940                    window,
 7941                    cx,
 7942                ),
 7943            ));
 7944        }
 7945    }
 7946
 7947    pub fn multi_buffer_visible_range(
 7948        &self,
 7949        display_snapshot: &DisplaySnapshot,
 7950        cx: &App,
 7951    ) -> Range<Point> {
 7952        let visible_start = self
 7953            .scroll_manager
 7954            .native_anchor(display_snapshot, cx)
 7955            .anchor
 7956            .to_point(display_snapshot.buffer_snapshot())
 7957            .to_display_point(display_snapshot);
 7958
 7959        let mut target_end = visible_start;
 7960        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 7961
 7962        visible_start.to_point(display_snapshot)
 7963            ..display_snapshot
 7964                .clip_point(target_end, Bias::Right)
 7965                .to_point(display_snapshot)
 7966    }
 7967
 7968    pub fn refresh_edit_prediction(
 7969        &mut self,
 7970        debounce: bool,
 7971        user_requested: bool,
 7972        window: &mut Window,
 7973        cx: &mut Context<Self>,
 7974    ) -> Option<()> {
 7975        if self.leader_id.is_some() {
 7976            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7977            return None;
 7978        }
 7979
 7980        let cursor = self.selections.newest_anchor().head();
 7981        let (buffer, cursor_buffer_position) =
 7982            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7983
 7984        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 7985            return None;
 7986        }
 7987
 7988        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7989            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7990            return None;
 7991        }
 7992
 7993        self.update_visible_edit_prediction(window, cx);
 7994
 7995        if !user_requested
 7996            && (!self.should_show_edit_predictions()
 7997                || !self.is_focused(window)
 7998                || buffer.read(cx).is_empty())
 7999        {
 8000            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8001            return None;
 8002        }
 8003
 8004        self.edit_prediction_provider()?
 8005            .refresh(buffer, cursor_buffer_position, debounce, cx);
 8006        Some(())
 8007    }
 8008
 8009    fn show_edit_predictions_in_menu(&self) -> bool {
 8010        match self.edit_prediction_settings {
 8011            EditPredictionSettings::Disabled => false,
 8012            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8013        }
 8014    }
 8015
 8016    pub fn edit_predictions_enabled(&self) -> bool {
 8017        match self.edit_prediction_settings {
 8018            EditPredictionSettings::Disabled => false,
 8019            EditPredictionSettings::Enabled { .. } => true,
 8020        }
 8021    }
 8022
 8023    fn edit_prediction_requires_modifier(&self) -> bool {
 8024        match self.edit_prediction_settings {
 8025            EditPredictionSettings::Disabled => false,
 8026            EditPredictionSettings::Enabled {
 8027                preview_requires_modifier,
 8028                ..
 8029            } => preview_requires_modifier,
 8030        }
 8031    }
 8032
 8033    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8034        if self.edit_prediction_provider.is_none() {
 8035            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8036            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8037            return;
 8038        }
 8039
 8040        let selection = self.selections.newest_anchor();
 8041        let cursor = selection.head();
 8042
 8043        if let Some((buffer, cursor_buffer_position)) =
 8044            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8045        {
 8046            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8047                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8048                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8049                return;
 8050            }
 8051            self.edit_prediction_settings =
 8052                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8053        }
 8054    }
 8055
 8056    fn edit_prediction_settings_at_position(
 8057        &self,
 8058        buffer: &Entity<Buffer>,
 8059        buffer_position: language::Anchor,
 8060        cx: &App,
 8061    ) -> EditPredictionSettings {
 8062        if !self.mode.is_full()
 8063            || !self.show_edit_predictions_override.unwrap_or(true)
 8064            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8065        {
 8066            return EditPredictionSettings::Disabled;
 8067        }
 8068
 8069        let buffer = buffer.read(cx);
 8070
 8071        let file = buffer.file();
 8072
 8073        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 8074            return EditPredictionSettings::Disabled;
 8075        };
 8076
 8077        let by_provider = matches!(
 8078            self.menu_edit_predictions_policy,
 8079            MenuEditPredictionsPolicy::ByProvider
 8080        );
 8081
 8082        let show_in_menu = by_provider
 8083            && self
 8084                .edit_prediction_provider
 8085                .as_ref()
 8086                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8087
 8088        let preview_requires_modifier =
 8089            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8090
 8091        EditPredictionSettings::Enabled {
 8092            show_in_menu,
 8093            preview_requires_modifier,
 8094        }
 8095    }
 8096
 8097    fn should_show_edit_predictions(&self) -> bool {
 8098        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8099    }
 8100
 8101    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8102        matches!(
 8103            self.edit_prediction_preview,
 8104            EditPredictionPreview::Active { .. }
 8105        )
 8106    }
 8107
 8108    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8109        let cursor = self.selections.newest_anchor().head();
 8110        if let Some((buffer, cursor_position)) =
 8111            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8112        {
 8113            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8114        } else {
 8115            false
 8116        }
 8117    }
 8118
 8119    pub fn supports_minimap(&self, cx: &App) -> bool {
 8120        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8121    }
 8122
 8123    fn edit_predictions_enabled_in_buffer(
 8124        &self,
 8125        buffer: &Entity<Buffer>,
 8126        buffer_position: language::Anchor,
 8127        cx: &App,
 8128    ) -> bool {
 8129        maybe!({
 8130            if self.read_only(cx) || self.leader_id.is_some() {
 8131                return Some(false);
 8132            }
 8133            let provider = self.edit_prediction_provider()?;
 8134            if !provider.is_enabled(buffer, buffer_position, cx) {
 8135                return Some(false);
 8136            }
 8137            let buffer = buffer.read(cx);
 8138            let Some(file) = buffer.file() else {
 8139                return Some(true);
 8140            };
 8141            let settings = all_language_settings(Some(file), cx);
 8142            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8143        })
 8144        .unwrap_or(false)
 8145    }
 8146
 8147    pub fn show_edit_prediction(
 8148        &mut self,
 8149        _: &ShowEditPrediction,
 8150        window: &mut Window,
 8151        cx: &mut Context<Self>,
 8152    ) {
 8153        if !self.has_active_edit_prediction() {
 8154            self.refresh_edit_prediction(false, true, window, cx);
 8155            return;
 8156        }
 8157
 8158        self.update_visible_edit_prediction(window, cx);
 8159    }
 8160
 8161    pub fn display_cursor_names(
 8162        &mut self,
 8163        _: &DisplayCursorNames,
 8164        window: &mut Window,
 8165        cx: &mut Context<Self>,
 8166    ) {
 8167        self.show_cursor_names(window, cx);
 8168    }
 8169
 8170    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8171        self.show_cursor_names = true;
 8172        cx.notify();
 8173        cx.spawn_in(window, async move |this, cx| {
 8174            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8175            this.update(cx, |this, cx| {
 8176                this.show_cursor_names = false;
 8177                cx.notify()
 8178            })
 8179            .ok()
 8180        })
 8181        .detach();
 8182    }
 8183
 8184    pub fn accept_partial_edit_prediction(
 8185        &mut self,
 8186        granularity: EditPredictionGranularity,
 8187        window: &mut Window,
 8188        cx: &mut Context<Self>,
 8189    ) {
 8190        if self.show_edit_predictions_in_menu() {
 8191            self.hide_context_menu(window, cx);
 8192        }
 8193
 8194        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8195            return;
 8196        };
 8197
 8198        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8199            return;
 8200        }
 8201
 8202        match &active_edit_prediction.completion {
 8203            EditPrediction::MoveWithin { target, .. } => {
 8204                let target = *target;
 8205
 8206                if matches!(granularity, EditPredictionGranularity::Full) {
 8207                    if let Some(position_map) = &self.last_position_map {
 8208                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8209                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8210
 8211                        if is_visible || !self.edit_prediction_requires_modifier() {
 8212                            self.unfold_ranges(&[target..target], true, false, cx);
 8213                            self.change_selections(
 8214                                SelectionEffects::scroll(Autoscroll::newest()),
 8215                                window,
 8216                                cx,
 8217                                |selections| {
 8218                                    selections.select_anchor_ranges([target..target]);
 8219                                },
 8220                            );
 8221                            self.clear_row_highlights::<EditPredictionPreview>();
 8222                            self.edit_prediction_preview
 8223                                .set_previous_scroll_position(None);
 8224                        } else {
 8225                            // Highlight and request scroll
 8226                            self.edit_prediction_preview
 8227                                .set_previous_scroll_position(Some(
 8228                                    position_map.snapshot.scroll_anchor,
 8229                                ));
 8230                            self.highlight_rows::<EditPredictionPreview>(
 8231                                target..target,
 8232                                cx.theme().colors().editor_highlighted_line_background,
 8233                                RowHighlightOptions {
 8234                                    autoscroll: true,
 8235                                    ..Default::default()
 8236                                },
 8237                                cx,
 8238                            );
 8239                            self.request_autoscroll(Autoscroll::fit(), cx);
 8240                        }
 8241                    }
 8242                } else {
 8243                    self.change_selections(
 8244                        SelectionEffects::scroll(Autoscroll::newest()),
 8245                        window,
 8246                        cx,
 8247                        |selections| {
 8248                            selections.select_anchor_ranges([target..target]);
 8249                        },
 8250                    );
 8251                }
 8252            }
 8253            EditPrediction::MoveOutside { snapshot, target } => {
 8254                if let Some(workspace) = self.workspace() {
 8255                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8256                        .detach_and_log_err(cx);
 8257                }
 8258            }
 8259            EditPrediction::Edit {
 8260                edits,
 8261                cursor_position,
 8262                ..
 8263            } => {
 8264                self.report_edit_prediction_event(
 8265                    active_edit_prediction.completion_id.clone(),
 8266                    true,
 8267                    cx,
 8268                );
 8269
 8270                match granularity {
 8271                    EditPredictionGranularity::Full => {
 8272                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8273
 8274                        // Compute fallback cursor position BEFORE applying the edit,
 8275                        // so the anchor tracks through the edit correctly
 8276                        let fallback_cursor_target = {
 8277                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8278                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8279                        };
 8280
 8281                        self.buffer.update(cx, |buffer, cx| {
 8282                            buffer.edit(edits.iter().cloned(), None, cx)
 8283                        });
 8284
 8285                        if let Some(provider) = self.edit_prediction_provider() {
 8286                            provider.accept(cx);
 8287                        }
 8288
 8289                        // Resolve cursor position after the edit is applied
 8290                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8291                            // The anchor tracks through the edit, then we add the offset
 8292                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8293                            let base_offset = anchor.to_offset(&snapshot).0;
 8294                            let target_offset =
 8295                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8296                            snapshot.anchor_after(target_offset)
 8297                        } else {
 8298                            fallback_cursor_target
 8299                        };
 8300
 8301                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8302                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8303                        });
 8304
 8305                        let selections = self.selections.disjoint_anchors_arc();
 8306                        if let Some(transaction_id_now) =
 8307                            self.buffer.read(cx).last_transaction_id(cx)
 8308                        {
 8309                            if transaction_id_prev != Some(transaction_id_now) {
 8310                                self.selection_history
 8311                                    .insert_transaction(transaction_id_now, selections);
 8312                            }
 8313                        }
 8314
 8315                        self.update_visible_edit_prediction(window, cx);
 8316                        if self.active_edit_prediction.is_none() {
 8317                            self.refresh_edit_prediction(true, true, window, cx);
 8318                        }
 8319                        cx.notify();
 8320                    }
 8321                    _ => {
 8322                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8323                        let cursor_offset = self
 8324                            .selections
 8325                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8326                            .head();
 8327
 8328                        let insertion = edits.iter().find_map(|(range, text)| {
 8329                            let range = range.to_offset(&snapshot);
 8330                            if range.is_empty() && range.start == cursor_offset {
 8331                                Some(text)
 8332                            } else {
 8333                                None
 8334                            }
 8335                        });
 8336
 8337                        if let Some(text) = insertion {
 8338                            let text_to_insert = match granularity {
 8339                                EditPredictionGranularity::Word => {
 8340                                    let mut partial = text
 8341                                        .chars()
 8342                                        .by_ref()
 8343                                        .take_while(|c| c.is_alphabetic())
 8344                                        .collect::<String>();
 8345                                    if partial.is_empty() {
 8346                                        partial = text
 8347                                            .chars()
 8348                                            .by_ref()
 8349                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8350                                            .collect::<String>();
 8351                                    }
 8352                                    partial
 8353                                }
 8354                                EditPredictionGranularity::Line => {
 8355                                    if let Some(line) = text.split_inclusive('\n').next() {
 8356                                        line.to_string()
 8357                                    } else {
 8358                                        text.to_string()
 8359                                    }
 8360                                }
 8361                                EditPredictionGranularity::Full => unreachable!(),
 8362                            };
 8363
 8364                            cx.emit(EditorEvent::InputHandled {
 8365                                utf16_range_to_replace: None,
 8366                                text: text_to_insert.clone().into(),
 8367                            });
 8368
 8369                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8370                            self.refresh_edit_prediction(true, true, window, cx);
 8371                            cx.notify();
 8372                        } else {
 8373                            self.accept_partial_edit_prediction(
 8374                                EditPredictionGranularity::Full,
 8375                                window,
 8376                                cx,
 8377                            );
 8378                        }
 8379                    }
 8380                }
 8381            }
 8382        }
 8383    }
 8384
 8385    pub fn accept_next_word_edit_prediction(
 8386        &mut self,
 8387        _: &AcceptNextWordEditPrediction,
 8388        window: &mut Window,
 8389        cx: &mut Context<Self>,
 8390    ) {
 8391        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8392    }
 8393
 8394    pub fn accept_next_line_edit_prediction(
 8395        &mut self,
 8396        _: &AcceptNextLineEditPrediction,
 8397        window: &mut Window,
 8398        cx: &mut Context<Self>,
 8399    ) {
 8400        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8401    }
 8402
 8403    pub fn accept_edit_prediction(
 8404        &mut self,
 8405        _: &AcceptEditPrediction,
 8406        window: &mut Window,
 8407        cx: &mut Context<Self>,
 8408    ) {
 8409        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8410    }
 8411
 8412    fn discard_edit_prediction(
 8413        &mut self,
 8414        reason: EditPredictionDiscardReason,
 8415        cx: &mut Context<Self>,
 8416    ) -> bool {
 8417        if reason == EditPredictionDiscardReason::Rejected {
 8418            let completion_id = self
 8419                .active_edit_prediction
 8420                .as_ref()
 8421                .and_then(|active_completion| active_completion.completion_id.clone());
 8422
 8423            self.report_edit_prediction_event(completion_id, false, cx);
 8424        }
 8425
 8426        if let Some(provider) = self.edit_prediction_provider() {
 8427            provider.discard(reason, cx);
 8428        }
 8429
 8430        self.take_active_edit_prediction(cx)
 8431    }
 8432
 8433    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8434        let Some(provider) = self.edit_prediction_provider() else {
 8435            return;
 8436        };
 8437
 8438        let Some((_, buffer, _)) = self
 8439            .buffer
 8440            .read(cx)
 8441            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8442        else {
 8443            return;
 8444        };
 8445
 8446        let extension = buffer
 8447            .read(cx)
 8448            .file()
 8449            .and_then(|file| Some(file.path().extension()?.to_string()));
 8450
 8451        let event_type = match accepted {
 8452            true => "Edit Prediction Accepted",
 8453            false => "Edit Prediction Discarded",
 8454        };
 8455        telemetry::event!(
 8456            event_type,
 8457            provider = provider.name(),
 8458            prediction_id = id,
 8459            suggestion_accepted = accepted,
 8460            file_extension = extension,
 8461        );
 8462    }
 8463
 8464    fn open_editor_at_anchor(
 8465        snapshot: &language::BufferSnapshot,
 8466        target: language::Anchor,
 8467        workspace: &Entity<Workspace>,
 8468        window: &mut Window,
 8469        cx: &mut App,
 8470    ) -> Task<Result<()>> {
 8471        workspace.update(cx, |workspace, cx| {
 8472            let path = snapshot.file().map(|file| file.full_path(cx));
 8473            let Some(path) =
 8474                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8475            else {
 8476                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8477            };
 8478            let target = text::ToPoint::to_point(&target, snapshot);
 8479            let item = workspace.open_path(path, None, true, window, cx);
 8480            window.spawn(cx, async move |cx| {
 8481                let Some(editor) = item.await?.downcast::<Editor>() else {
 8482                    return Ok(());
 8483                };
 8484                editor
 8485                    .update_in(cx, |editor, window, cx| {
 8486                        editor.go_to_singleton_buffer_point(target, window, cx);
 8487                    })
 8488                    .ok();
 8489                anyhow::Ok(())
 8490            })
 8491        })
 8492    }
 8493
 8494    pub fn has_active_edit_prediction(&self) -> bool {
 8495        self.active_edit_prediction.is_some()
 8496    }
 8497
 8498    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8499        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8500            return false;
 8501        };
 8502
 8503        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8504        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8505        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8506        true
 8507    }
 8508
 8509    /// Returns true when we're displaying the edit prediction popover below the cursor
 8510    /// like we are not previewing and the LSP autocomplete menu is visible
 8511    /// or we are in `when_holding_modifier` mode.
 8512    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8513        if self.edit_prediction_preview_is_active()
 8514            || !self.show_edit_predictions_in_menu()
 8515            || !self.edit_predictions_enabled()
 8516        {
 8517            return false;
 8518        }
 8519
 8520        if self.has_visible_completions_menu() {
 8521            return true;
 8522        }
 8523
 8524        has_completion && self.edit_prediction_requires_modifier()
 8525    }
 8526
 8527    fn handle_modifiers_changed(
 8528        &mut self,
 8529        modifiers: Modifiers,
 8530        position_map: &PositionMap,
 8531        window: &mut Window,
 8532        cx: &mut Context<Self>,
 8533    ) {
 8534        self.update_edit_prediction_settings(cx);
 8535
 8536        // Ensure that the edit prediction preview is updated, even when not
 8537        // enabled, if there's an active edit prediction preview.
 8538        if self.show_edit_predictions_in_menu()
 8539            || self.edit_prediction_requires_modifier()
 8540            || matches!(
 8541                self.edit_prediction_preview,
 8542                EditPredictionPreview::Active { .. }
 8543            )
 8544        {
 8545            self.update_edit_prediction_preview(&modifiers, window, cx);
 8546        }
 8547
 8548        self.update_selection_mode(&modifiers, position_map, window, cx);
 8549
 8550        let mouse_position = window.mouse_position();
 8551        if !position_map.text_hitbox.is_hovered(window) {
 8552            return;
 8553        }
 8554
 8555        self.update_hovered_link(
 8556            position_map.point_for_position(mouse_position),
 8557            Some(mouse_position),
 8558            &position_map.snapshot,
 8559            modifiers,
 8560            window,
 8561            cx,
 8562        )
 8563    }
 8564
 8565    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8566        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8567            MultiCursorModifier::Alt => modifiers.secondary(),
 8568            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8569        }
 8570    }
 8571
 8572    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8573        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8574            MultiCursorModifier::Alt => modifiers.alt,
 8575            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8576        }
 8577    }
 8578
 8579    fn columnar_selection_mode(
 8580        modifiers: &Modifiers,
 8581        cx: &mut Context<Self>,
 8582    ) -> Option<ColumnarMode> {
 8583        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8584            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8585                Some(ColumnarMode::FromMouse)
 8586            } else if Self::is_alt_pressed(modifiers, cx) {
 8587                Some(ColumnarMode::FromSelection)
 8588            } else {
 8589                None
 8590            }
 8591        } else {
 8592            None
 8593        }
 8594    }
 8595
 8596    fn update_selection_mode(
 8597        &mut self,
 8598        modifiers: &Modifiers,
 8599        position_map: &PositionMap,
 8600        window: &mut Window,
 8601        cx: &mut Context<Self>,
 8602    ) {
 8603        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8604            return;
 8605        };
 8606        if self.selections.pending_anchor().is_none() {
 8607            return;
 8608        }
 8609
 8610        let mouse_position = window.mouse_position();
 8611        let point_for_position = position_map.point_for_position(mouse_position);
 8612        let position = point_for_position.previous_valid;
 8613
 8614        self.select(
 8615            SelectPhase::BeginColumnar {
 8616                position,
 8617                reset: false,
 8618                mode,
 8619                goal_column: point_for_position.exact_unclipped.column(),
 8620            },
 8621            window,
 8622            cx,
 8623        );
 8624    }
 8625
 8626    fn update_edit_prediction_preview(
 8627        &mut self,
 8628        modifiers: &Modifiers,
 8629        window: &mut Window,
 8630        cx: &mut Context<Self>,
 8631    ) {
 8632        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8633
 8634        if modifiers_held {
 8635            if matches!(
 8636                self.edit_prediction_preview,
 8637                EditPredictionPreview::Inactive { .. }
 8638            ) {
 8639                self.edit_prediction_preview = EditPredictionPreview::Active {
 8640                    previous_scroll_position: None,
 8641                    since: Instant::now(),
 8642                };
 8643
 8644                self.update_visible_edit_prediction(window, cx);
 8645                cx.notify();
 8646            }
 8647        } else if let EditPredictionPreview::Active {
 8648            previous_scroll_position,
 8649            since,
 8650        } = self.edit_prediction_preview
 8651        {
 8652            if let (Some(previous_scroll_position), Some(position_map)) =
 8653                (previous_scroll_position, self.last_position_map.as_ref())
 8654            {
 8655                self.set_scroll_position(
 8656                    previous_scroll_position
 8657                        .scroll_position(&position_map.snapshot.display_snapshot),
 8658                    window,
 8659                    cx,
 8660                );
 8661            }
 8662
 8663            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8664                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8665            };
 8666            self.clear_row_highlights::<EditPredictionPreview>();
 8667            self.update_visible_edit_prediction(window, cx);
 8668            cx.notify();
 8669        }
 8670    }
 8671
 8672    fn update_visible_edit_prediction(
 8673        &mut self,
 8674        _window: &mut Window,
 8675        cx: &mut Context<Self>,
 8676    ) -> Option<()> {
 8677        if self.ime_transaction.is_some() {
 8678            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8679            return None;
 8680        }
 8681
 8682        let selection = self.selections.newest_anchor();
 8683        let cursor = selection.head();
 8684        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8685
 8686        // Check project-level disable_ai setting for the current buffer
 8687        if let Some((buffer, _)) = self.buffer.read(cx).text_anchor_for_position(cursor, cx) {
 8688            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8689                return None;
 8690            }
 8691        }
 8692        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8693        let excerpt_id = cursor.excerpt_id;
 8694
 8695        let show_in_menu = self.show_edit_predictions_in_menu();
 8696        let completions_menu_has_precedence = !show_in_menu
 8697            && (self.context_menu.borrow().is_some()
 8698                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8699
 8700        if completions_menu_has_precedence
 8701            || !offset_selection.is_empty()
 8702            || self
 8703                .active_edit_prediction
 8704                .as_ref()
 8705                .is_some_and(|completion| {
 8706                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8707                        return false;
 8708                    };
 8709                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8710                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8711                    !invalidation_range.contains(&offset_selection.head())
 8712                })
 8713        {
 8714            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8715            return None;
 8716        }
 8717
 8718        self.take_active_edit_prediction(cx);
 8719        let Some(provider) = self.edit_prediction_provider() else {
 8720            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8721            return None;
 8722        };
 8723
 8724        let (buffer, cursor_buffer_position) =
 8725            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8726
 8727        self.edit_prediction_settings =
 8728            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8729
 8730        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8731
 8732        if self.in_leading_whitespace {
 8733            let cursor_point = cursor.to_point(&multibuffer);
 8734            let mut suggested_indent = None;
 8735            multibuffer.suggested_indents_callback(
 8736                cursor_point.row..cursor_point.row + 1,
 8737                &mut |_, indent| {
 8738                    suggested_indent = Some(indent);
 8739                    ControlFlow::Break(())
 8740                },
 8741                cx,
 8742            );
 8743
 8744            if let Some(indent) = suggested_indent
 8745                && indent.len == cursor_point.column
 8746            {
 8747                self.in_leading_whitespace = false;
 8748            }
 8749        }
 8750
 8751        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8752
 8753        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8754        {
 8755            edit_prediction_types::EditPrediction::Local {
 8756                id,
 8757                edits,
 8758                cursor_position,
 8759                edit_preview,
 8760            } => (id, edits, cursor_position, edit_preview),
 8761            edit_prediction_types::EditPrediction::Jump {
 8762                id,
 8763                snapshot,
 8764                target,
 8765            } => {
 8766                if let Some(provider) = &self.edit_prediction_provider {
 8767                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8768                }
 8769                self.stale_edit_prediction_in_menu = None;
 8770                self.active_edit_prediction = Some(EditPredictionState {
 8771                    inlay_ids: vec![],
 8772                    completion: EditPrediction::MoveOutside { snapshot, target },
 8773                    completion_id: id,
 8774                    invalidation_range: None,
 8775                });
 8776                cx.notify();
 8777                return Some(());
 8778            }
 8779        };
 8780
 8781        let edits = edits
 8782            .into_iter()
 8783            .flat_map(|(range, new_text)| {
 8784                Some((
 8785                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8786                    new_text,
 8787                ))
 8788            })
 8789            .collect::<Vec<_>>();
 8790        if edits.is_empty() {
 8791            return None;
 8792        }
 8793
 8794        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8795            let anchor = multibuffer.anchor_in_excerpt(excerpt_id, predicted.anchor)?;
 8796            Some((anchor, predicted.offset))
 8797        });
 8798
 8799        let first_edit_start = edits.first().unwrap().0.start;
 8800        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8801        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8802
 8803        let last_edit_end = edits.last().unwrap().0.end;
 8804        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8805        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8806
 8807        let cursor_row = cursor.to_point(&multibuffer).row;
 8808
 8809        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8810
 8811        let mut inlay_ids = Vec::new();
 8812        let invalidation_row_range;
 8813        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8814            Some(cursor_row..edit_end_row)
 8815        } else if cursor_row > edit_end_row {
 8816            Some(edit_start_row..cursor_row)
 8817        } else {
 8818            None
 8819        };
 8820        let supports_jump = self
 8821            .edit_prediction_provider
 8822            .as_ref()
 8823            .map(|provider| provider.provider.supports_jump_to_edit())
 8824            .unwrap_or(true);
 8825
 8826        let is_move = supports_jump
 8827            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8828        let completion = if is_move {
 8829            if let Some(provider) = &self.edit_prediction_provider {
 8830                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8831            }
 8832            invalidation_row_range =
 8833                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8834            let target = first_edit_start;
 8835            EditPrediction::MoveWithin { target, snapshot }
 8836        } else {
 8837            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8838                && !self.edit_predictions_hidden_for_vim_mode;
 8839
 8840            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8841                if provider.show_tab_accept_marker() {
 8842                    EditDisplayMode::TabAccept
 8843                } else {
 8844                    EditDisplayMode::Inline
 8845                }
 8846            } else {
 8847                EditDisplayMode::DiffPopover
 8848            };
 8849
 8850            if show_completions_in_buffer {
 8851                if let Some(provider) = &self.edit_prediction_provider {
 8852                    let suggestion_display_type = match display_mode {
 8853                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8854                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8855                            SuggestionDisplayType::GhostText
 8856                        }
 8857                    };
 8858                    provider.provider.did_show(suggestion_display_type, cx);
 8859                }
 8860                if edits
 8861                    .iter()
 8862                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8863                {
 8864                    let mut inlays = Vec::new();
 8865                    for (range, new_text) in &edits {
 8866                        let inlay = Inlay::edit_prediction(
 8867                            post_inc(&mut self.next_inlay_id),
 8868                            range.start,
 8869                            new_text.as_ref(),
 8870                        );
 8871                        inlay_ids.push(inlay.id);
 8872                        inlays.push(inlay);
 8873                    }
 8874
 8875                    self.splice_inlays(&[], inlays, cx);
 8876                } else {
 8877                    let background_color = cx.theme().status().deleted_background;
 8878                    self.highlight_text(
 8879                        HighlightKey::EditPredictionHighlight,
 8880                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8881                        HighlightStyle {
 8882                            background_color: Some(background_color),
 8883                            ..Default::default()
 8884                        },
 8885                        cx,
 8886                    );
 8887                }
 8888            }
 8889
 8890            invalidation_row_range = edit_start_row..edit_end_row;
 8891
 8892            EditPrediction::Edit {
 8893                edits,
 8894                cursor_position,
 8895                edit_preview,
 8896                display_mode,
 8897                snapshot,
 8898            }
 8899        };
 8900
 8901        let invalidation_range = multibuffer
 8902            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8903            ..multibuffer.anchor_after(Point::new(
 8904                invalidation_row_range.end,
 8905                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8906            ));
 8907
 8908        self.stale_edit_prediction_in_menu = None;
 8909        self.active_edit_prediction = Some(EditPredictionState {
 8910            inlay_ids,
 8911            completion,
 8912            completion_id,
 8913            invalidation_range: Some(invalidation_range),
 8914        });
 8915
 8916        cx.notify();
 8917
 8918        Some(())
 8919    }
 8920
 8921    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8922        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8923    }
 8924
 8925    /// Get all display points of breakpoints that will be rendered within editor
 8926    ///
 8927    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8928    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8929    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8930    fn active_breakpoints(
 8931        &self,
 8932        range: Range<DisplayRow>,
 8933        window: &mut Window,
 8934        cx: &mut Context<Self>,
 8935    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8936        let mut breakpoint_display_points = HashMap::default();
 8937
 8938        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8939            return breakpoint_display_points;
 8940        };
 8941
 8942        let snapshot = self.snapshot(window, cx);
 8943
 8944        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8945        let Some(project) = self.project() else {
 8946            return breakpoint_display_points;
 8947        };
 8948
 8949        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8950            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8951
 8952        for (buffer_snapshot, range, excerpt_id) in
 8953            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8954        {
 8955            let Some(buffer) = project
 8956                .read(cx)
 8957                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8958            else {
 8959                continue;
 8960            };
 8961            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8962                &buffer,
 8963                Some(
 8964                    buffer_snapshot.anchor_before(range.start)
 8965                        ..buffer_snapshot.anchor_after(range.end),
 8966                ),
 8967                buffer_snapshot,
 8968                cx,
 8969            );
 8970            for (breakpoint, state) in breakpoints {
 8971                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8972                let position = multi_buffer_anchor
 8973                    .to_point(&multi_buffer_snapshot)
 8974                    .to_display_point(&snapshot);
 8975
 8976                breakpoint_display_points.insert(
 8977                    position.row(),
 8978                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8979                );
 8980            }
 8981        }
 8982
 8983        breakpoint_display_points
 8984    }
 8985
 8986    fn breakpoint_context_menu(
 8987        &self,
 8988        anchor: Anchor,
 8989        window: &mut Window,
 8990        cx: &mut Context<Self>,
 8991    ) -> Entity<ui::ContextMenu> {
 8992        let weak_editor = cx.weak_entity();
 8993        let focus_handle = self.focus_handle(cx);
 8994
 8995        let row = self
 8996            .buffer
 8997            .read(cx)
 8998            .snapshot(cx)
 8999            .summary_for_anchor::<Point>(&anchor)
 9000            .row;
 9001
 9002        let breakpoint = self
 9003            .breakpoint_at_row(row, window, cx)
 9004            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9005
 9006        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9007            "Edit Log Breakpoint"
 9008        } else {
 9009            "Set Log Breakpoint"
 9010        };
 9011
 9012        let condition_breakpoint_msg = if breakpoint
 9013            .as_ref()
 9014            .is_some_and(|bp| bp.1.condition.is_some())
 9015        {
 9016            "Edit Condition Breakpoint"
 9017        } else {
 9018            "Set Condition Breakpoint"
 9019        };
 9020
 9021        let hit_condition_breakpoint_msg = if breakpoint
 9022            .as_ref()
 9023            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9024        {
 9025            "Edit Hit Condition Breakpoint"
 9026        } else {
 9027            "Set Hit Condition Breakpoint"
 9028        };
 9029
 9030        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9031            "Unset Breakpoint"
 9032        } else {
 9033            "Set Breakpoint"
 9034        };
 9035
 9036        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9037
 9038        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9039            BreakpointState::Enabled => Some("Disable"),
 9040            BreakpointState::Disabled => Some("Enable"),
 9041        });
 9042
 9043        let (anchor, breakpoint) =
 9044            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9045
 9046        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9047            menu.on_blur_subscription(Subscription::new(|| {}))
 9048                .context(focus_handle)
 9049                .when(run_to_cursor, |this| {
 9050                    let weak_editor = weak_editor.clone();
 9051                    this.entry("Run to Cursor", None, move |window, cx| {
 9052                        weak_editor
 9053                            .update(cx, |editor, cx| {
 9054                                editor.change_selections(
 9055                                    SelectionEffects::no_scroll(),
 9056                                    window,
 9057                                    cx,
 9058                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9059                                );
 9060                            })
 9061                            .ok();
 9062
 9063                        window.dispatch_action(Box::new(RunToCursor), cx);
 9064                    })
 9065                    .separator()
 9066                })
 9067                .when_some(toggle_state_msg, |this, msg| {
 9068                    this.entry(msg, None, {
 9069                        let weak_editor = weak_editor.clone();
 9070                        let breakpoint = breakpoint.clone();
 9071                        move |_window, cx| {
 9072                            weak_editor
 9073                                .update(cx, |this, cx| {
 9074                                    this.edit_breakpoint_at_anchor(
 9075                                        anchor,
 9076                                        breakpoint.as_ref().clone(),
 9077                                        BreakpointEditAction::InvertState,
 9078                                        cx,
 9079                                    );
 9080                                })
 9081                                .log_err();
 9082                        }
 9083                    })
 9084                })
 9085                .entry(set_breakpoint_msg, None, {
 9086                    let weak_editor = weak_editor.clone();
 9087                    let breakpoint = breakpoint.clone();
 9088                    move |_window, cx| {
 9089                        weak_editor
 9090                            .update(cx, |this, cx| {
 9091                                this.edit_breakpoint_at_anchor(
 9092                                    anchor,
 9093                                    breakpoint.as_ref().clone(),
 9094                                    BreakpointEditAction::Toggle,
 9095                                    cx,
 9096                                );
 9097                            })
 9098                            .log_err();
 9099                    }
 9100                })
 9101                .entry(log_breakpoint_msg, None, {
 9102                    let breakpoint = breakpoint.clone();
 9103                    let weak_editor = weak_editor.clone();
 9104                    move |window, cx| {
 9105                        weak_editor
 9106                            .update(cx, |this, cx| {
 9107                                this.add_edit_breakpoint_block(
 9108                                    anchor,
 9109                                    breakpoint.as_ref(),
 9110                                    BreakpointPromptEditAction::Log,
 9111                                    window,
 9112                                    cx,
 9113                                );
 9114                            })
 9115                            .log_err();
 9116                    }
 9117                })
 9118                .entry(condition_breakpoint_msg, None, {
 9119                    let breakpoint = breakpoint.clone();
 9120                    let weak_editor = weak_editor.clone();
 9121                    move |window, cx| {
 9122                        weak_editor
 9123                            .update(cx, |this, cx| {
 9124                                this.add_edit_breakpoint_block(
 9125                                    anchor,
 9126                                    breakpoint.as_ref(),
 9127                                    BreakpointPromptEditAction::Condition,
 9128                                    window,
 9129                                    cx,
 9130                                );
 9131                            })
 9132                            .log_err();
 9133                    }
 9134                })
 9135                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9136                    weak_editor
 9137                        .update(cx, |this, cx| {
 9138                            this.add_edit_breakpoint_block(
 9139                                anchor,
 9140                                breakpoint.as_ref(),
 9141                                BreakpointPromptEditAction::HitCondition,
 9142                                window,
 9143                                cx,
 9144                            );
 9145                        })
 9146                        .log_err();
 9147                })
 9148        })
 9149    }
 9150
 9151    fn render_breakpoint(
 9152        &self,
 9153        position: Anchor,
 9154        row: DisplayRow,
 9155        breakpoint: &Breakpoint,
 9156        state: Option<BreakpointSessionState>,
 9157        cx: &mut Context<Self>,
 9158    ) -> IconButton {
 9159        let is_rejected = state.is_some_and(|s| !s.verified);
 9160        // Is it a breakpoint that shows up when hovering over gutter?
 9161        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9162            (false, false),
 9163            |PhantomBreakpointIndicator {
 9164                 is_active,
 9165                 display_row,
 9166                 collides_with_existing_breakpoint,
 9167             }| {
 9168                (
 9169                    is_active && display_row == row,
 9170                    collides_with_existing_breakpoint,
 9171                )
 9172            },
 9173        );
 9174
 9175        let (color, icon) = {
 9176            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9177                (false, false) => ui::IconName::DebugBreakpoint,
 9178                (true, false) => ui::IconName::DebugLogBreakpoint,
 9179                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9180                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9181            };
 9182
 9183            let theme_colors = cx.theme().colors();
 9184
 9185            let color = if is_phantom {
 9186                if collides_with_existing {
 9187                    Color::Custom(
 9188                        theme_colors
 9189                            .debugger_accent
 9190                            .blend(theme_colors.text.opacity(0.6)),
 9191                    )
 9192                } else {
 9193                    Color::Hint
 9194                }
 9195            } else if is_rejected {
 9196                Color::Disabled
 9197            } else {
 9198                Color::Debugger
 9199            };
 9200
 9201            (color, icon)
 9202        };
 9203
 9204        let breakpoint = Arc::from(breakpoint.clone());
 9205
 9206        let alt_as_text = gpui::Keystroke {
 9207            modifiers: Modifiers::secondary_key(),
 9208            ..Default::default()
 9209        };
 9210        let primary_action_text = if breakpoint.is_disabled() {
 9211            "Enable breakpoint"
 9212        } else if is_phantom && !collides_with_existing {
 9213            "Set breakpoint"
 9214        } else {
 9215            "Unset breakpoint"
 9216        };
 9217        let focus_handle = self.focus_handle.clone();
 9218
 9219        let meta = if is_rejected {
 9220            SharedString::from("No executable code is associated with this line.")
 9221        } else if collides_with_existing && !breakpoint.is_disabled() {
 9222            SharedString::from(format!(
 9223                "{alt_as_text}-click to disable,\nright-click for more options."
 9224            ))
 9225        } else {
 9226            SharedString::from("Right-click for more options.")
 9227        };
 9228        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9229            .icon_size(IconSize::XSmall)
 9230            .size(ui::ButtonSize::None)
 9231            .when(is_rejected, |this| {
 9232                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9233            })
 9234            .icon_color(color)
 9235            .style(ButtonStyle::Transparent)
 9236            .on_click(cx.listener({
 9237                move |editor, event: &ClickEvent, window, cx| {
 9238                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9239                        BreakpointEditAction::InvertState
 9240                    } else {
 9241                        BreakpointEditAction::Toggle
 9242                    };
 9243
 9244                    window.focus(&editor.focus_handle(cx), cx);
 9245                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9246                    editor.edit_breakpoint_at_anchor(
 9247                        position,
 9248                        breakpoint.as_ref().clone(),
 9249                        edit_action,
 9250                        cx,
 9251                    );
 9252                }
 9253            }))
 9254            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9255                editor.set_breakpoint_context_menu(
 9256                    row,
 9257                    Some(position),
 9258                    event.position(),
 9259                    window,
 9260                    cx,
 9261                );
 9262            }))
 9263            .tooltip(move |_window, cx| {
 9264                Tooltip::with_meta_in(
 9265                    primary_action_text,
 9266                    Some(&ToggleBreakpoint),
 9267                    meta.clone(),
 9268                    &focus_handle,
 9269                    cx,
 9270                )
 9271            })
 9272    }
 9273
 9274    fn build_tasks_context(
 9275        project: &Entity<Project>,
 9276        buffer: &Entity<Buffer>,
 9277        buffer_row: u32,
 9278        tasks: &Arc<RunnableTasks>,
 9279        cx: &mut Context<Self>,
 9280    ) -> Task<Option<task::TaskContext>> {
 9281        let position = Point::new(buffer_row, tasks.column);
 9282        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9283        let location = Location {
 9284            buffer: buffer.clone(),
 9285            range: range_start..range_start,
 9286        };
 9287        // Fill in the environmental variables from the tree-sitter captures
 9288        let mut captured_task_variables = TaskVariables::default();
 9289        for (capture_name, value) in tasks.extra_variables.clone() {
 9290            captured_task_variables.insert(
 9291                task::VariableName::Custom(capture_name.into()),
 9292                value.clone(),
 9293            );
 9294        }
 9295        project.update(cx, |project, cx| {
 9296            project.task_store().update(cx, |task_store, cx| {
 9297                task_store.task_context_for_location(captured_task_variables, location, cx)
 9298            })
 9299        })
 9300    }
 9301
 9302    pub fn context_menu_visible(&self) -> bool {
 9303        !self.edit_prediction_preview_is_active()
 9304            && self
 9305                .context_menu
 9306                .borrow()
 9307                .as_ref()
 9308                .is_some_and(|menu| menu.visible())
 9309    }
 9310
 9311    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9312        self.context_menu
 9313            .borrow()
 9314            .as_ref()
 9315            .map(|menu| menu.origin())
 9316    }
 9317
 9318    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9319        self.context_menu_options = Some(options);
 9320    }
 9321
 9322    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9323    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9324
 9325    fn render_edit_prediction_popover(
 9326        &mut self,
 9327        text_bounds: &Bounds<Pixels>,
 9328        content_origin: gpui::Point<Pixels>,
 9329        right_margin: Pixels,
 9330        editor_snapshot: &EditorSnapshot,
 9331        visible_row_range: Range<DisplayRow>,
 9332        scroll_top: ScrollOffset,
 9333        scroll_bottom: ScrollOffset,
 9334        line_layouts: &[LineWithInvisibles],
 9335        line_height: Pixels,
 9336        scroll_position: gpui::Point<ScrollOffset>,
 9337        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9338        newest_selection_head: Option<DisplayPoint>,
 9339        editor_width: Pixels,
 9340        style: &EditorStyle,
 9341        window: &mut Window,
 9342        cx: &mut App,
 9343    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9344        if self.mode().is_minimap() {
 9345            return None;
 9346        }
 9347        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9348
 9349        if self.edit_prediction_visible_in_cursor_popover(true) {
 9350            return None;
 9351        }
 9352
 9353        match &active_edit_prediction.completion {
 9354            EditPrediction::MoveWithin { target, .. } => {
 9355                let target_display_point = target.to_display_point(editor_snapshot);
 9356
 9357                if self.edit_prediction_requires_modifier() {
 9358                    if !self.edit_prediction_preview_is_active() {
 9359                        return None;
 9360                    }
 9361
 9362                    self.render_edit_prediction_modifier_jump_popover(
 9363                        text_bounds,
 9364                        content_origin,
 9365                        visible_row_range,
 9366                        line_layouts,
 9367                        line_height,
 9368                        scroll_pixel_position,
 9369                        newest_selection_head,
 9370                        target_display_point,
 9371                        window,
 9372                        cx,
 9373                    )
 9374                } else {
 9375                    self.render_edit_prediction_eager_jump_popover(
 9376                        text_bounds,
 9377                        content_origin,
 9378                        editor_snapshot,
 9379                        visible_row_range,
 9380                        scroll_top,
 9381                        scroll_bottom,
 9382                        line_height,
 9383                        scroll_pixel_position,
 9384                        target_display_point,
 9385                        editor_width,
 9386                        window,
 9387                        cx,
 9388                    )
 9389                }
 9390            }
 9391            EditPrediction::Edit {
 9392                display_mode: EditDisplayMode::Inline,
 9393                ..
 9394            } => None,
 9395            EditPrediction::Edit {
 9396                display_mode: EditDisplayMode::TabAccept,
 9397                edits,
 9398                ..
 9399            } => {
 9400                let range = &edits.first()?.0;
 9401                let target_display_point = range.end.to_display_point(editor_snapshot);
 9402
 9403                self.render_edit_prediction_end_of_line_popover(
 9404                    "Accept",
 9405                    editor_snapshot,
 9406                    visible_row_range,
 9407                    target_display_point,
 9408                    line_height,
 9409                    scroll_pixel_position,
 9410                    content_origin,
 9411                    editor_width,
 9412                    window,
 9413                    cx,
 9414                )
 9415            }
 9416            EditPrediction::Edit {
 9417                edits,
 9418                edit_preview,
 9419                display_mode: EditDisplayMode::DiffPopover,
 9420                snapshot,
 9421                ..
 9422            } => self.render_edit_prediction_diff_popover(
 9423                text_bounds,
 9424                content_origin,
 9425                right_margin,
 9426                editor_snapshot,
 9427                visible_row_range,
 9428                line_layouts,
 9429                line_height,
 9430                scroll_position,
 9431                scroll_pixel_position,
 9432                newest_selection_head,
 9433                editor_width,
 9434                style,
 9435                edits,
 9436                edit_preview,
 9437                snapshot,
 9438                window,
 9439                cx,
 9440            ),
 9441            EditPrediction::MoveOutside { snapshot, .. } => {
 9442                let mut element = self
 9443                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9444                    .into_any();
 9445
 9446                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9447                let origin_x = text_bounds.size.width - size.width - px(30.);
 9448                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9449                element.prepaint_at(origin, window, cx);
 9450
 9451                Some((element, origin))
 9452            }
 9453        }
 9454    }
 9455
 9456    fn render_edit_prediction_modifier_jump_popover(
 9457        &mut self,
 9458        text_bounds: &Bounds<Pixels>,
 9459        content_origin: gpui::Point<Pixels>,
 9460        visible_row_range: Range<DisplayRow>,
 9461        line_layouts: &[LineWithInvisibles],
 9462        line_height: Pixels,
 9463        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9464        newest_selection_head: Option<DisplayPoint>,
 9465        target_display_point: DisplayPoint,
 9466        window: &mut Window,
 9467        cx: &mut App,
 9468    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9469        let scrolled_content_origin =
 9470            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9471
 9472        const SCROLL_PADDING_Y: Pixels = px(12.);
 9473
 9474        if target_display_point.row() < visible_row_range.start {
 9475            return self.render_edit_prediction_scroll_popover(
 9476                &|_| SCROLL_PADDING_Y,
 9477                IconName::ArrowUp,
 9478                visible_row_range,
 9479                line_layouts,
 9480                newest_selection_head,
 9481                scrolled_content_origin,
 9482                window,
 9483                cx,
 9484            );
 9485        } else if target_display_point.row() >= visible_row_range.end {
 9486            return self.render_edit_prediction_scroll_popover(
 9487                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9488                IconName::ArrowDown,
 9489                visible_row_range,
 9490                line_layouts,
 9491                newest_selection_head,
 9492                scrolled_content_origin,
 9493                window,
 9494                cx,
 9495            );
 9496        }
 9497
 9498        const POLE_WIDTH: Pixels = px(2.);
 9499
 9500        let line_layout =
 9501            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9502        let target_column = target_display_point.column() as usize;
 9503
 9504        let target_x = line_layout.x_for_index(target_column);
 9505        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9506            - scroll_pixel_position.y;
 9507
 9508        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9509
 9510        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9511        border_color.l += 0.001;
 9512
 9513        let mut element = v_flex()
 9514            .items_end()
 9515            .when(flag_on_right, |el| el.items_start())
 9516            .child(if flag_on_right {
 9517                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9518                    .rounded_bl(px(0.))
 9519                    .rounded_tl(px(0.))
 9520                    .border_l_2()
 9521                    .border_color(border_color)
 9522            } else {
 9523                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9524                    .rounded_br(px(0.))
 9525                    .rounded_tr(px(0.))
 9526                    .border_r_2()
 9527                    .border_color(border_color)
 9528            })
 9529            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9530            .into_any();
 9531
 9532        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9533
 9534        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9535            - point(
 9536                if flag_on_right {
 9537                    POLE_WIDTH
 9538                } else {
 9539                    size.width - POLE_WIDTH
 9540                },
 9541                size.height - line_height,
 9542            );
 9543
 9544        origin.x = origin.x.max(content_origin.x);
 9545
 9546        element.prepaint_at(origin, window, cx);
 9547
 9548        Some((element, origin))
 9549    }
 9550
 9551    fn render_edit_prediction_scroll_popover(
 9552        &mut self,
 9553        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9554        scroll_icon: IconName,
 9555        visible_row_range: Range<DisplayRow>,
 9556        line_layouts: &[LineWithInvisibles],
 9557        newest_selection_head: Option<DisplayPoint>,
 9558        scrolled_content_origin: gpui::Point<Pixels>,
 9559        window: &mut Window,
 9560        cx: &mut App,
 9561    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9562        let mut element = self
 9563            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9564            .into_any();
 9565
 9566        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9567
 9568        let cursor = newest_selection_head?;
 9569        let cursor_row_layout =
 9570            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9571        let cursor_column = cursor.column() as usize;
 9572
 9573        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9574
 9575        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9576
 9577        element.prepaint_at(origin, window, cx);
 9578        Some((element, origin))
 9579    }
 9580
 9581    fn render_edit_prediction_eager_jump_popover(
 9582        &mut self,
 9583        text_bounds: &Bounds<Pixels>,
 9584        content_origin: gpui::Point<Pixels>,
 9585        editor_snapshot: &EditorSnapshot,
 9586        visible_row_range: Range<DisplayRow>,
 9587        scroll_top: ScrollOffset,
 9588        scroll_bottom: ScrollOffset,
 9589        line_height: Pixels,
 9590        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9591        target_display_point: DisplayPoint,
 9592        editor_width: Pixels,
 9593        window: &mut Window,
 9594        cx: &mut App,
 9595    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9596        if target_display_point.row().as_f64() < scroll_top {
 9597            let mut element = self
 9598                .render_edit_prediction_line_popover(
 9599                    "Jump to Edit",
 9600                    Some(IconName::ArrowUp),
 9601                    window,
 9602                    cx,
 9603                )
 9604                .into_any();
 9605
 9606            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9607            let offset = point(
 9608                (text_bounds.size.width - size.width) / 2.,
 9609                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9610            );
 9611
 9612            let origin = text_bounds.origin + offset;
 9613            element.prepaint_at(origin, window, cx);
 9614            Some((element, origin))
 9615        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9616            let mut element = self
 9617                .render_edit_prediction_line_popover(
 9618                    "Jump to Edit",
 9619                    Some(IconName::ArrowDown),
 9620                    window,
 9621                    cx,
 9622                )
 9623                .into_any();
 9624
 9625            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9626            let offset = point(
 9627                (text_bounds.size.width - size.width) / 2.,
 9628                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9629            );
 9630
 9631            let origin = text_bounds.origin + offset;
 9632            element.prepaint_at(origin, window, cx);
 9633            Some((element, origin))
 9634        } else {
 9635            self.render_edit_prediction_end_of_line_popover(
 9636                "Jump to Edit",
 9637                editor_snapshot,
 9638                visible_row_range,
 9639                target_display_point,
 9640                line_height,
 9641                scroll_pixel_position,
 9642                content_origin,
 9643                editor_width,
 9644                window,
 9645                cx,
 9646            )
 9647        }
 9648    }
 9649
 9650    fn render_edit_prediction_end_of_line_popover(
 9651        self: &mut Editor,
 9652        label: &'static str,
 9653        editor_snapshot: &EditorSnapshot,
 9654        visible_row_range: Range<DisplayRow>,
 9655        target_display_point: DisplayPoint,
 9656        line_height: Pixels,
 9657        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9658        content_origin: gpui::Point<Pixels>,
 9659        editor_width: Pixels,
 9660        window: &mut Window,
 9661        cx: &mut App,
 9662    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9663        let target_line_end = DisplayPoint::new(
 9664            target_display_point.row(),
 9665            editor_snapshot.line_len(target_display_point.row()),
 9666        );
 9667
 9668        let mut element = self
 9669            .render_edit_prediction_line_popover(label, None, window, cx)
 9670            .into_any();
 9671
 9672        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9673
 9674        let line_origin =
 9675            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9676
 9677        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9678        let mut origin = start_point
 9679            + line_origin
 9680            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9681        origin.x = origin.x.max(content_origin.x);
 9682
 9683        let max_x = content_origin.x + editor_width - size.width;
 9684
 9685        if origin.x > max_x {
 9686            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9687
 9688            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9689                origin.y += offset;
 9690                IconName::ArrowUp
 9691            } else {
 9692                origin.y -= offset;
 9693                IconName::ArrowDown
 9694            };
 9695
 9696            element = self
 9697                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9698                .into_any();
 9699
 9700            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9701
 9702            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9703        }
 9704
 9705        element.prepaint_at(origin, window, cx);
 9706        Some((element, origin))
 9707    }
 9708
 9709    fn render_edit_prediction_diff_popover(
 9710        self: &Editor,
 9711        text_bounds: &Bounds<Pixels>,
 9712        content_origin: gpui::Point<Pixels>,
 9713        right_margin: Pixels,
 9714        editor_snapshot: &EditorSnapshot,
 9715        visible_row_range: Range<DisplayRow>,
 9716        line_layouts: &[LineWithInvisibles],
 9717        line_height: Pixels,
 9718        scroll_position: gpui::Point<ScrollOffset>,
 9719        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9720        newest_selection_head: Option<DisplayPoint>,
 9721        editor_width: Pixels,
 9722        style: &EditorStyle,
 9723        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9724        edit_preview: &Option<language::EditPreview>,
 9725        snapshot: &language::BufferSnapshot,
 9726        window: &mut Window,
 9727        cx: &mut App,
 9728    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9729        let edit_start = edits
 9730            .first()
 9731            .unwrap()
 9732            .0
 9733            .start
 9734            .to_display_point(editor_snapshot);
 9735        let edit_end = edits
 9736            .last()
 9737            .unwrap()
 9738            .0
 9739            .end
 9740            .to_display_point(editor_snapshot);
 9741
 9742        let is_visible = visible_row_range.contains(&edit_start.row())
 9743            || visible_row_range.contains(&edit_end.row());
 9744        if !is_visible {
 9745            return None;
 9746        }
 9747
 9748        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9749            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9750        } else {
 9751            // Fallback for providers without edit_preview
 9752            crate::edit_prediction_fallback_text(edits, cx)
 9753        };
 9754
 9755        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9756        let line_count = highlighted_edits.text.lines().count();
 9757
 9758        const BORDER_WIDTH: Pixels = px(1.);
 9759
 9760        let keybind = self.render_edit_prediction_keybind(window, cx);
 9761        let has_keybind = keybind.is_some();
 9762
 9763        let mut element = h_flex()
 9764            .items_start()
 9765            .child(
 9766                h_flex()
 9767                    .bg(cx.theme().colors().editor_background)
 9768                    .border(BORDER_WIDTH)
 9769                    .shadow_xs()
 9770                    .border_color(cx.theme().colors().border)
 9771                    .rounded_l_lg()
 9772                    .when(line_count > 1, |el| el.rounded_br_lg())
 9773                    .pr_1()
 9774                    .child(styled_text),
 9775            )
 9776            .child(
 9777                h_flex()
 9778                    .h(line_height + BORDER_WIDTH * 2.)
 9779                    .px_1p5()
 9780                    .gap_1()
 9781                    // Workaround: For some reason, there's a gap if we don't do this
 9782                    .ml(-BORDER_WIDTH)
 9783                    .shadow(vec![gpui::BoxShadow {
 9784                        color: gpui::black().opacity(0.05),
 9785                        offset: point(px(1.), px(1.)),
 9786                        blur_radius: px(2.),
 9787                        spread_radius: px(0.),
 9788                    }])
 9789                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9790                    .border(BORDER_WIDTH)
 9791                    .border_color(cx.theme().colors().border)
 9792                    .rounded_r_lg()
 9793                    .id("edit_prediction_diff_popover_keybind")
 9794                    .when(!has_keybind, |el| {
 9795                        let status_colors = cx.theme().status();
 9796
 9797                        el.bg(status_colors.error_background)
 9798                            .border_color(status_colors.error.opacity(0.6))
 9799                            .child(Icon::new(IconName::Info).color(Color::Error))
 9800                            .cursor_default()
 9801                            .hoverable_tooltip(move |_window, cx| {
 9802                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9803                            })
 9804                    })
 9805                    .children(keybind),
 9806            )
 9807            .into_any();
 9808
 9809        let longest_row =
 9810            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9811        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9812            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9813        } else {
 9814            layout_line(
 9815                longest_row,
 9816                editor_snapshot,
 9817                style,
 9818                editor_width,
 9819                |_| false,
 9820                window,
 9821                cx,
 9822            )
 9823            .width
 9824        };
 9825
 9826        let viewport_bounds =
 9827            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9828                right: -right_margin,
 9829                ..Default::default()
 9830            });
 9831
 9832        let x_after_longest = Pixels::from(
 9833            ScrollPixelOffset::from(
 9834                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9835            ) - scroll_pixel_position.x,
 9836        );
 9837
 9838        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9839
 9840        // Fully visible if it can be displayed within the window (allow overlapping other
 9841        // panes). However, this is only allowed if the popover starts within text_bounds.
 9842        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9843            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9844
 9845        let mut origin = if can_position_to_the_right {
 9846            point(
 9847                x_after_longest,
 9848                text_bounds.origin.y
 9849                    + Pixels::from(
 9850                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9851                            - scroll_pixel_position.y,
 9852                    ),
 9853            )
 9854        } else {
 9855            let cursor_row = newest_selection_head.map(|head| head.row());
 9856            let above_edit = edit_start
 9857                .row()
 9858                .0
 9859                .checked_sub(line_count as u32)
 9860                .map(DisplayRow);
 9861            let below_edit = Some(edit_end.row() + 1);
 9862            let above_cursor =
 9863                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9864            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9865
 9866            // Place the edit popover adjacent to the edit if there is a location
 9867            // available that is onscreen and does not obscure the cursor. Otherwise,
 9868            // place it adjacent to the cursor.
 9869            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9870                .into_iter()
 9871                .flatten()
 9872                .find(|&start_row| {
 9873                    let end_row = start_row + line_count as u32;
 9874                    visible_row_range.contains(&start_row)
 9875                        && visible_row_range.contains(&end_row)
 9876                        && cursor_row
 9877                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9878                })?;
 9879
 9880            content_origin
 9881                + point(
 9882                    Pixels::from(-scroll_pixel_position.x),
 9883                    Pixels::from(
 9884                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9885                    ),
 9886                )
 9887        };
 9888
 9889        origin.x -= BORDER_WIDTH;
 9890
 9891        window.with_content_mask(
 9892            Some(gpui::ContentMask {
 9893                bounds: *text_bounds,
 9894            }),
 9895            |window| {
 9896                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9897            },
 9898        );
 9899
 9900        // Do not return an element, since it will already be drawn due to defer_draw.
 9901        None
 9902    }
 9903
 9904    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9905        px(30.)
 9906    }
 9907
 9908    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9909        if self.read_only(cx) {
 9910            cx.theme().players().read_only()
 9911        } else {
 9912            self.style.as_ref().unwrap().local_player
 9913        }
 9914    }
 9915
 9916    fn render_edit_prediction_inline_keystroke(
 9917        &self,
 9918        keystroke: &gpui::KeybindingKeystroke,
 9919        modifiers_color: Color,
 9920        cx: &App,
 9921    ) -> AnyElement {
 9922        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9923
 9924        h_flex()
 9925            .px_0p5()
 9926            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9927            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9928            .text_size(TextSize::XSmall.rems(cx))
 9929            .child(h_flex().children(ui::render_modifiers(
 9930                keystroke.modifiers(),
 9931                PlatformStyle::platform(),
 9932                Some(modifiers_color),
 9933                Some(IconSize::XSmall.rems().into()),
 9934                true,
 9935            )))
 9936            .when(is_platform_style_mac, |parent| {
 9937                parent.child(keystroke.key().to_string())
 9938            })
 9939            .when(!is_platform_style_mac, |parent| {
 9940                parent.child(
 9941                    Key::new(util::capitalize(keystroke.key()), Some(Color::Default))
 9942                        .size(Some(IconSize::XSmall.rems().into())),
 9943                )
 9944            })
 9945            .into_any()
 9946    }
 9947
 9948    fn render_edit_prediction_popover_keystroke(
 9949        &self,
 9950        keystroke: &gpui::KeybindingKeystroke,
 9951        color: Color,
 9952        cx: &App,
 9953    ) -> AnyElement {
 9954        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9955
 9956        if keystroke.modifiers().modified() {
 9957            h_flex()
 9958                .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9959                .when(is_platform_style_mac, |parent| parent.gap_1())
 9960                .child(h_flex().children(ui::render_modifiers(
 9961                    keystroke.modifiers(),
 9962                    PlatformStyle::platform(),
 9963                    Some(color),
 9964                    None,
 9965                    false,
 9966                )))
 9967                .into_any()
 9968        } else {
 9969            Key::new(util::capitalize(keystroke.key()), Some(color))
 9970                .size(Some(IconSize::XSmall.rems().into()))
 9971                .into_any_element()
 9972        }
 9973    }
 9974
 9975    fn render_edit_prediction_keybind(
 9976        &self,
 9977        window: &mut Window,
 9978        cx: &mut App,
 9979    ) -> Option<AnyElement> {
 9980        let keybind_display =
 9981            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
 9982        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
 9983
 9984        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
 9985            Color::Accent
 9986        } else {
 9987            Color::Muted
 9988        };
 9989
 9990        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
 9991    }
 9992
 9993    fn render_edit_prediction_line_popover(
 9994        &self,
 9995        label: impl Into<SharedString>,
 9996        icon: Option<IconName>,
 9997        window: &mut Window,
 9998        cx: &mut App,
 9999    ) -> Stateful<Div> {
10000        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10001
10002        let keybind = self.render_edit_prediction_keybind(window, cx);
10003        let has_keybind = keybind.is_some();
10004        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10005
10006        h_flex()
10007            .id("ep-line-popover")
10008            .py_0p5()
10009            .pl_1()
10010            .pr(padding_right)
10011            .gap_1()
10012            .rounded_md()
10013            .border_1()
10014            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10015            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10016            .shadow_xs()
10017            .when(!has_keybind, |el| {
10018                let status_colors = cx.theme().status();
10019
10020                el.bg(status_colors.error_background)
10021                    .border_color(status_colors.error.opacity(0.6))
10022                    .pl_2()
10023                    .child(Icon::new(icons.error).color(Color::Error))
10024                    .cursor_default()
10025                    .hoverable_tooltip(move |_window, cx| {
10026                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10027                    })
10028            })
10029            .children(keybind)
10030            .child(
10031                Label::new(label)
10032                    .size(LabelSize::Small)
10033                    .when(!has_keybind, |el| {
10034                        el.color(cx.theme().status().error.into()).strikethrough()
10035                    }),
10036            )
10037            .when(!has_keybind, |el| {
10038                el.child(
10039                    h_flex().ml_1().child(
10040                        Icon::new(IconName::Info)
10041                            .size(IconSize::Small)
10042                            .color(cx.theme().status().error.into()),
10043                    ),
10044                )
10045            })
10046            .when_some(icon, |element, icon| {
10047                element.child(
10048                    div()
10049                        .mt(px(1.5))
10050                        .child(Icon::new(icon).size(IconSize::Small)),
10051                )
10052            })
10053    }
10054
10055    fn render_edit_prediction_jump_outside_popover(
10056        &self,
10057        snapshot: &BufferSnapshot,
10058        window: &mut Window,
10059        cx: &mut App,
10060    ) -> Stateful<Div> {
10061        let keybind = self.render_edit_prediction_keybind(window, cx);
10062        let has_keybind = keybind.is_some();
10063        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10064
10065        let file_name = snapshot
10066            .file()
10067            .map(|file| SharedString::new(file.file_name(cx)))
10068            .unwrap_or(SharedString::new_static("untitled"));
10069
10070        h_flex()
10071            .id("ep-jump-outside-popover")
10072            .py_1()
10073            .px_2()
10074            .gap_1()
10075            .rounded_md()
10076            .border_1()
10077            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10078            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10079            .shadow_xs()
10080            .when(!has_keybind, |el| {
10081                let status_colors = cx.theme().status();
10082
10083                el.bg(status_colors.error_background)
10084                    .border_color(status_colors.error.opacity(0.6))
10085                    .pl_2()
10086                    .child(Icon::new(icons.error).color(Color::Error))
10087                    .cursor_default()
10088                    .hoverable_tooltip(move |_window, cx| {
10089                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10090                    })
10091            })
10092            .children(keybind)
10093            .child(
10094                Label::new(file_name)
10095                    .size(LabelSize::Small)
10096                    .buffer_font(cx)
10097                    .when(!has_keybind, |el| {
10098                        el.color(cx.theme().status().error.into()).strikethrough()
10099                    }),
10100            )
10101            .when(!has_keybind, |el| {
10102                el.child(
10103                    h_flex().ml_1().child(
10104                        Icon::new(IconName::Info)
10105                            .size(IconSize::Small)
10106                            .color(cx.theme().status().error.into()),
10107                    ),
10108                )
10109            })
10110            .child(
10111                div()
10112                    .mt(px(1.5))
10113                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10114            )
10115    }
10116
10117    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10118        let accent_color = cx.theme().colors().text_accent;
10119        let editor_bg_color = cx.theme().colors().editor_background;
10120        editor_bg_color.blend(accent_color.opacity(0.1))
10121    }
10122
10123    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
10124        let accent_color = cx.theme().colors().text_accent;
10125        let editor_bg_color = cx.theme().colors().editor_background;
10126        editor_bg_color.blend(accent_color.opacity(0.6))
10127    }
10128    fn get_prediction_provider_icons(
10129        provider: &Option<RegisteredEditPredictionDelegate>,
10130        cx: &App,
10131    ) -> edit_prediction_types::EditPredictionIconSet {
10132        match provider {
10133            Some(provider) => provider.provider.icons(cx),
10134            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10135        }
10136    }
10137
10138    fn render_edit_prediction_cursor_popover(
10139        &self,
10140        min_width: Pixels,
10141        max_width: Pixels,
10142        cursor_point: Point,
10143        style: &EditorStyle,
10144        window: &mut Window,
10145        cx: &mut Context<Editor>,
10146    ) -> Option<AnyElement> {
10147        let provider = self.edit_prediction_provider.as_ref()?;
10148        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10149
10150        let is_refreshing = provider.provider.is_refreshing(cx);
10151
10152        fn pending_completion_container(icon: IconName) -> Div {
10153            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10154        }
10155
10156        let completion = match &self.active_edit_prediction {
10157            Some(prediction) => {
10158                if !self.has_visible_completions_menu() {
10159                    const RADIUS: Pixels = px(6.);
10160                    const BORDER_WIDTH: Pixels = px(1.);
10161                    let keybind_display = self.edit_prediction_keybind_display(
10162                        EditPredictionKeybindSurface::CursorPopoverCompact,
10163                        window,
10164                        cx,
10165                    );
10166
10167                    return Some(
10168                        h_flex()
10169                            .elevation_2(cx)
10170                            .border(BORDER_WIDTH)
10171                            .border_color(cx.theme().colors().border)
10172                            .when(keybind_display.missing_accept_keystroke, |el| {
10173                                el.border_color(cx.theme().status().error)
10174                            })
10175                            .rounded(RADIUS)
10176                            .rounded_tl(px(0.))
10177                            .overflow_hidden()
10178                            .child(div().px_1p5().child(match &prediction.completion {
10179                                EditPrediction::MoveWithin { target, snapshot } => {
10180                                    use text::ToPoint as _;
10181                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
10182                                    {
10183                                        Icon::new(icons.down)
10184                                    } else {
10185                                        Icon::new(icons.up)
10186                                    }
10187                                }
10188                                EditPrediction::MoveOutside { .. } => {
10189                                    // TODO [zeta2] custom icon for external jump?
10190                                    Icon::new(icons.base)
10191                                }
10192                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10193                            }))
10194                            .child(
10195                                h_flex()
10196                                    .gap_1()
10197                                    .py_1()
10198                                    .px_2()
10199                                    .rounded_r(RADIUS - BORDER_WIDTH)
10200                                    .border_l_1()
10201                                    .border_color(cx.theme().colors().border)
10202                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10203                                    .when(keybind_display.show_hold_label, |el| {
10204                                        el.child(
10205                                            Label::new("Hold")
10206                                                .size(LabelSize::Small)
10207                                                .when(
10208                                                    keybind_display.missing_accept_keystroke,
10209                                                    |el| el.strikethrough(),
10210                                                )
10211                                                .line_height_style(LineHeightStyle::UiLabel),
10212                                        )
10213                                    })
10214                                    .id("edit_prediction_cursor_popover_keybind")
10215                                    .when(keybind_display.missing_accept_keystroke, |el| {
10216                                        let status_colors = cx.theme().status();
10217
10218                                        el.bg(status_colors.error_background)
10219                                            .border_color(status_colors.error.opacity(0.6))
10220                                            .child(Icon::new(IconName::Info).color(Color::Error))
10221                                            .cursor_default()
10222                                            .hoverable_tooltip(move |_window, cx| {
10223                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10224                                                    .into()
10225                                            })
10226                                    })
10227                                    .when_some(
10228                                        keybind_display.displayed_keystroke.as_ref(),
10229                                        |el, compact_keystroke| {
10230                                            el.child(self.render_edit_prediction_popover_keystroke(
10231                                                compact_keystroke,
10232                                                Color::Default,
10233                                                cx,
10234                                            ))
10235                                        },
10236                                    ),
10237                            )
10238                            .into_any(),
10239                    );
10240                }
10241
10242                self.render_edit_prediction_cursor_popover_preview(
10243                    prediction,
10244                    cursor_point,
10245                    style,
10246                    cx,
10247                )?
10248            }
10249
10250            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10251                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10252                    stale_completion,
10253                    cursor_point,
10254                    style,
10255                    cx,
10256                )?,
10257
10258                None => pending_completion_container(icons.base)
10259                    .child(Label::new("...").size(LabelSize::Small)),
10260            },
10261
10262            None => pending_completion_container(icons.base)
10263                .child(Label::new("...").size(LabelSize::Small)),
10264        };
10265
10266        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10267            completion
10268                .with_animation(
10269                    "loading-completion",
10270                    Animation::new(Duration::from_secs(2))
10271                        .repeat()
10272                        .with_easing(pulsating_between(0.4, 0.8)),
10273                    |label, delta| label.opacity(delta),
10274                )
10275                .into_any_element()
10276        } else {
10277            completion.into_any_element()
10278        };
10279
10280        let has_completion = self.active_edit_prediction.is_some();
10281        let keybind_display = self.edit_prediction_keybind_display(
10282            EditPredictionKeybindSurface::CursorPopoverExpanded,
10283            window,
10284            cx,
10285        );
10286
10287        Some(
10288            h_flex()
10289                .min_w(min_width)
10290                .max_w(max_width)
10291                .flex_1()
10292                .elevation_2(cx)
10293                .border_color(cx.theme().colors().border)
10294                .child(
10295                    div()
10296                        .flex_1()
10297                        .py_1()
10298                        .px_2()
10299                        .overflow_hidden()
10300                        .child(completion),
10301                )
10302                .when_some(
10303                    keybind_display.displayed_keystroke.as_ref(),
10304                    |el, keystroke| {
10305                        let key_color = if !has_completion {
10306                            Color::Muted
10307                        } else {
10308                            Color::Default
10309                        };
10310
10311                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10312                            el.child(
10313                                h_flex()
10314                                    .h_full()
10315                                    .border_l_1()
10316                                    .rounded_r_lg()
10317                                    .border_color(cx.theme().colors().border)
10318                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10319                                    .gap_1()
10320                                    .py_1()
10321                                    .px_2()
10322                                    .child(self.render_edit_prediction_popover_keystroke(
10323                                        keystroke, key_color, cx,
10324                                    ))
10325                                    .child(Label::new("Preview").into_any_element())
10326                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10327                            )
10328                        } else {
10329                            el.child(
10330                                h_flex()
10331                                    .h_full()
10332                                    .border_l_1()
10333                                    .rounded_r_lg()
10334                                    .border_color(cx.theme().colors().border)
10335                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10336                                    .gap_1()
10337                                    .py_1()
10338                                    .px_2()
10339                                    .child(self.render_edit_prediction_popover_keystroke(
10340                                        keystroke, key_color, cx,
10341                                    ))
10342                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10343                            )
10344                        }
10345                    },
10346                )
10347                .into_any(),
10348        )
10349    }
10350
10351    fn render_edit_prediction_cursor_popover_preview(
10352        &self,
10353        completion: &EditPredictionState,
10354        cursor_point: Point,
10355        style: &EditorStyle,
10356        cx: &mut Context<Editor>,
10357    ) -> Option<Div> {
10358        use text::ToPoint as _;
10359
10360        fn render_relative_row_jump(
10361            prefix: impl Into<String>,
10362            current_row: u32,
10363            target_row: u32,
10364        ) -> Div {
10365            let (row_diff, arrow) = if target_row < current_row {
10366                (current_row - target_row, IconName::ArrowUp)
10367            } else {
10368                (target_row - current_row, IconName::ArrowDown)
10369            };
10370
10371            h_flex()
10372                .child(
10373                    Label::new(format!("{}{}", prefix.into(), row_diff))
10374                        .color(Color::Muted)
10375                        .size(LabelSize::Small),
10376                )
10377                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10378        }
10379
10380        let supports_jump = self
10381            .edit_prediction_provider
10382            .as_ref()
10383            .map(|provider| provider.provider.supports_jump_to_edit())
10384            .unwrap_or(true);
10385
10386        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10387
10388        match &completion.completion {
10389            EditPrediction::MoveWithin {
10390                target, snapshot, ..
10391            } => {
10392                if !supports_jump {
10393                    return None;
10394                }
10395
10396                Some(
10397                    h_flex()
10398                        .px_2()
10399                        .gap_2()
10400                        .flex_1()
10401                        .child(
10402                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10403                                Icon::new(icons.down)
10404                            } else {
10405                                Icon::new(icons.up)
10406                            },
10407                        )
10408                        .child(Label::new("Jump to Edit")),
10409                )
10410            }
10411            EditPrediction::MoveOutside { snapshot, .. } => {
10412                let file_name = snapshot
10413                    .file()
10414                    .map(|file| file.file_name(cx))
10415                    .unwrap_or("untitled");
10416                Some(
10417                    h_flex()
10418                        .px_2()
10419                        .gap_2()
10420                        .flex_1()
10421                        .child(Icon::new(icons.base))
10422                        .child(Label::new(format!("Jump to {file_name}"))),
10423                )
10424            }
10425            EditPrediction::Edit {
10426                edits,
10427                edit_preview,
10428                snapshot,
10429                ..
10430            } => {
10431                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10432
10433                let (highlighted_edits, has_more_lines) =
10434                    if let Some(edit_preview) = edit_preview.as_ref() {
10435                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10436                            .first_line_preview()
10437                    } else {
10438                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10439                    };
10440
10441                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10442                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10443
10444                let preview = h_flex()
10445                    .gap_1()
10446                    .min_w_16()
10447                    .child(styled_text)
10448                    .when(has_more_lines, |parent| parent.child(""));
10449
10450                let left = if supports_jump && first_edit_row != cursor_point.row {
10451                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10452                        .into_any_element()
10453                } else {
10454                    Icon::new(icons.base).into_any_element()
10455                };
10456
10457                Some(
10458                    h_flex()
10459                        .h_full()
10460                        .flex_1()
10461                        .gap_2()
10462                        .pr_1()
10463                        .overflow_x_hidden()
10464                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10465                        .child(left)
10466                        .child(preview),
10467                )
10468            }
10469        }
10470    }
10471
10472    pub fn render_context_menu(
10473        &mut self,
10474        max_height_in_lines: u32,
10475        window: &mut Window,
10476        cx: &mut Context<Editor>,
10477    ) -> Option<AnyElement> {
10478        let menu = self.context_menu.borrow();
10479        let menu = menu.as_ref()?;
10480        if !menu.visible() {
10481            return None;
10482        };
10483        self.style
10484            .as_ref()
10485            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10486    }
10487
10488    fn render_context_menu_aside(
10489        &mut self,
10490        max_size: Size<Pixels>,
10491        window: &mut Window,
10492        cx: &mut Context<Editor>,
10493    ) -> Option<AnyElement> {
10494        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10495            if menu.visible() {
10496                menu.render_aside(max_size, window, cx)
10497            } else {
10498                None
10499            }
10500        })
10501    }
10502
10503    fn hide_context_menu(
10504        &mut self,
10505        window: &mut Window,
10506        cx: &mut Context<Self>,
10507    ) -> Option<CodeContextMenu> {
10508        cx.notify();
10509        self.completion_tasks.clear();
10510        let context_menu = self.context_menu.borrow_mut().take();
10511        self.stale_edit_prediction_in_menu.take();
10512        self.update_visible_edit_prediction(window, cx);
10513        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10514            && let Some(completion_provider) = &self.completion_provider
10515        {
10516            completion_provider.selection_changed(None, window, cx);
10517        }
10518        context_menu
10519    }
10520
10521    fn show_snippet_choices(
10522        &mut self,
10523        choices: &Vec<String>,
10524        selection: Range<Anchor>,
10525        cx: &mut Context<Self>,
10526    ) {
10527        let Some((_, buffer, _)) = self
10528            .buffer()
10529            .read(cx)
10530            .excerpt_containing(selection.start, cx)
10531        else {
10532            return;
10533        };
10534        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10535        else {
10536            return;
10537        };
10538        if buffer != end_buffer {
10539            log::error!("expected anchor range to have matching buffer IDs");
10540            return;
10541        }
10542
10543        let id = post_inc(&mut self.next_completion_id);
10544        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10545        let mut context_menu = self.context_menu.borrow_mut();
10546        let old_menu = context_menu.take();
10547        *context_menu = Some(CodeContextMenu::Completions(
10548            CompletionsMenu::new_snippet_choices(
10549                id,
10550                true,
10551                choices,
10552                selection,
10553                buffer,
10554                old_menu.map(|menu| menu.primary_scroll_handle()),
10555                snippet_sort_order,
10556            ),
10557        ));
10558    }
10559
10560    pub fn insert_snippet(
10561        &mut self,
10562        insertion_ranges: &[Range<MultiBufferOffset>],
10563        snippet: Snippet,
10564        window: &mut Window,
10565        cx: &mut Context<Self>,
10566    ) -> Result<()> {
10567        struct Tabstop<T> {
10568            is_end_tabstop: bool,
10569            ranges: Vec<Range<T>>,
10570            choices: Option<Vec<String>>,
10571        }
10572
10573        let tabstops = self.buffer.update(cx, |buffer, cx| {
10574            let snippet_text: Arc<str> = snippet.text.clone().into();
10575            let edits = insertion_ranges
10576                .iter()
10577                .cloned()
10578                .map(|range| (range, snippet_text.clone()));
10579            let autoindent_mode = AutoindentMode::Block {
10580                original_indent_columns: Vec::new(),
10581            };
10582            buffer.edit(edits, Some(autoindent_mode), cx);
10583
10584            let snapshot = &*buffer.read(cx);
10585            let snippet = &snippet;
10586            snippet
10587                .tabstops
10588                .iter()
10589                .map(|tabstop| {
10590                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10591                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10592                    });
10593                    let mut tabstop_ranges = tabstop
10594                        .ranges
10595                        .iter()
10596                        .flat_map(|tabstop_range| {
10597                            let mut delta = 0_isize;
10598                            insertion_ranges.iter().map(move |insertion_range| {
10599                                let insertion_start = insertion_range.start + delta;
10600                                delta += snippet.text.len() as isize
10601                                    - (insertion_range.end - insertion_range.start) as isize;
10602
10603                                let start =
10604                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10605                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10606                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10607                            })
10608                        })
10609                        .collect::<Vec<_>>();
10610                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10611
10612                    Tabstop {
10613                        is_end_tabstop,
10614                        ranges: tabstop_ranges,
10615                        choices: tabstop.choices.clone(),
10616                    }
10617                })
10618                .collect::<Vec<_>>()
10619        });
10620        if let Some(tabstop) = tabstops.first() {
10621            self.change_selections(Default::default(), window, cx, |s| {
10622                // Reverse order so that the first range is the newest created selection.
10623                // Completions will use it and autoscroll will prioritize it.
10624                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10625            });
10626
10627            if let Some(choices) = &tabstop.choices
10628                && let Some(selection) = tabstop.ranges.first()
10629            {
10630                self.show_snippet_choices(choices, selection.clone(), cx)
10631            }
10632
10633            // If we're already at the last tabstop and it's at the end of the snippet,
10634            // we're done, we don't need to keep the state around.
10635            if !tabstop.is_end_tabstop {
10636                let choices = tabstops
10637                    .iter()
10638                    .map(|tabstop| tabstop.choices.clone())
10639                    .collect();
10640
10641                let ranges = tabstops
10642                    .into_iter()
10643                    .map(|tabstop| tabstop.ranges)
10644                    .collect::<Vec<_>>();
10645
10646                self.snippet_stack.push(SnippetState {
10647                    active_index: 0,
10648                    ranges,
10649                    choices,
10650                });
10651            }
10652
10653            // Check whether the just-entered snippet ends with an auto-closable bracket.
10654            if self.autoclose_regions.is_empty() {
10655                let snapshot = self.buffer.read(cx).snapshot(cx);
10656                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10657                    let selection_head = selection.head();
10658                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10659                        continue;
10660                    };
10661
10662                    let mut bracket_pair = None;
10663                    let max_lookup_length = scope
10664                        .brackets()
10665                        .map(|(pair, _)| {
10666                            pair.start
10667                                .as_str()
10668                                .chars()
10669                                .count()
10670                                .max(pair.end.as_str().chars().count())
10671                        })
10672                        .max();
10673                    if let Some(max_lookup_length) = max_lookup_length {
10674                        let next_text = snapshot
10675                            .chars_at(selection_head)
10676                            .take(max_lookup_length)
10677                            .collect::<String>();
10678                        let prev_text = snapshot
10679                            .reversed_chars_at(selection_head)
10680                            .take(max_lookup_length)
10681                            .collect::<String>();
10682
10683                        for (pair, enabled) in scope.brackets() {
10684                            if enabled
10685                                && pair.close
10686                                && prev_text.starts_with(pair.start.as_str())
10687                                && next_text.starts_with(pair.end.as_str())
10688                            {
10689                                bracket_pair = Some(pair.clone());
10690                                break;
10691                            }
10692                        }
10693                    }
10694
10695                    if let Some(pair) = bracket_pair {
10696                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10697                        let autoclose_enabled =
10698                            self.use_autoclose && snapshot_settings.use_autoclose;
10699                        if autoclose_enabled {
10700                            let start = snapshot.anchor_after(selection_head);
10701                            let end = snapshot.anchor_after(selection_head);
10702                            self.autoclose_regions.push(AutocloseRegion {
10703                                selection_id: selection.id,
10704                                range: start..end,
10705                                pair,
10706                            });
10707                        }
10708                    }
10709                }
10710            }
10711        }
10712        Ok(())
10713    }
10714
10715    pub fn move_to_next_snippet_tabstop(
10716        &mut self,
10717        window: &mut Window,
10718        cx: &mut Context<Self>,
10719    ) -> bool {
10720        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10721    }
10722
10723    pub fn move_to_prev_snippet_tabstop(
10724        &mut self,
10725        window: &mut Window,
10726        cx: &mut Context<Self>,
10727    ) -> bool {
10728        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10729    }
10730
10731    pub fn move_to_snippet_tabstop(
10732        &mut self,
10733        bias: Bias,
10734        window: &mut Window,
10735        cx: &mut Context<Self>,
10736    ) -> bool {
10737        if let Some(mut snippet) = self.snippet_stack.pop() {
10738            match bias {
10739                Bias::Left => {
10740                    if snippet.active_index > 0 {
10741                        snippet.active_index -= 1;
10742                    } else {
10743                        self.snippet_stack.push(snippet);
10744                        return false;
10745                    }
10746                }
10747                Bias::Right => {
10748                    if snippet.active_index + 1 < snippet.ranges.len() {
10749                        snippet.active_index += 1;
10750                    } else {
10751                        self.snippet_stack.push(snippet);
10752                        return false;
10753                    }
10754                }
10755            }
10756            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10757                self.change_selections(Default::default(), window, cx, |s| {
10758                    // Reverse order so that the first range is the newest created selection.
10759                    // Completions will use it and autoscroll will prioritize it.
10760                    s.select_ranges(current_ranges.iter().rev().cloned())
10761                });
10762
10763                if let Some(choices) = &snippet.choices[snippet.active_index]
10764                    && let Some(selection) = current_ranges.first()
10765                {
10766                    self.show_snippet_choices(choices, selection.clone(), cx);
10767                }
10768
10769                // If snippet state is not at the last tabstop, push it back on the stack
10770                if snippet.active_index + 1 < snippet.ranges.len() {
10771                    self.snippet_stack.push(snippet);
10772                }
10773                return true;
10774            }
10775        }
10776
10777        false
10778    }
10779
10780    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10781        self.transact(window, cx, |this, window, cx| {
10782            this.select_all(&SelectAll, window, cx);
10783            this.insert("", window, cx);
10784        });
10785    }
10786
10787    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10788        if self.read_only(cx) {
10789            return;
10790        }
10791        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10792        self.transact(window, cx, |this, window, cx| {
10793            this.select_autoclose_pair(window, cx);
10794
10795            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10796
10797            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10798            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10799            for selection in &mut selections {
10800                if selection.is_empty() {
10801                    let old_head = selection.head();
10802                    let mut new_head =
10803                        movement::left(&display_map, old_head.to_display_point(&display_map))
10804                            .to_point(&display_map);
10805                    if let Some((buffer, line_buffer_range)) = display_map
10806                        .buffer_snapshot()
10807                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10808                    {
10809                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10810                        let indent_len = match indent_size.kind {
10811                            IndentKind::Space => {
10812                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10813                            }
10814                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10815                        };
10816                        if old_head.column <= indent_size.len && old_head.column > 0 {
10817                            let indent_len = indent_len.get();
10818                            new_head = cmp::min(
10819                                new_head,
10820                                MultiBufferPoint::new(
10821                                    old_head.row,
10822                                    ((old_head.column - 1) / indent_len) * indent_len,
10823                                ),
10824                            );
10825                        }
10826                    }
10827
10828                    selection.set_head(new_head, SelectionGoal::None);
10829                }
10830            }
10831
10832            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10833            this.insert("", window, cx);
10834            linked_edits.apply_with_left_expansion(cx);
10835            this.refresh_edit_prediction(true, false, window, cx);
10836            refresh_linked_ranges(this, window, cx);
10837        });
10838    }
10839
10840    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10841        if self.read_only(cx) {
10842            return;
10843        }
10844        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10845        self.transact(window, cx, |this, window, cx| {
10846            this.change_selections(Default::default(), window, cx, |s| {
10847                s.move_with(&mut |map, selection| {
10848                    if selection.is_empty() {
10849                        let cursor = movement::right(map, selection.head());
10850                        selection.end = cursor;
10851                        selection.reversed = true;
10852                        selection.goal = SelectionGoal::None;
10853                    }
10854                })
10855            });
10856            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10857            this.insert("", window, cx);
10858            linked_edits.apply(cx);
10859            this.refresh_edit_prediction(true, false, window, cx);
10860            refresh_linked_ranges(this, window, cx);
10861        });
10862    }
10863
10864    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10865        if self.mode.is_single_line() {
10866            cx.propagate();
10867            return;
10868        }
10869
10870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10871        if self.move_to_prev_snippet_tabstop(window, cx) {
10872            return;
10873        }
10874        self.outdent(&Outdent, window, cx);
10875    }
10876
10877    pub fn next_snippet_tabstop(
10878        &mut self,
10879        _: &NextSnippetTabstop,
10880        window: &mut Window,
10881        cx: &mut Context<Self>,
10882    ) {
10883        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10884            cx.propagate();
10885            return;
10886        }
10887
10888        if self.move_to_next_snippet_tabstop(window, cx) {
10889            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10890            return;
10891        }
10892        cx.propagate();
10893    }
10894
10895    pub fn previous_snippet_tabstop(
10896        &mut self,
10897        _: &PreviousSnippetTabstop,
10898        window: &mut Window,
10899        cx: &mut Context<Self>,
10900    ) {
10901        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10902            cx.propagate();
10903            return;
10904        }
10905
10906        if self.move_to_prev_snippet_tabstop(window, cx) {
10907            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10908            return;
10909        }
10910        cx.propagate();
10911    }
10912
10913    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10914        if self.mode.is_single_line() {
10915            cx.propagate();
10916            return;
10917        }
10918
10919        if self.move_to_next_snippet_tabstop(window, cx) {
10920            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10921            return;
10922        }
10923        if self.read_only(cx) {
10924            return;
10925        }
10926        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10927        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10928        let buffer = self.buffer.read(cx);
10929        let snapshot = buffer.snapshot(cx);
10930        let rows_iter = selections.iter().map(|s| s.head().row);
10931        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10932
10933        let has_some_cursor_in_whitespace = selections
10934            .iter()
10935            .filter(|selection| selection.is_empty())
10936            .any(|selection| {
10937                let cursor = selection.head();
10938                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10939                cursor.column < current_indent.len
10940            });
10941
10942        let mut edits = Vec::new();
10943        let mut prev_edited_row = 0;
10944        let mut row_delta = 0;
10945        for selection in &mut selections {
10946            if selection.start.row != prev_edited_row {
10947                row_delta = 0;
10948            }
10949            prev_edited_row = selection.end.row;
10950
10951            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10952            if selection.is_empty() {
10953                let cursor = selection.head();
10954                let settings = buffer.language_settings_at(cursor, cx);
10955                if settings.indent_list_on_tab {
10956                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10957                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10958                            row_delta = Self::indent_selection(
10959                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10960                            );
10961                            continue;
10962                        }
10963                    }
10964                }
10965            }
10966
10967            // If the selection is non-empty, then increase the indentation of the selected lines.
10968            if !selection.is_empty() {
10969                row_delta =
10970                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10971                continue;
10972            }
10973
10974            let cursor = selection.head();
10975            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10976            if let Some(suggested_indent) =
10977                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10978            {
10979                // Don't do anything if already at suggested indent
10980                // and there is any other cursor which is not
10981                if has_some_cursor_in_whitespace
10982                    && cursor.column == current_indent.len
10983                    && current_indent.len == suggested_indent.len
10984                {
10985                    continue;
10986                }
10987
10988                // Adjust line and move cursor to suggested indent
10989                // if cursor is not at suggested indent
10990                if cursor.column < suggested_indent.len
10991                    && cursor.column <= current_indent.len
10992                    && current_indent.len <= suggested_indent.len
10993                {
10994                    selection.start = Point::new(cursor.row, suggested_indent.len);
10995                    selection.end = selection.start;
10996                    if row_delta == 0 {
10997                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10998                            cursor.row,
10999                            current_indent,
11000                            suggested_indent,
11001                        ));
11002                        row_delta = suggested_indent.len - current_indent.len;
11003                    }
11004                    continue;
11005                }
11006
11007                // If current indent is more than suggested indent
11008                // only move cursor to current indent and skip indent
11009                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11010                    selection.start = Point::new(cursor.row, current_indent.len);
11011                    selection.end = selection.start;
11012                    continue;
11013                }
11014            }
11015
11016            // Otherwise, insert a hard or soft tab.
11017            let settings = buffer.language_settings_at(cursor, cx);
11018            let tab_size = if settings.hard_tabs {
11019                IndentSize::tab()
11020            } else {
11021                let tab_size = settings.tab_size.get();
11022                let indent_remainder = snapshot
11023                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11024                    .flat_map(str::chars)
11025                    .fold(row_delta % tab_size, |counter: u32, c| {
11026                        if c == '\t' {
11027                            0
11028                        } else {
11029                            (counter + 1) % tab_size
11030                        }
11031                    });
11032
11033                let chars_to_next_tab_stop = tab_size - indent_remainder;
11034                IndentSize::spaces(chars_to_next_tab_stop)
11035            };
11036            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11037            selection.end = selection.start;
11038            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11039            row_delta += tab_size.len;
11040        }
11041
11042        self.transact(window, cx, |this, window, cx| {
11043            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11044            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11045            this.refresh_edit_prediction(true, false, window, cx);
11046        });
11047    }
11048
11049    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11050        if self.read_only(cx) {
11051            return;
11052        }
11053        if self.mode.is_single_line() {
11054            cx.propagate();
11055            return;
11056        }
11057
11058        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11059        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11060        let mut prev_edited_row = 0;
11061        let mut row_delta = 0;
11062        let mut edits = Vec::new();
11063        let buffer = self.buffer.read(cx);
11064        let snapshot = buffer.snapshot(cx);
11065        for selection in &mut selections {
11066            if selection.start.row != prev_edited_row {
11067                row_delta = 0;
11068            }
11069            prev_edited_row = selection.end.row;
11070
11071            row_delta =
11072                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11073        }
11074
11075        self.transact(window, cx, |this, window, cx| {
11076            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11077            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11078        });
11079    }
11080
11081    fn indent_selection(
11082        buffer: &MultiBuffer,
11083        snapshot: &MultiBufferSnapshot,
11084        selection: &mut Selection<Point>,
11085        edits: &mut Vec<(Range<Point>, String)>,
11086        delta_for_start_row: u32,
11087        cx: &App,
11088    ) -> u32 {
11089        let settings = buffer.language_settings_at(selection.start, cx);
11090        let tab_size = settings.tab_size.get();
11091        let indent_kind = if settings.hard_tabs {
11092            IndentKind::Tab
11093        } else {
11094            IndentKind::Space
11095        };
11096        let mut start_row = selection.start.row;
11097        let mut end_row = selection.end.row + 1;
11098
11099        // If a selection ends at the beginning of a line, don't indent
11100        // that last line.
11101        if selection.end.column == 0 && selection.end.row > selection.start.row {
11102            end_row -= 1;
11103        }
11104
11105        // Avoid re-indenting a row that has already been indented by a
11106        // previous selection, but still update this selection's column
11107        // to reflect that indentation.
11108        if delta_for_start_row > 0 {
11109            start_row += 1;
11110            selection.start.column += delta_for_start_row;
11111            if selection.end.row == selection.start.row {
11112                selection.end.column += delta_for_start_row;
11113            }
11114        }
11115
11116        let mut delta_for_end_row = 0;
11117        let has_multiple_rows = start_row + 1 != end_row;
11118        for row in start_row..end_row {
11119            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11120            let indent_delta = match (current_indent.kind, indent_kind) {
11121                (IndentKind::Space, IndentKind::Space) => {
11122                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11123                    IndentSize::spaces(columns_to_next_tab_stop)
11124                }
11125                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11126                (_, IndentKind::Tab) => IndentSize::tab(),
11127            };
11128
11129            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11130                0
11131            } else {
11132                selection.start.column
11133            };
11134            let row_start = Point::new(row, start);
11135            edits.push((
11136                row_start..row_start,
11137                indent_delta.chars().collect::<String>(),
11138            ));
11139
11140            // Update this selection's endpoints to reflect the indentation.
11141            if row == selection.start.row {
11142                selection.start.column += indent_delta.len;
11143            }
11144            if row == selection.end.row {
11145                selection.end.column += indent_delta.len;
11146                delta_for_end_row = indent_delta.len;
11147            }
11148        }
11149
11150        if selection.start.row == selection.end.row {
11151            delta_for_start_row + delta_for_end_row
11152        } else {
11153            delta_for_end_row
11154        }
11155    }
11156
11157    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11158        if self.read_only(cx) {
11159            return;
11160        }
11161        if self.mode.is_single_line() {
11162            cx.propagate();
11163            return;
11164        }
11165
11166        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11167        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11168        let selections = self.selections.all::<Point>(&display_map);
11169        let mut deletion_ranges = Vec::new();
11170        let mut last_outdent = None;
11171        {
11172            let buffer = self.buffer.read(cx);
11173            let snapshot = buffer.snapshot(cx);
11174            for selection in &selections {
11175                let settings = buffer.language_settings_at(selection.start, cx);
11176                let tab_size = settings.tab_size.get();
11177                let mut rows = selection.spanned_rows(false, &display_map);
11178
11179                // Avoid re-outdenting a row that has already been outdented by a
11180                // previous selection.
11181                if let Some(last_row) = last_outdent
11182                    && last_row == rows.start
11183                {
11184                    rows.start = rows.start.next_row();
11185                }
11186                let has_multiple_rows = rows.len() > 1;
11187                for row in rows.iter_rows() {
11188                    let indent_size = snapshot.indent_size_for_line(row);
11189                    if indent_size.len > 0 {
11190                        let deletion_len = match indent_size.kind {
11191                            IndentKind::Space => {
11192                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11193                                if columns_to_prev_tab_stop == 0 {
11194                                    tab_size
11195                                } else {
11196                                    columns_to_prev_tab_stop
11197                                }
11198                            }
11199                            IndentKind::Tab => 1,
11200                        };
11201                        let start = if has_multiple_rows
11202                            || deletion_len > selection.start.column
11203                            || indent_size.len < selection.start.column
11204                        {
11205                            0
11206                        } else {
11207                            selection.start.column - deletion_len
11208                        };
11209                        deletion_ranges.push(
11210                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11211                        );
11212                        last_outdent = Some(row);
11213                    }
11214                }
11215            }
11216        }
11217
11218        self.transact(window, cx, |this, window, cx| {
11219            this.buffer.update(cx, |buffer, cx| {
11220                let empty_str: Arc<str> = Arc::default();
11221                buffer.edit(
11222                    deletion_ranges
11223                        .into_iter()
11224                        .map(|range| (range, empty_str.clone())),
11225                    None,
11226                    cx,
11227                );
11228            });
11229            let selections = this
11230                .selections
11231                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11232            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11233        });
11234    }
11235
11236    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11237        if self.read_only(cx) {
11238            return;
11239        }
11240        if self.mode.is_single_line() {
11241            cx.propagate();
11242            return;
11243        }
11244
11245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11246        let selections = self
11247            .selections
11248            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11249            .into_iter()
11250            .map(|s| s.range());
11251
11252        self.transact(window, cx, |this, window, cx| {
11253            this.buffer.update(cx, |buffer, cx| {
11254                buffer.autoindent_ranges(selections, cx);
11255            });
11256            let selections = this
11257                .selections
11258                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11259            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11260        });
11261    }
11262
11263    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11264        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11265        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11266        let selections = self.selections.all::<Point>(&display_map);
11267
11268        let mut new_cursors = Vec::new();
11269        let mut edit_ranges = Vec::new();
11270        let mut selections = selections.iter().peekable();
11271        while let Some(selection) = selections.next() {
11272            let mut rows = selection.spanned_rows(false, &display_map);
11273
11274            // Accumulate contiguous regions of rows that we want to delete.
11275            while let Some(next_selection) = selections.peek() {
11276                let next_rows = next_selection.spanned_rows(false, &display_map);
11277                if next_rows.start <= rows.end {
11278                    rows.end = next_rows.end;
11279                    selections.next().unwrap();
11280                } else {
11281                    break;
11282                }
11283            }
11284
11285            let buffer = display_map.buffer_snapshot();
11286            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11287            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11288                // If there's a line after the range, delete the \n from the end of the row range
11289                (
11290                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11291                    rows.end,
11292                )
11293            } else {
11294                // If there isn't a line after the range, delete the \n from the line before the
11295                // start of the row range
11296                edit_start = edit_start.saturating_sub_usize(1);
11297                (buffer.len(), rows.start.previous_row())
11298            };
11299
11300            let text_layout_details = self.text_layout_details(window, cx);
11301            let x = display_map.x_for_display_point(
11302                selection.head().to_display_point(&display_map),
11303                &text_layout_details,
11304            );
11305            let row = Point::new(target_row.0, 0)
11306                .to_display_point(&display_map)
11307                .row();
11308            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11309
11310            new_cursors.push((
11311                selection.id,
11312                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11313                SelectionGoal::None,
11314            ));
11315            edit_ranges.push(edit_start..edit_end);
11316        }
11317
11318        self.transact(window, cx, |this, window, cx| {
11319            let buffer = this.buffer.update(cx, |buffer, cx| {
11320                let empty_str: Arc<str> = Arc::default();
11321                buffer.edit(
11322                    edit_ranges
11323                        .into_iter()
11324                        .map(|range| (range, empty_str.clone())),
11325                    None,
11326                    cx,
11327                );
11328                buffer.snapshot(cx)
11329            });
11330            let new_selections = new_cursors
11331                .into_iter()
11332                .map(|(id, cursor, goal)| {
11333                    let cursor = cursor.to_point(&buffer);
11334                    Selection {
11335                        id,
11336                        start: cursor,
11337                        end: cursor,
11338                        reversed: false,
11339                        goal,
11340                    }
11341                })
11342                .collect();
11343
11344            this.change_selections(Default::default(), window, cx, |s| {
11345                s.select(new_selections);
11346            });
11347        });
11348    }
11349
11350    pub fn join_lines_impl(
11351        &mut self,
11352        insert_whitespace: bool,
11353        window: &mut Window,
11354        cx: &mut Context<Self>,
11355    ) {
11356        if self.read_only(cx) {
11357            return;
11358        }
11359        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11360        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11361            let start = MultiBufferRow(selection.start.row);
11362            // Treat single line selections as if they include the next line. Otherwise this action
11363            // would do nothing for single line selections individual cursors.
11364            let end = if selection.start.row == selection.end.row {
11365                MultiBufferRow(selection.start.row + 1)
11366            } else if selection.end.column == 0 {
11367                // If the selection ends at the start of a line, it's logically at the end of the
11368                // previous line (plus its newline).
11369                // Don't include the end line unless there's only one line selected.
11370                if selection.start.row + 1 == selection.end.row {
11371                    MultiBufferRow(selection.end.row)
11372                } else {
11373                    MultiBufferRow(selection.end.row - 1)
11374                }
11375            } else {
11376                MultiBufferRow(selection.end.row)
11377            };
11378
11379            if let Some(last_row_range) = row_ranges.last_mut()
11380                && start <= last_row_range.end
11381            {
11382                last_row_range.end = end;
11383                continue;
11384            }
11385            row_ranges.push(start..end);
11386        }
11387
11388        let snapshot = self.buffer.read(cx).snapshot(cx);
11389        let mut cursor_positions = Vec::new();
11390        for row_range in &row_ranges {
11391            let anchor = snapshot.anchor_before(Point::new(
11392                row_range.end.previous_row().0,
11393                snapshot.line_len(row_range.end.previous_row()),
11394            ));
11395            cursor_positions.push(anchor..anchor);
11396        }
11397
11398        self.transact(window, cx, |this, window, cx| {
11399            for row_range in row_ranges.into_iter().rev() {
11400                for row in row_range.iter_rows().rev() {
11401                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11402                    let next_line_row = row.next_row();
11403                    let indent = snapshot.indent_size_for_line(next_line_row);
11404                    let mut join_start_column = indent.len;
11405
11406                    if let Some(language_scope) =
11407                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11408                    {
11409                        let line_end =
11410                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11411                        let line_text_after_indent = snapshot
11412                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11413                            .collect::<String>();
11414
11415                        if !line_text_after_indent.is_empty() {
11416                            let block_prefix = language_scope
11417                                .block_comment()
11418                                .map(|c| c.prefix.as_ref())
11419                                .filter(|p| !p.is_empty());
11420                            let doc_prefix = language_scope
11421                                .documentation_comment()
11422                                .map(|c| c.prefix.as_ref())
11423                                .filter(|p| !p.is_empty());
11424                            let all_prefixes = language_scope
11425                                .line_comment_prefixes()
11426                                .iter()
11427                                .map(|p| p.as_ref())
11428                                .chain(block_prefix)
11429                                .chain(doc_prefix)
11430                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11431
11432                            let mut longest_prefix_len = None;
11433                            for prefix in all_prefixes {
11434                                let trimmed = prefix.trim_end();
11435                                if line_text_after_indent.starts_with(trimmed) {
11436                                    let candidate_len =
11437                                        if line_text_after_indent.starts_with(prefix) {
11438                                            prefix.len()
11439                                        } else {
11440                                            trimmed.len()
11441                                        };
11442                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11443                                        longest_prefix_len = Some(candidate_len);
11444                                    }
11445                                }
11446                            }
11447
11448                            if let Some(prefix_len) = longest_prefix_len {
11449                                join_start_column =
11450                                    join_start_column.saturating_add(prefix_len as u32);
11451                            }
11452                        }
11453                    }
11454
11455                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11456
11457                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11458                        && insert_whitespace
11459                    {
11460                        " "
11461                    } else {
11462                        ""
11463                    };
11464
11465                    this.buffer.update(cx, |buffer, cx| {
11466                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11467                    });
11468                }
11469            }
11470
11471            this.change_selections(Default::default(), window, cx, |s| {
11472                s.select_anchor_ranges(cursor_positions)
11473            });
11474        });
11475    }
11476
11477    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11478        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11479        self.join_lines_impl(true, window, cx);
11480    }
11481
11482    pub fn sort_lines_case_sensitive(
11483        &mut self,
11484        _: &SortLinesCaseSensitive,
11485        window: &mut Window,
11486        cx: &mut Context<Self>,
11487    ) {
11488        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11489    }
11490
11491    pub fn sort_lines_by_length(
11492        &mut self,
11493        _: &SortLinesByLength,
11494        window: &mut Window,
11495        cx: &mut Context<Self>,
11496    ) {
11497        self.manipulate_immutable_lines(window, cx, |lines| {
11498            lines.sort_by_key(|&line| line.chars().count())
11499        })
11500    }
11501
11502    pub fn sort_lines_case_insensitive(
11503        &mut self,
11504        _: &SortLinesCaseInsensitive,
11505        window: &mut Window,
11506        cx: &mut Context<Self>,
11507    ) {
11508        self.manipulate_immutable_lines(window, cx, |lines| {
11509            lines.sort_by_key(|line| line.to_lowercase())
11510        })
11511    }
11512
11513    pub fn unique_lines_case_insensitive(
11514        &mut self,
11515        _: &UniqueLinesCaseInsensitive,
11516        window: &mut Window,
11517        cx: &mut Context<Self>,
11518    ) {
11519        self.manipulate_immutable_lines(window, cx, |lines| {
11520            let mut seen = HashSet::default();
11521            lines.retain(|line| seen.insert(line.to_lowercase()));
11522        })
11523    }
11524
11525    pub fn unique_lines_case_sensitive(
11526        &mut self,
11527        _: &UniqueLinesCaseSensitive,
11528        window: &mut Window,
11529        cx: &mut Context<Self>,
11530    ) {
11531        self.manipulate_immutable_lines(window, cx, |lines| {
11532            let mut seen = HashSet::default();
11533            lines.retain(|line| seen.insert(*line));
11534        })
11535    }
11536
11537    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11538        let snapshot = self.buffer.read(cx).snapshot(cx);
11539        for selection in self.selections.disjoint_anchors_arc().iter() {
11540            if snapshot
11541                .language_at(selection.start)
11542                .and_then(|lang| lang.config().wrap_characters.as_ref())
11543                .is_some()
11544            {
11545                return true;
11546            }
11547        }
11548        false
11549    }
11550
11551    fn wrap_selections_in_tag(
11552        &mut self,
11553        _: &WrapSelectionsInTag,
11554        window: &mut Window,
11555        cx: &mut Context<Self>,
11556    ) {
11557        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11558
11559        let snapshot = self.buffer.read(cx).snapshot(cx);
11560
11561        let mut edits = Vec::new();
11562        let mut boundaries = Vec::new();
11563
11564        for selection in self
11565            .selections
11566            .all_adjusted(&self.display_snapshot(cx))
11567            .iter()
11568        {
11569            let Some(wrap_config) = snapshot
11570                .language_at(selection.start)
11571                .and_then(|lang| lang.config().wrap_characters.clone())
11572            else {
11573                continue;
11574            };
11575
11576            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11577            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11578
11579            let start_before = snapshot.anchor_before(selection.start);
11580            let end_after = snapshot.anchor_after(selection.end);
11581
11582            edits.push((start_before..start_before, open_tag));
11583            edits.push((end_after..end_after, close_tag));
11584
11585            boundaries.push((
11586                start_before,
11587                end_after,
11588                wrap_config.start_prefix.len(),
11589                wrap_config.end_suffix.len(),
11590            ));
11591        }
11592
11593        if edits.is_empty() {
11594            return;
11595        }
11596
11597        self.transact(window, cx, |this, window, cx| {
11598            let buffer = this.buffer.update(cx, |buffer, cx| {
11599                buffer.edit(edits, None, cx);
11600                buffer.snapshot(cx)
11601            });
11602
11603            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11604            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11605                boundaries.into_iter()
11606            {
11607                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11608                let close_offset = end_after
11609                    .to_offset(&buffer)
11610                    .saturating_sub_usize(end_suffix_len);
11611                new_selections.push(open_offset..open_offset);
11612                new_selections.push(close_offset..close_offset);
11613            }
11614
11615            this.change_selections(Default::default(), window, cx, |s| {
11616                s.select_ranges(new_selections);
11617            });
11618
11619            this.request_autoscroll(Autoscroll::fit(), cx);
11620        });
11621    }
11622
11623    pub fn toggle_read_only(
11624        &mut self,
11625        _: &workspace::ToggleReadOnlyFile,
11626        _: &mut Window,
11627        cx: &mut Context<Self>,
11628    ) {
11629        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11630            buffer.update(cx, |buffer, cx| {
11631                buffer.set_capability(
11632                    match buffer.capability() {
11633                        Capability::ReadWrite => Capability::Read,
11634                        Capability::Read => Capability::ReadWrite,
11635                        Capability::ReadOnly => Capability::ReadOnly,
11636                    },
11637                    cx,
11638                );
11639            })
11640        }
11641    }
11642
11643    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11644        let Some(project) = self.project.clone() else {
11645            return;
11646        };
11647        let task = self.reload(project, window, cx);
11648        self.detach_and_notify_err(task, window, cx);
11649    }
11650
11651    pub fn restore_file(
11652        &mut self,
11653        _: &::git::RestoreFile,
11654        window: &mut Window,
11655        cx: &mut Context<Self>,
11656    ) {
11657        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11658        let mut buffer_ids = HashSet::default();
11659        let snapshot = self.buffer().read(cx).snapshot(cx);
11660        for selection in self
11661            .selections
11662            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11663        {
11664            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11665        }
11666
11667        let buffer = self.buffer().read(cx);
11668        let ranges = buffer_ids
11669            .into_iter()
11670            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11671            .collect::<Vec<_>>();
11672
11673        self.restore_hunks_in_ranges(ranges, window, cx);
11674    }
11675
11676    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11677        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11678        let selections = self
11679            .selections
11680            .all(&self.display_snapshot(cx))
11681            .into_iter()
11682            .map(|s| s.range())
11683            .collect();
11684        self.restore_hunks_in_ranges(selections, window, cx);
11685    }
11686
11687    /// Restores the diff hunks in the editor's selections and moves the cursor
11688    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11689    /// not all diff hunks are expanded.
11690    pub fn restore_and_next(
11691        &mut self,
11692        _: &::git::RestoreAndNext,
11693        window: &mut Window,
11694        cx: &mut Context<Self>,
11695    ) {
11696        let selections = self
11697            .selections
11698            .all(&self.display_snapshot(cx))
11699            .into_iter()
11700            .map(|selection| selection.range())
11701            .collect();
11702
11703        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11704        self.restore_hunks_in_ranges(selections, window, cx);
11705
11706        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11707        let wrap_around = !all_diff_hunks_expanded;
11708        let snapshot = self.snapshot(window, cx);
11709        let position = self
11710            .selections
11711            .newest::<Point>(&snapshot.display_snapshot)
11712            .head();
11713
11714        self.go_to_hunk_before_or_after_position(
11715            &snapshot,
11716            position,
11717            Direction::Next,
11718            wrap_around,
11719            window,
11720            cx,
11721        );
11722    }
11723
11724    pub fn restore_hunks_in_ranges(
11725        &mut self,
11726        ranges: Vec<Range<Point>>,
11727        window: &mut Window,
11728        cx: &mut Context<Editor>,
11729    ) {
11730        if self.delegate_stage_and_restore {
11731            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11732            if !hunks.is_empty() {
11733                cx.emit(EditorEvent::RestoreRequested { hunks });
11734            }
11735            return;
11736        }
11737        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11738        self.transact(window, cx, |editor, window, cx| {
11739            editor.restore_diff_hunks(hunks, cx);
11740            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
11741                selections.refresh()
11742            });
11743        });
11744    }
11745
11746    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11747        let mut revert_changes = HashMap::default();
11748        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11749        for (buffer_id, hunks) in &chunk_by {
11750            let hunks = hunks.collect::<Vec<_>>();
11751            for hunk in &hunks {
11752                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11753            }
11754            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11755        }
11756        if !revert_changes.is_empty() {
11757            self.buffer().update(cx, |multi_buffer, cx| {
11758                for (buffer_id, changes) in revert_changes {
11759                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11760                        buffer.update(cx, |buffer, cx| {
11761                            buffer.edit(
11762                                changes
11763                                    .into_iter()
11764                                    .map(|(range, text)| (range, text.to_string())),
11765                                None,
11766                                cx,
11767                            );
11768                        });
11769                    }
11770                }
11771            });
11772        }
11773    }
11774
11775    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11776        if let Some(status) = self
11777            .addons
11778            .iter()
11779            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11780        {
11781            return Some(status);
11782        }
11783        self.project
11784            .as_ref()?
11785            .read(cx)
11786            .status_for_buffer_id(buffer_id, cx)
11787    }
11788
11789    pub fn open_active_item_in_terminal(
11790        &mut self,
11791        _: &OpenInTerminal,
11792        window: &mut Window,
11793        cx: &mut Context<Self>,
11794    ) {
11795        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11796            let project_path = buffer.read(cx).project_path(cx)?;
11797            let project = self.project()?.read(cx);
11798            let entry = project.entry_for_path(&project_path, cx)?;
11799            let parent = match &entry.canonical_path {
11800                Some(canonical_path) => canonical_path.to_path_buf(),
11801                None => project.absolute_path(&project_path, cx)?,
11802            }
11803            .parent()?
11804            .to_path_buf();
11805            Some(parent)
11806        }) {
11807            window.dispatch_action(
11808                OpenTerminal {
11809                    working_directory,
11810                    local: false,
11811                }
11812                .boxed_clone(),
11813                cx,
11814            );
11815        }
11816    }
11817
11818    fn set_breakpoint_context_menu(
11819        &mut self,
11820        display_row: DisplayRow,
11821        position: Option<Anchor>,
11822        clicked_point: gpui::Point<Pixels>,
11823        window: &mut Window,
11824        cx: &mut Context<Self>,
11825    ) {
11826        let source = self
11827            .buffer
11828            .read(cx)
11829            .snapshot(cx)
11830            .anchor_before(Point::new(display_row.0, 0u32));
11831
11832        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11833
11834        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11835            self,
11836            source,
11837            clicked_point,
11838            context_menu,
11839            window,
11840            cx,
11841        );
11842    }
11843
11844    fn add_edit_breakpoint_block(
11845        &mut self,
11846        anchor: Anchor,
11847        breakpoint: &Breakpoint,
11848        edit_action: BreakpointPromptEditAction,
11849        window: &mut Window,
11850        cx: &mut Context<Self>,
11851    ) {
11852        let weak_editor = cx.weak_entity();
11853        let bp_prompt = cx.new(|cx| {
11854            BreakpointPromptEditor::new(
11855                weak_editor,
11856                anchor,
11857                breakpoint.clone(),
11858                edit_action,
11859                window,
11860                cx,
11861            )
11862        });
11863
11864        let height = bp_prompt.update(cx, |this, cx| {
11865            this.prompt
11866                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11867        });
11868        let cloned_prompt = bp_prompt.clone();
11869        let blocks = vec![BlockProperties {
11870            style: BlockStyle::Sticky,
11871            placement: BlockPlacement::Above(anchor),
11872            height: Some(height),
11873            render: Arc::new(move |cx| {
11874                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11875                cloned_prompt.clone().into_any_element()
11876            }),
11877            priority: 0,
11878        }];
11879
11880        let focus_handle = bp_prompt.focus_handle(cx);
11881        window.focus(&focus_handle, cx);
11882
11883        let block_ids = self.insert_blocks(blocks, None, cx);
11884        bp_prompt.update(cx, |prompt, _| {
11885            prompt.add_block_ids(block_ids);
11886        });
11887    }
11888
11889    pub(crate) fn breakpoint_at_row(
11890        &self,
11891        row: u32,
11892        window: &mut Window,
11893        cx: &mut Context<Self>,
11894    ) -> Option<(Anchor, Breakpoint)> {
11895        let snapshot = self.snapshot(window, cx);
11896        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11897
11898        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11899    }
11900
11901    pub(crate) fn breakpoint_at_anchor(
11902        &self,
11903        breakpoint_position: Anchor,
11904        snapshot: &EditorSnapshot,
11905        cx: &mut Context<Self>,
11906    ) -> Option<(Anchor, Breakpoint)> {
11907        let buffer = self
11908            .buffer
11909            .read(cx)
11910            .buffer_for_anchor(breakpoint_position, cx)?;
11911
11912        let enclosing_excerpt = breakpoint_position.excerpt_id;
11913        let buffer_snapshot = buffer.read(cx).snapshot();
11914
11915        let row = buffer_snapshot
11916            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11917            .row;
11918
11919        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11920        let anchor_end = snapshot
11921            .buffer_snapshot()
11922            .anchor_after(Point::new(row, line_len));
11923
11924        self.breakpoint_store
11925            .as_ref()?
11926            .read_with(cx, |breakpoint_store, cx| {
11927                breakpoint_store
11928                    .breakpoints(
11929                        &buffer,
11930                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11931                        &buffer_snapshot,
11932                        cx,
11933                    )
11934                    .next()
11935                    .and_then(|(bp, _)| {
11936                        let breakpoint_row = buffer_snapshot
11937                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11938                            .row;
11939
11940                        if breakpoint_row == row {
11941                            snapshot
11942                                .buffer_snapshot()
11943                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11944                                .map(|position| (position, bp.bp.clone()))
11945                        } else {
11946                            None
11947                        }
11948                    })
11949            })
11950    }
11951
11952    pub fn edit_log_breakpoint(
11953        &mut self,
11954        _: &EditLogBreakpoint,
11955        window: &mut Window,
11956        cx: &mut Context<Self>,
11957    ) {
11958        if self.breakpoint_store.is_none() {
11959            return;
11960        }
11961
11962        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11963            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11964                message: None,
11965                state: BreakpointState::Enabled,
11966                condition: None,
11967                hit_condition: None,
11968            });
11969
11970            self.add_edit_breakpoint_block(
11971                anchor,
11972                &breakpoint,
11973                BreakpointPromptEditAction::Log,
11974                window,
11975                cx,
11976            );
11977        }
11978    }
11979
11980    fn breakpoints_at_cursors(
11981        &self,
11982        window: &mut Window,
11983        cx: &mut Context<Self>,
11984    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11985        let snapshot = self.snapshot(window, cx);
11986        let cursors = self
11987            .selections
11988            .disjoint_anchors_arc()
11989            .iter()
11990            .map(|selection| {
11991                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11992
11993                let breakpoint_position = self
11994                    .breakpoint_at_row(cursor_position.row, window, cx)
11995                    .map(|bp| bp.0)
11996                    .unwrap_or_else(|| {
11997                        snapshot
11998                            .display_snapshot
11999                            .buffer_snapshot()
12000                            .anchor_after(Point::new(cursor_position.row, 0))
12001                    });
12002
12003                let breakpoint = self
12004                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12005                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12006
12007                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12008            })
12009            // 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.
12010            .collect::<HashMap<Anchor, _>>();
12011
12012        cursors.into_iter().collect()
12013    }
12014
12015    pub fn enable_breakpoint(
12016        &mut self,
12017        _: &crate::actions::EnableBreakpoint,
12018        window: &mut Window,
12019        cx: &mut Context<Self>,
12020    ) {
12021        if self.breakpoint_store.is_none() {
12022            return;
12023        }
12024
12025        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12026            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12027                continue;
12028            };
12029            self.edit_breakpoint_at_anchor(
12030                anchor,
12031                breakpoint,
12032                BreakpointEditAction::InvertState,
12033                cx,
12034            );
12035        }
12036    }
12037
12038    pub fn align_selections(
12039        &mut self,
12040        _: &crate::actions::AlignSelections,
12041        window: &mut Window,
12042        cx: &mut Context<Self>,
12043    ) {
12044        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12045
12046        let display_snapshot = self.display_snapshot(cx);
12047
12048        struct CursorData {
12049            anchor: Anchor,
12050            point: Point,
12051        }
12052        let cursor_data: Vec<CursorData> = self
12053            .selections
12054            .disjoint_anchors()
12055            .iter()
12056            .map(|selection| {
12057                let anchor = if selection.reversed {
12058                    selection.head()
12059                } else {
12060                    selection.tail()
12061                };
12062                CursorData {
12063                    anchor: anchor,
12064                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12065                }
12066            })
12067            .collect();
12068
12069        let rows_anchors_count: Vec<usize> = cursor_data
12070            .iter()
12071            .map(|cursor| cursor.point.row)
12072            .chunk_by(|&row| row)
12073            .into_iter()
12074            .map(|(_, group)| group.count())
12075            .collect();
12076        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12077        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12078        let mut edits = Vec::new();
12079
12080        for column_idx in 0..max_columns {
12081            let mut cursor_index = 0;
12082
12083            // Calculate target_column => position that the selections will go
12084            let mut target_column = 0;
12085            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12086                // Skip rows that don't have this column
12087                if column_idx >= *cursor_count {
12088                    cursor_index += cursor_count;
12089                    continue;
12090                }
12091
12092                let point = &cursor_data[cursor_index + column_idx].point;
12093                let adjusted_column = point.column + rows_column_offset[row_idx];
12094                if adjusted_column > target_column {
12095                    target_column = adjusted_column;
12096                }
12097                cursor_index += cursor_count;
12098            }
12099
12100            // Collect edits for this column
12101            cursor_index = 0;
12102            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12103                // Skip rows that don't have this column
12104                if column_idx >= *cursor_count {
12105                    cursor_index += *cursor_count;
12106                    continue;
12107                }
12108
12109                let point = &cursor_data[cursor_index + column_idx].point;
12110                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12111                if spaces_needed > 0 {
12112                    let anchor = cursor_data[cursor_index + column_idx]
12113                        .anchor
12114                        .bias_left(&display_snapshot);
12115                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12116                }
12117                rows_column_offset[row_idx] += spaces_needed;
12118
12119                cursor_index += *cursor_count;
12120            }
12121        }
12122
12123        if !edits.is_empty() {
12124            self.transact(window, cx, |editor, _window, cx| {
12125                editor.edit(edits, cx);
12126            });
12127        }
12128    }
12129
12130    pub fn disable_breakpoint(
12131        &mut self,
12132        _: &crate::actions::DisableBreakpoint,
12133        window: &mut Window,
12134        cx: &mut Context<Self>,
12135    ) {
12136        if self.breakpoint_store.is_none() {
12137            return;
12138        }
12139
12140        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12141            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12142                continue;
12143            };
12144            self.edit_breakpoint_at_anchor(
12145                anchor,
12146                breakpoint,
12147                BreakpointEditAction::InvertState,
12148                cx,
12149            );
12150        }
12151    }
12152
12153    pub fn toggle_breakpoint(
12154        &mut self,
12155        _: &crate::actions::ToggleBreakpoint,
12156        window: &mut Window,
12157        cx: &mut Context<Self>,
12158    ) {
12159        if self.breakpoint_store.is_none() {
12160            return;
12161        }
12162
12163        let snapshot = self.snapshot(window, cx);
12164        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12165            if self.gutter_breakpoint_indicator.0.is_some() {
12166                let display_row = anchor
12167                    .to_point(snapshot.buffer_snapshot())
12168                    .to_display_point(&snapshot.display_snapshot)
12169                    .row();
12170                self.update_breakpoint_collision_on_toggle(
12171                    display_row,
12172                    &BreakpointEditAction::Toggle,
12173                );
12174            }
12175
12176            if let Some(breakpoint) = breakpoint {
12177                self.edit_breakpoint_at_anchor(
12178                    anchor,
12179                    breakpoint,
12180                    BreakpointEditAction::Toggle,
12181                    cx,
12182                );
12183            } else {
12184                self.edit_breakpoint_at_anchor(
12185                    anchor,
12186                    Breakpoint::new_standard(),
12187                    BreakpointEditAction::Toggle,
12188                    cx,
12189                );
12190            }
12191        }
12192    }
12193
12194    fn update_breakpoint_collision_on_toggle(
12195        &mut self,
12196        display_row: DisplayRow,
12197        edit_action: &BreakpointEditAction,
12198    ) {
12199        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12200            if breakpoint_indicator.display_row == display_row
12201                && matches!(edit_action, BreakpointEditAction::Toggle)
12202            {
12203                breakpoint_indicator.collides_with_existing_breakpoint =
12204                    !breakpoint_indicator.collides_with_existing_breakpoint;
12205            }
12206        }
12207    }
12208
12209    pub fn edit_breakpoint_at_anchor(
12210        &mut self,
12211        breakpoint_position: Anchor,
12212        breakpoint: Breakpoint,
12213        edit_action: BreakpointEditAction,
12214        cx: &mut Context<Self>,
12215    ) {
12216        let Some(breakpoint_store) = &self.breakpoint_store else {
12217            return;
12218        };
12219
12220        let Some(buffer) = self
12221            .buffer
12222            .read(cx)
12223            .buffer_for_anchor(breakpoint_position, cx)
12224        else {
12225            return;
12226        };
12227
12228        breakpoint_store.update(cx, |breakpoint_store, cx| {
12229            breakpoint_store.toggle_breakpoint(
12230                buffer,
12231                BreakpointWithPosition {
12232                    position: breakpoint_position.text_anchor,
12233                    bp: breakpoint,
12234                },
12235                edit_action,
12236                cx,
12237            );
12238        });
12239
12240        cx.notify();
12241    }
12242
12243    #[cfg(any(test, feature = "test-support"))]
12244    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12245        self.breakpoint_store.clone()
12246    }
12247
12248    pub fn prepare_restore_change(
12249        &self,
12250        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12251        hunk: &MultiBufferDiffHunk,
12252        cx: &mut App,
12253    ) -> Option<()> {
12254        if hunk.is_created_file() {
12255            return None;
12256        }
12257        let buffer = self.buffer.read(cx);
12258        let diff = buffer.diff_for(hunk.buffer_id)?;
12259        let buffer = buffer.buffer(hunk.buffer_id)?;
12260        let buffer = buffer.read(cx);
12261        let original_text = diff
12262            .read(cx)
12263            .base_text(cx)
12264            .as_rope()
12265            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12266        let buffer_snapshot = buffer.snapshot();
12267        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12268        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12269            probe
12270                .0
12271                .start
12272                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12273                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12274        }) {
12275            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12276            Some(())
12277        } else {
12278            None
12279        }
12280    }
12281
12282    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12283        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12284    }
12285
12286    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12287        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12288    }
12289
12290    pub fn rotate_selections_forward(
12291        &mut self,
12292        _: &RotateSelectionsForward,
12293        window: &mut Window,
12294        cx: &mut Context<Self>,
12295    ) {
12296        self.rotate_selections(window, cx, false)
12297    }
12298
12299    pub fn rotate_selections_backward(
12300        &mut self,
12301        _: &RotateSelectionsBackward,
12302        window: &mut Window,
12303        cx: &mut Context<Self>,
12304    ) {
12305        self.rotate_selections(window, cx, true)
12306    }
12307
12308    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12309        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12310        let display_snapshot = self.display_snapshot(cx);
12311        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12312
12313        if selections.len() < 2 {
12314            return;
12315        }
12316
12317        let (edits, new_selections) = {
12318            let buffer = self.buffer.read(cx).read(cx);
12319            let has_selections = selections.iter().any(|s| !s.is_empty());
12320            if has_selections {
12321                let mut selected_texts: Vec<String> = selections
12322                    .iter()
12323                    .map(|selection| {
12324                        buffer
12325                            .text_for_range(selection.start..selection.end)
12326                            .collect()
12327                    })
12328                    .collect();
12329
12330                if reverse {
12331                    selected_texts.rotate_left(1);
12332                } else {
12333                    selected_texts.rotate_right(1);
12334                }
12335
12336                let mut offset_delta: i64 = 0;
12337                let mut new_selections = Vec::new();
12338                let edits: Vec<_> = selections
12339                    .iter()
12340                    .zip(selected_texts.iter())
12341                    .map(|(selection, new_text)| {
12342                        let old_len = (selection.end.0 - selection.start.0) as i64;
12343                        let new_len = new_text.len() as i64;
12344                        let adjusted_start =
12345                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12346                        let adjusted_end =
12347                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12348
12349                        new_selections.push(Selection {
12350                            id: selection.id,
12351                            start: adjusted_start,
12352                            end: adjusted_end,
12353                            reversed: selection.reversed,
12354                            goal: selection.goal,
12355                        });
12356
12357                        offset_delta += new_len - old_len;
12358                        (selection.start..selection.end, new_text.clone())
12359                    })
12360                    .collect();
12361                (edits, new_selections)
12362            } else {
12363                let mut all_rows: Vec<u32> = selections
12364                    .iter()
12365                    .map(|selection| buffer.offset_to_point(selection.start).row)
12366                    .collect();
12367                all_rows.sort_unstable();
12368                all_rows.dedup();
12369
12370                if all_rows.len() < 2 {
12371                    return;
12372                }
12373
12374                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12375                    .iter()
12376                    .map(|&row| {
12377                        let start = Point::new(row, 0);
12378                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12379                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12380                    })
12381                    .collect();
12382
12383                let mut line_texts: Vec<String> = line_ranges
12384                    .iter()
12385                    .map(|range| buffer.text_for_range(range.clone()).collect())
12386                    .collect();
12387
12388                if reverse {
12389                    line_texts.rotate_left(1);
12390                } else {
12391                    line_texts.rotate_right(1);
12392                }
12393
12394                let edits = line_ranges
12395                    .iter()
12396                    .zip(line_texts.iter())
12397                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12398                    .collect();
12399
12400                let num_rows = all_rows.len();
12401                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12402                    .iter()
12403                    .enumerate()
12404                    .map(|(i, &row)| (row, i))
12405                    .collect();
12406
12407                // Compute new line start offsets after rotation (handles CRLF)
12408                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12409                let first_line_start = line_ranges[0].start.0;
12410                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12411                for text in line_texts.iter().take(num_rows - 1) {
12412                    let prev_start = *new_line_starts.last().unwrap();
12413                    new_line_starts.push(prev_start + text.len() + newline_len);
12414                }
12415
12416                let new_selections = selections
12417                    .iter()
12418                    .map(|selection| {
12419                        let point = buffer.offset_to_point(selection.start);
12420                        let old_index = row_to_index[&point.row];
12421                        let new_index = if reverse {
12422                            (old_index + num_rows - 1) % num_rows
12423                        } else {
12424                            (old_index + 1) % num_rows
12425                        };
12426                        let new_offset =
12427                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12428                        Selection {
12429                            id: selection.id,
12430                            start: new_offset,
12431                            end: new_offset,
12432                            reversed: selection.reversed,
12433                            goal: selection.goal,
12434                        }
12435                    })
12436                    .collect();
12437
12438                (edits, new_selections)
12439            }
12440        };
12441
12442        self.transact(window, cx, |this, window, cx| {
12443            this.buffer.update(cx, |buffer, cx| {
12444                buffer.edit(edits, None, cx);
12445            });
12446            this.change_selections(Default::default(), window, cx, |s| {
12447                s.select(new_selections);
12448            });
12449        });
12450    }
12451
12452    fn manipulate_lines<M>(
12453        &mut self,
12454        window: &mut Window,
12455        cx: &mut Context<Self>,
12456        mut manipulate: M,
12457    ) where
12458        M: FnMut(&str) -> LineManipulationResult,
12459    {
12460        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12461
12462        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12463        let buffer = self.buffer.read(cx).snapshot(cx);
12464
12465        let mut edits = Vec::new();
12466
12467        let selections = self.selections.all::<Point>(&display_map);
12468        let mut selections = selections.iter().peekable();
12469        let mut contiguous_row_selections = Vec::new();
12470        let mut new_selections = Vec::new();
12471        let mut added_lines = 0;
12472        let mut removed_lines = 0;
12473
12474        while let Some(selection) = selections.next() {
12475            let (start_row, end_row) = consume_contiguous_rows(
12476                &mut contiguous_row_selections,
12477                selection,
12478                &display_map,
12479                &mut selections,
12480            );
12481
12482            let start_point = Point::new(start_row.0, 0);
12483            let end_point = Point::new(
12484                end_row.previous_row().0,
12485                buffer.line_len(end_row.previous_row()),
12486            );
12487            let text = buffer
12488                .text_for_range(start_point..end_point)
12489                .collect::<String>();
12490
12491            let LineManipulationResult {
12492                new_text,
12493                line_count_before,
12494                line_count_after,
12495            } = manipulate(&text);
12496
12497            edits.push((start_point..end_point, new_text));
12498
12499            // Selections must change based on added and removed line count
12500            let start_row =
12501                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12502            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12503            new_selections.push(Selection {
12504                id: selection.id,
12505                start: start_row,
12506                end: end_row,
12507                goal: SelectionGoal::None,
12508                reversed: selection.reversed,
12509            });
12510
12511            if line_count_after > line_count_before {
12512                added_lines += line_count_after - line_count_before;
12513            } else if line_count_before > line_count_after {
12514                removed_lines += line_count_before - line_count_after;
12515            }
12516        }
12517
12518        self.transact(window, cx, |this, window, cx| {
12519            let buffer = this.buffer.update(cx, |buffer, cx| {
12520                buffer.edit(edits, None, cx);
12521                buffer.snapshot(cx)
12522            });
12523
12524            // Recalculate offsets on newly edited buffer
12525            let new_selections = new_selections
12526                .iter()
12527                .map(|s| {
12528                    let start_point = Point::new(s.start.0, 0);
12529                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12530                    Selection {
12531                        id: s.id,
12532                        start: buffer.point_to_offset(start_point),
12533                        end: buffer.point_to_offset(end_point),
12534                        goal: s.goal,
12535                        reversed: s.reversed,
12536                    }
12537                })
12538                .collect();
12539
12540            this.change_selections(Default::default(), window, cx, |s| {
12541                s.select(new_selections);
12542            });
12543
12544            this.request_autoscroll(Autoscroll::fit(), cx);
12545        });
12546    }
12547
12548    fn manipulate_immutable_lines<Fn>(
12549        &mut self,
12550        window: &mut Window,
12551        cx: &mut Context<Self>,
12552        mut callback: Fn,
12553    ) where
12554        Fn: FnMut(&mut Vec<&str>),
12555    {
12556        self.manipulate_lines(window, cx, |text| {
12557            let mut lines: Vec<&str> = text.split('\n').collect();
12558            let line_count_before = lines.len();
12559
12560            callback(&mut lines);
12561
12562            LineManipulationResult {
12563                new_text: lines.join("\n"),
12564                line_count_before,
12565                line_count_after: lines.len(),
12566            }
12567        });
12568    }
12569
12570    fn manipulate_mutable_lines<Fn>(
12571        &mut self,
12572        window: &mut Window,
12573        cx: &mut Context<Self>,
12574        mut callback: Fn,
12575    ) where
12576        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12577    {
12578        self.manipulate_lines(window, cx, |text| {
12579            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12580            let line_count_before = lines.len();
12581
12582            callback(&mut lines);
12583
12584            LineManipulationResult {
12585                new_text: lines.join("\n"),
12586                line_count_before,
12587                line_count_after: lines.len(),
12588            }
12589        });
12590    }
12591
12592    pub fn convert_indentation_to_spaces(
12593        &mut self,
12594        _: &ConvertIndentationToSpaces,
12595        window: &mut Window,
12596        cx: &mut Context<Self>,
12597    ) {
12598        let settings = self.buffer.read(cx).language_settings(cx);
12599        let tab_size = settings.tab_size.get() as usize;
12600
12601        self.manipulate_mutable_lines(window, cx, |lines| {
12602            // Allocates a reasonably sized scratch buffer once for the whole loop
12603            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12604            // Avoids recomputing spaces that could be inserted many times
12605            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12606                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12607                .collect();
12608
12609            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12610                let mut chars = line.as_ref().chars();
12611                let mut col = 0;
12612                let mut changed = false;
12613
12614                for ch in chars.by_ref() {
12615                    match ch {
12616                        ' ' => {
12617                            reindented_line.push(' ');
12618                            col += 1;
12619                        }
12620                        '\t' => {
12621                            // \t are converted to spaces depending on the current column
12622                            let spaces_len = tab_size - (col % tab_size);
12623                            reindented_line.extend(&space_cache[spaces_len - 1]);
12624                            col += spaces_len;
12625                            changed = true;
12626                        }
12627                        _ => {
12628                            // If we dont append before break, the character is consumed
12629                            reindented_line.push(ch);
12630                            break;
12631                        }
12632                    }
12633                }
12634
12635                if !changed {
12636                    reindented_line.clear();
12637                    continue;
12638                }
12639                // Append the rest of the line and replace old reference with new one
12640                reindented_line.extend(chars);
12641                *line = Cow::Owned(reindented_line.clone());
12642                reindented_line.clear();
12643            }
12644        });
12645    }
12646
12647    pub fn convert_indentation_to_tabs(
12648        &mut self,
12649        _: &ConvertIndentationToTabs,
12650        window: &mut Window,
12651        cx: &mut Context<Self>,
12652    ) {
12653        let settings = self.buffer.read(cx).language_settings(cx);
12654        let tab_size = settings.tab_size.get() as usize;
12655
12656        self.manipulate_mutable_lines(window, cx, |lines| {
12657            // Allocates a reasonably sized buffer once for the whole loop
12658            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12659            // Avoids recomputing spaces that could be inserted many times
12660            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12661                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12662                .collect();
12663
12664            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12665                let mut chars = line.chars();
12666                let mut spaces_count = 0;
12667                let mut first_non_indent_char = None;
12668                let mut changed = false;
12669
12670                for ch in chars.by_ref() {
12671                    match ch {
12672                        ' ' => {
12673                            // Keep track of spaces. Append \t when we reach tab_size
12674                            spaces_count += 1;
12675                            changed = true;
12676                            if spaces_count == tab_size {
12677                                reindented_line.push('\t');
12678                                spaces_count = 0;
12679                            }
12680                        }
12681                        '\t' => {
12682                            reindented_line.push('\t');
12683                            spaces_count = 0;
12684                        }
12685                        _ => {
12686                            // Dont append it yet, we might have remaining spaces
12687                            first_non_indent_char = Some(ch);
12688                            break;
12689                        }
12690                    }
12691                }
12692
12693                if !changed {
12694                    reindented_line.clear();
12695                    continue;
12696                }
12697                // Remaining spaces that didn't make a full tab stop
12698                if spaces_count > 0 {
12699                    reindented_line.extend(&space_cache[spaces_count - 1]);
12700                }
12701                // If we consume an extra character that was not indentation, add it back
12702                if let Some(extra_char) = first_non_indent_char {
12703                    reindented_line.push(extra_char);
12704                }
12705                // Append the rest of the line and replace old reference with new one
12706                reindented_line.extend(chars);
12707                *line = Cow::Owned(reindented_line.clone());
12708                reindented_line.clear();
12709            }
12710        });
12711    }
12712
12713    pub fn convert_to_upper_case(
12714        &mut self,
12715        _: &ConvertToUpperCase,
12716        window: &mut Window,
12717        cx: &mut Context<Self>,
12718    ) {
12719        self.manipulate_text(window, cx, |text| text.to_uppercase())
12720    }
12721
12722    pub fn convert_to_lower_case(
12723        &mut self,
12724        _: &ConvertToLowerCase,
12725        window: &mut Window,
12726        cx: &mut Context<Self>,
12727    ) {
12728        self.manipulate_text(window, cx, |text| text.to_lowercase())
12729    }
12730
12731    pub fn convert_to_title_case(
12732        &mut self,
12733        _: &ConvertToTitleCase,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        self.manipulate_text(window, cx, |text| {
12738            Self::convert_text_case(text, Case::Title)
12739        })
12740    }
12741
12742    pub fn convert_to_snake_case(
12743        &mut self,
12744        _: &ConvertToSnakeCase,
12745        window: &mut Window,
12746        cx: &mut Context<Self>,
12747    ) {
12748        self.manipulate_text(window, cx, |text| {
12749            Self::convert_text_case(text, Case::Snake)
12750        })
12751    }
12752
12753    pub fn convert_to_kebab_case(
12754        &mut self,
12755        _: &ConvertToKebabCase,
12756        window: &mut Window,
12757        cx: &mut Context<Self>,
12758    ) {
12759        self.manipulate_text(window, cx, |text| {
12760            Self::convert_text_case(text, Case::Kebab)
12761        })
12762    }
12763
12764    pub fn convert_to_upper_camel_case(
12765        &mut self,
12766        _: &ConvertToUpperCamelCase,
12767        window: &mut Window,
12768        cx: &mut Context<Self>,
12769    ) {
12770        self.manipulate_text(window, cx, |text| {
12771            Self::convert_text_case(text, Case::UpperCamel)
12772        })
12773    }
12774
12775    pub fn convert_to_lower_camel_case(
12776        &mut self,
12777        _: &ConvertToLowerCamelCase,
12778        window: &mut Window,
12779        cx: &mut Context<Self>,
12780    ) {
12781        self.manipulate_text(window, cx, |text| {
12782            Self::convert_text_case(text, Case::Camel)
12783        })
12784    }
12785
12786    pub fn convert_to_opposite_case(
12787        &mut self,
12788        _: &ConvertToOppositeCase,
12789        window: &mut Window,
12790        cx: &mut Context<Self>,
12791    ) {
12792        self.manipulate_text(window, cx, |text| {
12793            text.chars()
12794                .fold(String::with_capacity(text.len()), |mut t, c| {
12795                    if c.is_uppercase() {
12796                        t.extend(c.to_lowercase());
12797                    } else {
12798                        t.extend(c.to_uppercase());
12799                    }
12800                    t
12801                })
12802        })
12803    }
12804
12805    pub fn convert_to_sentence_case(
12806        &mut self,
12807        _: &ConvertToSentenceCase,
12808        window: &mut Window,
12809        cx: &mut Context<Self>,
12810    ) {
12811        self.manipulate_text(window, cx, |text| {
12812            Self::convert_text_case(text, Case::Sentence)
12813        })
12814    }
12815
12816    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12817        self.manipulate_text(window, cx, |text| {
12818            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12819            if has_upper_case_characters {
12820                text.to_lowercase()
12821            } else {
12822                text.to_uppercase()
12823            }
12824        })
12825    }
12826
12827    pub fn convert_to_rot13(
12828        &mut self,
12829        _: &ConvertToRot13,
12830        window: &mut Window,
12831        cx: &mut Context<Self>,
12832    ) {
12833        self.manipulate_text(window, cx, |text| {
12834            text.chars()
12835                .map(|c| match c {
12836                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12837                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12838                    _ => c,
12839                })
12840                .collect()
12841        })
12842    }
12843
12844    fn convert_text_case(text: &str, case: Case) -> String {
12845        text.lines()
12846            .map(|line| {
12847                let trimmed_start = line.trim_start();
12848                let leading = &line[..line.len() - trimmed_start.len()];
12849                let trimmed = trimmed_start.trim_end();
12850                let trailing = &trimmed_start[trimmed.len()..];
12851                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12852            })
12853            .join("\n")
12854    }
12855
12856    pub fn convert_to_rot47(
12857        &mut self,
12858        _: &ConvertToRot47,
12859        window: &mut Window,
12860        cx: &mut Context<Self>,
12861    ) {
12862        self.manipulate_text(window, cx, |text| {
12863            text.chars()
12864                .map(|c| {
12865                    let code_point = c as u32;
12866                    if code_point >= 33 && code_point <= 126 {
12867                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12868                    }
12869                    c
12870                })
12871                .collect()
12872        })
12873    }
12874
12875    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12876    where
12877        Fn: FnMut(&str) -> String,
12878    {
12879        let buffer = self.buffer.read(cx).snapshot(cx);
12880
12881        let mut new_selections = Vec::new();
12882        let mut edits = Vec::new();
12883        let mut selection_adjustment = 0isize;
12884
12885        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12886            let selection_is_empty = selection.is_empty();
12887
12888            let (start, end) = if selection_is_empty {
12889                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12890                (word_range.start, word_range.end)
12891            } else {
12892                (
12893                    buffer.point_to_offset(selection.start),
12894                    buffer.point_to_offset(selection.end),
12895                )
12896            };
12897
12898            let text = buffer.text_for_range(start..end).collect::<String>();
12899            let old_length = text.len() as isize;
12900            let text = callback(&text);
12901
12902            new_selections.push(Selection {
12903                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12904                end: MultiBufferOffset(
12905                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12906                ),
12907                goal: SelectionGoal::None,
12908                id: selection.id,
12909                reversed: selection.reversed,
12910            });
12911
12912            selection_adjustment += old_length - text.len() as isize;
12913
12914            edits.push((start..end, text));
12915        }
12916
12917        self.transact(window, cx, |this, window, cx| {
12918            this.buffer.update(cx, |buffer, cx| {
12919                buffer.edit(edits, None, cx);
12920            });
12921
12922            this.change_selections(Default::default(), window, cx, |s| {
12923                s.select(new_selections);
12924            });
12925
12926            this.request_autoscroll(Autoscroll::fit(), cx);
12927        });
12928    }
12929
12930    pub fn move_selection_on_drop(
12931        &mut self,
12932        selection: &Selection<Anchor>,
12933        target: DisplayPoint,
12934        is_cut: bool,
12935        window: &mut Window,
12936        cx: &mut Context<Self>,
12937    ) {
12938        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12939        let buffer = display_map.buffer_snapshot();
12940        let mut edits = Vec::new();
12941        let insert_point = display_map
12942            .clip_point(target, Bias::Left)
12943            .to_point(&display_map);
12944        let text = buffer
12945            .text_for_range(selection.start..selection.end)
12946            .collect::<String>();
12947        if is_cut {
12948            edits.push(((selection.start..selection.end), String::new()));
12949        }
12950        let insert_anchor = buffer.anchor_before(insert_point);
12951        edits.push(((insert_anchor..insert_anchor), text));
12952        let last_edit_start = insert_anchor.bias_left(buffer);
12953        let last_edit_end = insert_anchor.bias_right(buffer);
12954        self.transact(window, cx, |this, window, cx| {
12955            this.buffer.update(cx, |buffer, cx| {
12956                buffer.edit(edits, None, cx);
12957            });
12958            this.change_selections(Default::default(), window, cx, |s| {
12959                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12960            });
12961        });
12962    }
12963
12964    pub fn clear_selection_drag_state(&mut self) {
12965        self.selection_drag_state = SelectionDragState::None;
12966    }
12967
12968    pub fn duplicate(
12969        &mut self,
12970        upwards: bool,
12971        whole_lines: bool,
12972        window: &mut Window,
12973        cx: &mut Context<Self>,
12974    ) {
12975        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12976
12977        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12978        let buffer = display_map.buffer_snapshot();
12979        let selections = self.selections.all::<Point>(&display_map);
12980
12981        let mut edits = Vec::new();
12982        let mut selections_iter = selections.iter().peekable();
12983        while let Some(selection) = selections_iter.next() {
12984            let mut rows = selection.spanned_rows(false, &display_map);
12985            // duplicate line-wise
12986            if whole_lines || selection.start == selection.end {
12987                // Avoid duplicating the same lines twice.
12988                while let Some(next_selection) = selections_iter.peek() {
12989                    let next_rows = next_selection.spanned_rows(false, &display_map);
12990                    if next_rows.start < rows.end {
12991                        rows.end = next_rows.end;
12992                        selections_iter.next().unwrap();
12993                    } else {
12994                        break;
12995                    }
12996                }
12997
12998                // Copy the text from the selected row region and splice it either at the start
12999                // or end of the region.
13000                let start = Point::new(rows.start.0, 0);
13001                let end = Point::new(
13002                    rows.end.previous_row().0,
13003                    buffer.line_len(rows.end.previous_row()),
13004                );
13005
13006                let mut text = buffer.text_for_range(start..end).collect::<String>();
13007
13008                let insert_location = if upwards {
13009                    // When duplicating upward, we need to insert before the current line.
13010                    // If we're on the last line and it doesn't end with a newline,
13011                    // we need to add a newline before the duplicated content.
13012                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13013                        && buffer.max_point().column > 0
13014                        && !text.ends_with('\n');
13015
13016                    if needs_leading_newline {
13017                        text.insert(0, '\n');
13018                        end
13019                    } else {
13020                        text.push('\n');
13021                        Point::new(rows.start.0, 0)
13022                    }
13023                } else {
13024                    text.push('\n');
13025                    start
13026                };
13027                edits.push((insert_location..insert_location, text));
13028            } else {
13029                // duplicate character-wise
13030                let start = selection.start;
13031                let end = selection.end;
13032                let text = buffer.text_for_range(start..end).collect::<String>();
13033                edits.push((selection.end..selection.end, text));
13034            }
13035        }
13036
13037        self.transact(window, cx, |this, window, cx| {
13038            this.buffer.update(cx, |buffer, cx| {
13039                buffer.edit(edits, None, cx);
13040            });
13041
13042            // When duplicating upward with whole lines, move the cursor to the duplicated line
13043            if upwards && whole_lines {
13044                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13045
13046                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13047                    let mut new_ranges = Vec::new();
13048                    let selections = s.all::<Point>(&display_map);
13049                    let mut selections_iter = selections.iter().peekable();
13050
13051                    while let Some(first_selection) = selections_iter.next() {
13052                        // Group contiguous selections together to find the total row span
13053                        let mut group_selections = vec![first_selection];
13054                        let mut rows = first_selection.spanned_rows(false, &display_map);
13055
13056                        while let Some(next_selection) = selections_iter.peek() {
13057                            let next_rows = next_selection.spanned_rows(false, &display_map);
13058                            if next_rows.start < rows.end {
13059                                rows.end = next_rows.end;
13060                                group_selections.push(selections_iter.next().unwrap());
13061                            } else {
13062                                break;
13063                            }
13064                        }
13065
13066                        let row_count = rows.end.0 - rows.start.0;
13067
13068                        // Move all selections in this group up by the total number of duplicated rows
13069                        for selection in group_selections {
13070                            let new_start = Point::new(
13071                                selection.start.row.saturating_sub(row_count),
13072                                selection.start.column,
13073                            );
13074
13075                            let new_end = Point::new(
13076                                selection.end.row.saturating_sub(row_count),
13077                                selection.end.column,
13078                            );
13079
13080                            new_ranges.push(new_start..new_end);
13081                        }
13082                    }
13083
13084                    s.select_ranges(new_ranges);
13085                });
13086            }
13087
13088            this.request_autoscroll(Autoscroll::fit(), cx);
13089        });
13090    }
13091
13092    pub fn duplicate_line_up(
13093        &mut self,
13094        _: &DuplicateLineUp,
13095        window: &mut Window,
13096        cx: &mut Context<Self>,
13097    ) {
13098        self.duplicate(true, true, window, cx);
13099    }
13100
13101    pub fn duplicate_line_down(
13102        &mut self,
13103        _: &DuplicateLineDown,
13104        window: &mut Window,
13105        cx: &mut Context<Self>,
13106    ) {
13107        self.duplicate(false, true, window, cx);
13108    }
13109
13110    pub fn duplicate_selection(
13111        &mut self,
13112        _: &DuplicateSelection,
13113        window: &mut Window,
13114        cx: &mut Context<Self>,
13115    ) {
13116        self.duplicate(false, false, window, cx);
13117    }
13118
13119    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13120        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13121        if self.mode.is_single_line() {
13122            cx.propagate();
13123            return;
13124        }
13125
13126        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13127        let buffer = self.buffer.read(cx).snapshot(cx);
13128
13129        let mut edits = Vec::new();
13130        let mut unfold_ranges = Vec::new();
13131        let mut refold_creases = Vec::new();
13132
13133        let selections = self.selections.all::<Point>(&display_map);
13134        let mut selections = selections.iter().peekable();
13135        let mut contiguous_row_selections = Vec::new();
13136        let mut new_selections = Vec::new();
13137
13138        while let Some(selection) = selections.next() {
13139            // Find all the selections that span a contiguous row range
13140            let (start_row, end_row) = consume_contiguous_rows(
13141                &mut contiguous_row_selections,
13142                selection,
13143                &display_map,
13144                &mut selections,
13145            );
13146
13147            // Move the text spanned by the row range to be before the line preceding the row range
13148            if start_row.0 > 0 {
13149                let range_to_move = Point::new(
13150                    start_row.previous_row().0,
13151                    buffer.line_len(start_row.previous_row()),
13152                )
13153                    ..Point::new(
13154                        end_row.previous_row().0,
13155                        buffer.line_len(end_row.previous_row()),
13156                    );
13157                let insertion_point = display_map
13158                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13159                    .0;
13160
13161                // Don't move lines across excerpts
13162                if buffer
13163                    .excerpt_containing(insertion_point..range_to_move.end)
13164                    .is_some()
13165                {
13166                    let text = buffer
13167                        .text_for_range(range_to_move.clone())
13168                        .flat_map(|s| s.chars())
13169                        .skip(1)
13170                        .chain(['\n'])
13171                        .collect::<String>();
13172
13173                    edits.push((
13174                        buffer.anchor_after(range_to_move.start)
13175                            ..buffer.anchor_before(range_to_move.end),
13176                        String::new(),
13177                    ));
13178                    let insertion_anchor = buffer.anchor_after(insertion_point);
13179                    edits.push((insertion_anchor..insertion_anchor, text));
13180
13181                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13182
13183                    // Move selections up
13184                    new_selections.extend(contiguous_row_selections.drain(..).map(
13185                        |mut selection| {
13186                            selection.start.row -= row_delta;
13187                            selection.end.row -= row_delta;
13188                            selection
13189                        },
13190                    ));
13191
13192                    // Move folds up
13193                    unfold_ranges.push(range_to_move.clone());
13194                    for fold in display_map.folds_in_range(
13195                        buffer.anchor_before(range_to_move.start)
13196                            ..buffer.anchor_after(range_to_move.end),
13197                    ) {
13198                        let mut start = fold.range.start.to_point(&buffer);
13199                        let mut end = fold.range.end.to_point(&buffer);
13200                        start.row -= row_delta;
13201                        end.row -= row_delta;
13202                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13203                    }
13204                }
13205            }
13206
13207            // If we didn't move line(s), preserve the existing selections
13208            new_selections.append(&mut contiguous_row_selections);
13209        }
13210
13211        self.transact(window, cx, |this, window, cx| {
13212            this.unfold_ranges(&unfold_ranges, true, true, cx);
13213            this.buffer.update(cx, |buffer, cx| {
13214                for (range, text) in edits {
13215                    buffer.edit([(range, text)], None, cx);
13216                }
13217            });
13218            this.fold_creases(refold_creases, true, window, cx);
13219            this.change_selections(Default::default(), window, cx, |s| {
13220                s.select(new_selections);
13221            })
13222        });
13223    }
13224
13225    pub fn move_line_down(
13226        &mut self,
13227        _: &MoveLineDown,
13228        window: &mut Window,
13229        cx: &mut Context<Self>,
13230    ) {
13231        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13232        if self.mode.is_single_line() {
13233            cx.propagate();
13234            return;
13235        }
13236
13237        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13238        let buffer = self.buffer.read(cx).snapshot(cx);
13239
13240        let mut edits = Vec::new();
13241        let mut unfold_ranges = Vec::new();
13242        let mut refold_creases = Vec::new();
13243
13244        let selections = self.selections.all::<Point>(&display_map);
13245        let mut selections = selections.iter().peekable();
13246        let mut contiguous_row_selections = Vec::new();
13247        let mut new_selections = Vec::new();
13248
13249        while let Some(selection) = selections.next() {
13250            // Find all the selections that span a contiguous row range
13251            let (start_row, end_row) = consume_contiguous_rows(
13252                &mut contiguous_row_selections,
13253                selection,
13254                &display_map,
13255                &mut selections,
13256            );
13257
13258            // Move the text spanned by the row range to be after the last line of the row range
13259            if end_row.0 <= buffer.max_point().row {
13260                let range_to_move =
13261                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13262                let insertion_point = display_map
13263                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13264                    .0;
13265
13266                // Don't move lines across excerpt boundaries
13267                if buffer
13268                    .excerpt_containing(range_to_move.start..insertion_point)
13269                    .is_some()
13270                {
13271                    let mut text = String::from("\n");
13272                    text.extend(buffer.text_for_range(range_to_move.clone()));
13273                    text.pop(); // Drop trailing newline
13274                    edits.push((
13275                        buffer.anchor_after(range_to_move.start)
13276                            ..buffer.anchor_before(range_to_move.end),
13277                        String::new(),
13278                    ));
13279                    let insertion_anchor = buffer.anchor_after(insertion_point);
13280                    edits.push((insertion_anchor..insertion_anchor, text));
13281
13282                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13283
13284                    // Move selections down
13285                    new_selections.extend(contiguous_row_selections.drain(..).map(
13286                        |mut selection| {
13287                            selection.start.row += row_delta;
13288                            selection.end.row += row_delta;
13289                            selection
13290                        },
13291                    ));
13292
13293                    // Move folds down
13294                    unfold_ranges.push(range_to_move.clone());
13295                    for fold in display_map.folds_in_range(
13296                        buffer.anchor_before(range_to_move.start)
13297                            ..buffer.anchor_after(range_to_move.end),
13298                    ) {
13299                        let mut start = fold.range.start.to_point(&buffer);
13300                        let mut end = fold.range.end.to_point(&buffer);
13301                        start.row += row_delta;
13302                        end.row += row_delta;
13303                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13304                    }
13305                }
13306            }
13307
13308            // If we didn't move line(s), preserve the existing selections
13309            new_selections.append(&mut contiguous_row_selections);
13310        }
13311
13312        self.transact(window, cx, |this, window, cx| {
13313            this.unfold_ranges(&unfold_ranges, true, true, cx);
13314            this.buffer.update(cx, |buffer, cx| {
13315                for (range, text) in edits {
13316                    buffer.edit([(range, text)], None, cx);
13317                }
13318            });
13319            this.fold_creases(refold_creases, true, window, cx);
13320            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13321        });
13322    }
13323
13324    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13325        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13326        let text_layout_details = &self.text_layout_details(window, cx);
13327        self.transact(window, cx, |this, window, cx| {
13328            let edits = this.change_selections(Default::default(), window, cx, |s| {
13329                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13330                s.move_with(&mut |display_map, selection| {
13331                    if !selection.is_empty() {
13332                        return;
13333                    }
13334
13335                    let mut head = selection.head();
13336                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13337                    if head.column() == display_map.line_len(head.row()) {
13338                        transpose_offset = display_map
13339                            .buffer_snapshot()
13340                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13341                    }
13342
13343                    if transpose_offset == MultiBufferOffset(0) {
13344                        return;
13345                    }
13346
13347                    *head.column_mut() += 1;
13348                    head = display_map.clip_point(head, Bias::Right);
13349                    let goal = SelectionGoal::HorizontalPosition(
13350                        display_map
13351                            .x_for_display_point(head, text_layout_details)
13352                            .into(),
13353                    );
13354                    selection.collapse_to(head, goal);
13355
13356                    let transpose_start = display_map
13357                        .buffer_snapshot()
13358                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13359                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13360                        let transpose_end = display_map
13361                            .buffer_snapshot()
13362                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13363                        if let Some(ch) = display_map
13364                            .buffer_snapshot()
13365                            .chars_at(transpose_start)
13366                            .next()
13367                        {
13368                            edits.push((transpose_start..transpose_offset, String::new()));
13369                            edits.push((transpose_end..transpose_end, ch.to_string()));
13370                        }
13371                    }
13372                });
13373                edits
13374            });
13375            this.buffer
13376                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13377            let selections = this
13378                .selections
13379                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13380            this.change_selections(Default::default(), window, cx, |s| {
13381                s.select(selections);
13382            });
13383        });
13384    }
13385
13386    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13387        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13388        if self.mode.is_single_line() {
13389            cx.propagate();
13390            return;
13391        }
13392
13393        self.rewrap_impl(RewrapOptions::default(), cx)
13394    }
13395
13396    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13397        let buffer = self.buffer.read(cx).snapshot(cx);
13398        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13399
13400        #[derive(Clone, Debug, PartialEq)]
13401        enum CommentFormat {
13402            /// single line comment, with prefix for line
13403            Line(String),
13404            /// single line within a block comment, with prefix for line
13405            BlockLine(String),
13406            /// a single line of a block comment that includes the initial delimiter
13407            BlockCommentWithStart(BlockCommentConfig),
13408            /// a single line of a block comment that includes the ending delimiter
13409            BlockCommentWithEnd(BlockCommentConfig),
13410        }
13411
13412        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13413        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13414            let language_settings = buffer.language_settings_at(selection.head(), cx);
13415            let language_scope = buffer.language_scope_at(selection.head());
13416
13417            let indent_and_prefix_for_row =
13418                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13419                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13420                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13421                        &language_scope
13422                    {
13423                        let indent_end = Point::new(row, indent.len);
13424                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13425                        let line_text_after_indent = buffer
13426                            .text_for_range(indent_end..line_end)
13427                            .collect::<String>();
13428
13429                        let is_within_comment_override = buffer
13430                            .language_scope_at(indent_end)
13431                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13432                        let comment_delimiters = if is_within_comment_override {
13433                            // we are within a comment syntax node, but we don't
13434                            // yet know what kind of comment: block, doc or line
13435                            match (
13436                                language_scope.documentation_comment(),
13437                                language_scope.block_comment(),
13438                            ) {
13439                                (Some(config), _) | (_, Some(config))
13440                                    if buffer.contains_str_at(indent_end, &config.start) =>
13441                                {
13442                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13443                                }
13444                                (Some(config), _) | (_, Some(config))
13445                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13446                                {
13447                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13448                                }
13449                                (Some(config), _) | (_, Some(config))
13450                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13451                                {
13452                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13453                                }
13454                                (_, _) => language_scope
13455                                    .line_comment_prefixes()
13456                                    .iter()
13457                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13458                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13459                            }
13460                        } else {
13461                            // we not in an overridden comment node, but we may
13462                            // be within a non-overridden line comment node
13463                            language_scope
13464                                .line_comment_prefixes()
13465                                .iter()
13466                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13467                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13468                        };
13469
13470                        let rewrap_prefix = language_scope
13471                            .rewrap_prefixes()
13472                            .iter()
13473                            .find_map(|prefix_regex| {
13474                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13475                                    if mat.start() == 0 {
13476                                        Some(mat.as_str().to_string())
13477                                    } else {
13478                                        None
13479                                    }
13480                                })
13481                            })
13482                            .flatten();
13483                        (comment_delimiters, rewrap_prefix)
13484                    } else {
13485                        (None, None)
13486                    };
13487                    (indent, comment_prefix, rewrap_prefix)
13488                };
13489
13490            let mut start_row = selection.start.row;
13491            let mut end_row = selection.end.row;
13492
13493            if selection.is_empty() {
13494                let cursor_row = selection.start.row;
13495
13496                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13497                let line_prefix = match &comment_prefix {
13498                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13499                        Some(prefix.as_str())
13500                    }
13501                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13502                        prefix, ..
13503                    })) => Some(prefix.as_ref()),
13504                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13505                        start: _,
13506                        end: _,
13507                        prefix,
13508                        tab_size,
13509                    })) => {
13510                        indent_size.len += tab_size;
13511                        Some(prefix.as_ref())
13512                    }
13513                    None => None,
13514                };
13515                let indent_prefix = indent_size.chars().collect::<String>();
13516                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13517
13518                'expand_upwards: while start_row > 0 {
13519                    let prev_row = start_row - 1;
13520                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13521                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13522                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13523                    {
13524                        start_row = prev_row;
13525                    } else {
13526                        break 'expand_upwards;
13527                    }
13528                }
13529
13530                'expand_downwards: while end_row < buffer.max_point().row {
13531                    let next_row = end_row + 1;
13532                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13533                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13534                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13535                    {
13536                        end_row = next_row;
13537                    } else {
13538                        break 'expand_downwards;
13539                    }
13540                }
13541            }
13542
13543            let mut non_blank_rows_iter = (start_row..=end_row)
13544                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13545                .peekable();
13546
13547            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13548                row
13549            } else {
13550                return Vec::new();
13551            };
13552
13553            let mut ranges = Vec::new();
13554
13555            let mut current_range_start = first_row;
13556            let mut prev_row = first_row;
13557            let (
13558                mut current_range_indent,
13559                mut current_range_comment_delimiters,
13560                mut current_range_rewrap_prefix,
13561            ) = indent_and_prefix_for_row(first_row);
13562
13563            for row in non_blank_rows_iter.skip(1) {
13564                let has_paragraph_break = row > prev_row + 1;
13565
13566                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13567                    indent_and_prefix_for_row(row);
13568
13569                let has_indent_change = row_indent != current_range_indent;
13570                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13571
13572                let has_boundary_change = has_comment_change
13573                    || row_rewrap_prefix.is_some()
13574                    || (has_indent_change && current_range_comment_delimiters.is_some());
13575
13576                if has_paragraph_break || has_boundary_change {
13577                    ranges.push((
13578                        language_settings.clone(),
13579                        Point::new(current_range_start, 0)
13580                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13581                        current_range_indent,
13582                        current_range_comment_delimiters.clone(),
13583                        current_range_rewrap_prefix.clone(),
13584                    ));
13585                    current_range_start = row;
13586                    current_range_indent = row_indent;
13587                    current_range_comment_delimiters = row_comment_delimiters;
13588                    current_range_rewrap_prefix = row_rewrap_prefix;
13589                }
13590                prev_row = row;
13591            }
13592
13593            ranges.push((
13594                language_settings.clone(),
13595                Point::new(current_range_start, 0)
13596                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13597                current_range_indent,
13598                current_range_comment_delimiters,
13599                current_range_rewrap_prefix,
13600            ));
13601
13602            ranges
13603        });
13604
13605        let mut edits = Vec::new();
13606        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13607
13608        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13609            wrap_ranges
13610        {
13611            let start_row = wrap_range.start.row;
13612            let end_row = wrap_range.end.row;
13613
13614            // Skip selections that overlap with a range that has already been rewrapped.
13615            let selection_range = start_row..end_row;
13616            if rewrapped_row_ranges
13617                .iter()
13618                .any(|range| range.overlaps(&selection_range))
13619            {
13620                continue;
13621            }
13622
13623            let tab_size = language_settings.tab_size;
13624
13625            let (line_prefix, inside_comment) = match &comment_prefix {
13626                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13627                    (Some(prefix.as_str()), true)
13628                }
13629                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13630                    (Some(prefix.as_ref()), true)
13631                }
13632                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13633                    start: _,
13634                    end: _,
13635                    prefix,
13636                    tab_size,
13637                })) => {
13638                    indent_size.len += tab_size;
13639                    (Some(prefix.as_ref()), true)
13640                }
13641                None => (None, false),
13642            };
13643            let indent_prefix = indent_size.chars().collect::<String>();
13644            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13645
13646            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13647                RewrapBehavior::InComments => inside_comment,
13648                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13649                RewrapBehavior::Anywhere => true,
13650            };
13651
13652            let should_rewrap = options.override_language_settings
13653                || allow_rewrap_based_on_language
13654                || self.hard_wrap.is_some();
13655            if !should_rewrap {
13656                continue;
13657            }
13658
13659            let start = Point::new(start_row, 0);
13660            let start_offset = ToOffset::to_offset(&start, &buffer);
13661            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13662            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13663            let mut first_line_delimiter = None;
13664            let mut last_line_delimiter = None;
13665            let Some(lines_without_prefixes) = selection_text
13666                .lines()
13667                .enumerate()
13668                .map(|(ix, line)| {
13669                    let line_trimmed = line.trim_start();
13670                    if rewrap_prefix.is_some() && ix > 0 {
13671                        Ok(line_trimmed)
13672                    } else if let Some(
13673                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13674                            start,
13675                            prefix,
13676                            end,
13677                            tab_size,
13678                        })
13679                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13680                            start,
13681                            prefix,
13682                            end,
13683                            tab_size,
13684                        }),
13685                    ) = &comment_prefix
13686                    {
13687                        let line_trimmed = line_trimmed
13688                            .strip_prefix(start.as_ref())
13689                            .map(|s| {
13690                                let mut indent_size = indent_size;
13691                                indent_size.len -= tab_size;
13692                                let indent_prefix: String = indent_size.chars().collect();
13693                                first_line_delimiter = Some((indent_prefix, start));
13694                                s.trim_start()
13695                            })
13696                            .unwrap_or(line_trimmed);
13697                        let line_trimmed = line_trimmed
13698                            .strip_suffix(end.as_ref())
13699                            .map(|s| {
13700                                last_line_delimiter = Some(end);
13701                                s.trim_end()
13702                            })
13703                            .unwrap_or(line_trimmed);
13704                        let line_trimmed = line_trimmed
13705                            .strip_prefix(prefix.as_ref())
13706                            .unwrap_or(line_trimmed);
13707                        Ok(line_trimmed)
13708                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13709                        line_trimmed.strip_prefix(prefix).with_context(|| {
13710                            format!("line did not start with prefix {prefix:?}: {line:?}")
13711                        })
13712                    } else {
13713                        line_trimmed
13714                            .strip_prefix(&line_prefix.trim_start())
13715                            .with_context(|| {
13716                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13717                            })
13718                    }
13719                })
13720                .collect::<Result<Vec<_>, _>>()
13721                .log_err()
13722            else {
13723                continue;
13724            };
13725
13726            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13727                buffer
13728                    .language_settings_at(Point::new(start_row, 0), cx)
13729                    .preferred_line_length as usize
13730            });
13731
13732            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13733                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13734            } else {
13735                line_prefix.clone()
13736            };
13737
13738            let wrapped_text = {
13739                let mut wrapped_text = wrap_with_prefix(
13740                    line_prefix,
13741                    subsequent_lines_prefix,
13742                    lines_without_prefixes.join("\n"),
13743                    wrap_column,
13744                    tab_size,
13745                    options.preserve_existing_whitespace,
13746                );
13747
13748                if let Some((indent, delimiter)) = first_line_delimiter {
13749                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13750                }
13751                if let Some(last_line) = last_line_delimiter {
13752                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13753                }
13754
13755                wrapped_text
13756            };
13757
13758            // TODO: should always use char-based diff while still supporting cursor behavior that
13759            // matches vim.
13760            let mut diff_options = DiffOptions::default();
13761            if options.override_language_settings {
13762                diff_options.max_word_diff_len = 0;
13763                diff_options.max_word_diff_line_count = 0;
13764            } else {
13765                diff_options.max_word_diff_len = usize::MAX;
13766                diff_options.max_word_diff_line_count = usize::MAX;
13767            }
13768
13769            for (old_range, new_text) in
13770                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13771            {
13772                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13773                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13774                edits.push((edit_start..edit_end, new_text));
13775            }
13776
13777            rewrapped_row_ranges.push(start_row..=end_row);
13778        }
13779
13780        self.buffer
13781            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13782    }
13783
13784    pub fn cut_common(
13785        &mut self,
13786        cut_no_selection_line: bool,
13787        window: &mut Window,
13788        cx: &mut Context<Self>,
13789    ) -> ClipboardItem {
13790        let mut text = String::new();
13791        let buffer = self.buffer.read(cx).snapshot(cx);
13792        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13793        let mut clipboard_selections = Vec::with_capacity(selections.len());
13794        {
13795            let max_point = buffer.max_point();
13796            let mut is_first = true;
13797            let mut prev_selection_was_entire_line = false;
13798            for selection in &mut selections {
13799                let is_entire_line =
13800                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13801                if is_entire_line {
13802                    selection.start = Point::new(selection.start.row, 0);
13803                    if !selection.is_empty() && selection.end.column == 0 {
13804                        selection.end = cmp::min(max_point, selection.end);
13805                    } else {
13806                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13807                    }
13808                    selection.goal = SelectionGoal::None;
13809                }
13810                if is_first {
13811                    is_first = false;
13812                } else if !prev_selection_was_entire_line {
13813                    text += "\n";
13814                }
13815                prev_selection_was_entire_line = is_entire_line;
13816                let mut len = 0;
13817                for chunk in buffer.text_for_range(selection.start..selection.end) {
13818                    text.push_str(chunk);
13819                    len += chunk.len();
13820                }
13821
13822                clipboard_selections.push(ClipboardSelection::for_buffer(
13823                    len,
13824                    is_entire_line,
13825                    selection.range(),
13826                    &buffer,
13827                    self.project.as_ref(),
13828                    cx,
13829                ));
13830            }
13831        }
13832
13833        self.transact(window, cx, |this, window, cx| {
13834            this.change_selections(Default::default(), window, cx, |s| {
13835                s.select(selections);
13836            });
13837            this.insert("", window, cx);
13838        });
13839        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13840    }
13841
13842    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13843        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13844        let item = self.cut_common(true, window, cx);
13845        cx.write_to_clipboard(item);
13846    }
13847
13848    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13849        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13850        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13851            s.move_with(&mut |snapshot, sel| {
13852                if sel.is_empty() {
13853                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13854                }
13855                if sel.is_empty() {
13856                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13857                }
13858            });
13859        });
13860        let item = self.cut_common(false, window, cx);
13861        cx.set_global(KillRing(item))
13862    }
13863
13864    pub fn kill_ring_yank(
13865        &mut self,
13866        _: &KillRingYank,
13867        window: &mut Window,
13868        cx: &mut Context<Self>,
13869    ) {
13870        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13871        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13872            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13873                (kill_ring.text().to_string(), kill_ring.metadata_json())
13874            } else {
13875                return;
13876            }
13877        } else {
13878            return;
13879        };
13880        self.do_paste(&text, metadata, false, window, cx);
13881    }
13882
13883    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13884        self.do_copy(true, cx);
13885    }
13886
13887    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13888        self.do_copy(false, cx);
13889    }
13890
13891    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13892        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13893        let buffer = self.buffer.read(cx).read(cx);
13894        let mut text = String::new();
13895        let mut clipboard_selections = Vec::with_capacity(selections.len());
13896
13897        let max_point = buffer.max_point();
13898        let mut is_first = true;
13899        for selection in &selections {
13900            let mut start = selection.start;
13901            let mut end = selection.end;
13902            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13903            let mut add_trailing_newline = false;
13904            if is_entire_line {
13905                start = Point::new(start.row, 0);
13906                let next_line_start = Point::new(end.row + 1, 0);
13907                if next_line_start <= max_point {
13908                    end = next_line_start;
13909                } else {
13910                    // We're on the last line without a trailing newline.
13911                    // Copy to the end of the line and add a newline afterwards.
13912                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13913                    add_trailing_newline = true;
13914                }
13915            }
13916
13917            let mut trimmed_selections = Vec::new();
13918            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13919                let row = MultiBufferRow(start.row);
13920                let first_indent = buffer.indent_size_for_line(row);
13921                if first_indent.len == 0 || start.column > first_indent.len {
13922                    trimmed_selections.push(start..end);
13923                } else {
13924                    trimmed_selections.push(
13925                        Point::new(row.0, first_indent.len)
13926                            ..Point::new(row.0, buffer.line_len(row)),
13927                    );
13928                    for row in start.row + 1..=end.row {
13929                        let mut line_len = buffer.line_len(MultiBufferRow(row));
13930                        if row == end.row {
13931                            line_len = end.column;
13932                        }
13933                        if line_len == 0 {
13934                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
13935                            continue;
13936                        }
13937                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13938                        if row_indent_size.len >= first_indent.len {
13939                            trimmed_selections
13940                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
13941                        } else {
13942                            trimmed_selections.clear();
13943                            trimmed_selections.push(start..end);
13944                            break;
13945                        }
13946                    }
13947                }
13948            } else {
13949                trimmed_selections.push(start..end);
13950            }
13951
13952            let is_multiline_trim = trimmed_selections.len() > 1;
13953            let mut selection_len: usize = 0;
13954            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13955
13956            for trimmed_range in trimmed_selections {
13957                if is_first {
13958                    is_first = false;
13959                } else if is_multiline_trim || !prev_selection_was_entire_line {
13960                    text.push('\n');
13961                    if is_multiline_trim {
13962                        selection_len += 1;
13963                    }
13964                }
13965                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13966                    text.push_str(chunk);
13967                    selection_len += chunk.len();
13968                }
13969                if add_trailing_newline {
13970                    text.push('\n');
13971                    selection_len += 1;
13972                }
13973            }
13974
13975            clipboard_selections.push(ClipboardSelection::for_buffer(
13976                selection_len,
13977                is_entire_line,
13978                start..end,
13979                &buffer,
13980                self.project.as_ref(),
13981                cx,
13982            ));
13983        }
13984
13985        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13986            text,
13987            clipboard_selections,
13988        ));
13989    }
13990
13991    pub fn do_paste(
13992        &mut self,
13993        text: &String,
13994        clipboard_selections: Option<Vec<ClipboardSelection>>,
13995        handle_entire_lines: bool,
13996        window: &mut Window,
13997        cx: &mut Context<Self>,
13998    ) {
13999        if self.read_only(cx) {
14000            return;
14001        }
14002
14003        let clipboard_text = Cow::Borrowed(text.as_str());
14004
14005        self.transact(window, cx, |this, window, cx| {
14006            let had_active_edit_prediction = this.has_active_edit_prediction();
14007            let display_map = this.display_snapshot(cx);
14008            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14009            let cursor_offset = this
14010                .selections
14011                .last::<MultiBufferOffset>(&display_map)
14012                .head();
14013
14014            if let Some(mut clipboard_selections) = clipboard_selections {
14015                let all_selections_were_entire_line =
14016                    clipboard_selections.iter().all(|s| s.is_entire_line);
14017                let first_selection_indent_column =
14018                    clipboard_selections.first().map(|s| s.first_line_indent);
14019                if clipboard_selections.len() != old_selections.len() {
14020                    clipboard_selections.drain(..);
14021                }
14022                let mut auto_indent_on_paste = true;
14023
14024                this.buffer.update(cx, |buffer, cx| {
14025                    let snapshot = buffer.read(cx);
14026                    auto_indent_on_paste = snapshot
14027                        .language_settings_at(cursor_offset, cx)
14028                        .auto_indent_on_paste;
14029
14030                    let mut start_offset = 0;
14031                    let mut edits = Vec::new();
14032                    let mut original_indent_columns = Vec::new();
14033                    for (ix, selection) in old_selections.iter().enumerate() {
14034                        let to_insert;
14035                        let entire_line;
14036                        let original_indent_column;
14037                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14038                            let end_offset = start_offset + clipboard_selection.len;
14039                            to_insert = &clipboard_text[start_offset..end_offset];
14040                            entire_line = clipboard_selection.is_entire_line;
14041                            start_offset = if entire_line {
14042                                end_offset
14043                            } else {
14044                                end_offset + 1
14045                            };
14046                            original_indent_column = Some(clipboard_selection.first_line_indent);
14047                        } else {
14048                            to_insert = &*clipboard_text;
14049                            entire_line = all_selections_were_entire_line;
14050                            original_indent_column = first_selection_indent_column
14051                        }
14052
14053                        let (range, to_insert) =
14054                            if selection.is_empty() && handle_entire_lines && entire_line {
14055                                // If the corresponding selection was empty when this slice of the
14056                                // clipboard text was written, then the entire line containing the
14057                                // selection was copied. If this selection is also currently empty,
14058                                // then paste the line before the current line of the buffer.
14059                                let column = selection.start.to_point(&snapshot).column as usize;
14060                                let line_start = selection.start - column;
14061                                (line_start..line_start, Cow::Borrowed(to_insert))
14062                            } else {
14063                                let language = snapshot.language_at(selection.head());
14064                                let range = selection.range();
14065                                if let Some(language) = language
14066                                    && language.name() == "Markdown"
14067                                {
14068                                    edit_for_markdown_paste(
14069                                        &snapshot,
14070                                        range,
14071                                        to_insert,
14072                                        url::Url::parse(to_insert).ok(),
14073                                    )
14074                                } else {
14075                                    (range, Cow::Borrowed(to_insert))
14076                                }
14077                            };
14078
14079                        edits.push((range, to_insert));
14080                        original_indent_columns.push(original_indent_column);
14081                    }
14082                    drop(snapshot);
14083
14084                    buffer.edit(
14085                        edits,
14086                        if auto_indent_on_paste {
14087                            Some(AutoindentMode::Block {
14088                                original_indent_columns,
14089                            })
14090                        } else {
14091                            None
14092                        },
14093                        cx,
14094                    );
14095                });
14096
14097                let selections = this
14098                    .selections
14099                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14100                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14101            } else {
14102                let url = url::Url::parse(&clipboard_text).ok();
14103
14104                let auto_indent_mode = if !clipboard_text.is_empty() {
14105                    Some(AutoindentMode::Block {
14106                        original_indent_columns: Vec::new(),
14107                    })
14108                } else {
14109                    None
14110                };
14111
14112                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14113                    let snapshot = buffer.snapshot(cx);
14114
14115                    let anchors = old_selections
14116                        .iter()
14117                        .map(|s| {
14118                            let anchor = snapshot.anchor_after(s.head());
14119                            s.map(|_| anchor)
14120                        })
14121                        .collect::<Vec<_>>();
14122
14123                    let mut edits = Vec::new();
14124
14125                    // When pasting text without metadata (e.g. copied from an
14126                    // external editor using multiple cursors) and the number of
14127                    // lines matches the number of selections, distribute one
14128                    // line per cursor instead of pasting the whole text at each.
14129                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14130                    let distribute_lines =
14131                        old_selections.len() > 1 && lines.len() == old_selections.len();
14132
14133                    for (ix, selection) in old_selections.iter().enumerate() {
14134                        let language = snapshot.language_at(selection.head());
14135                        let range = selection.range();
14136
14137                        let text_for_cursor: &str = if distribute_lines {
14138                            lines[ix]
14139                        } else {
14140                            &clipboard_text
14141                        };
14142
14143                        let (edit_range, edit_text) = if let Some(language) = language
14144                            && language.name() == "Markdown"
14145                        {
14146                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14147                        } else {
14148                            (range, Cow::Borrowed(text_for_cursor))
14149                        };
14150
14151                        edits.push((edit_range, edit_text));
14152                    }
14153
14154                    drop(snapshot);
14155                    buffer.edit(edits, auto_indent_mode, cx);
14156
14157                    anchors
14158                });
14159
14160                this.change_selections(Default::default(), window, cx, |s| {
14161                    s.select_anchors(selection_anchors);
14162                });
14163            }
14164
14165            //   🤔                 |    ..     | show_in_menu |
14166            // | ..                  |   true        true
14167            // | had_edit_prediction |   false       true
14168
14169            let trigger_in_words =
14170                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14171
14172            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14173        });
14174    }
14175
14176    pub fn diff_clipboard_with_selection(
14177        &mut self,
14178        _: &DiffClipboardWithSelection,
14179        window: &mut Window,
14180        cx: &mut Context<Self>,
14181    ) {
14182        let selections = self
14183            .selections
14184            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14185
14186        if selections.is_empty() {
14187            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14188            return;
14189        };
14190
14191        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14192            item.entries().iter().find_map(|entry| match entry {
14193                ClipboardEntry::String(text) => Some(text.text().to_string()),
14194                _ => None,
14195            })
14196        });
14197
14198        let Some(clipboard_text) = clipboard_text else {
14199            log::warn!("Clipboard doesn't contain text.");
14200            return;
14201        };
14202
14203        window.dispatch_action(
14204            Box::new(DiffClipboardWithSelectionData {
14205                clipboard_text,
14206                editor: cx.entity(),
14207            }),
14208            cx,
14209        );
14210    }
14211
14212    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14213        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14214        if let Some(item) = cx.read_from_clipboard() {
14215            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14216                ClipboardEntry::String(s) => Some(s),
14217                _ => None,
14218            });
14219            match clipboard_string {
14220                Some(clipboard_string) => self.do_paste(
14221                    clipboard_string.text(),
14222                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14223                    true,
14224                    window,
14225                    cx,
14226                ),
14227                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14228            }
14229        }
14230    }
14231
14232    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14233        if self.read_only(cx) {
14234            return;
14235        }
14236
14237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14238
14239        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14240            if let Some((selections, _)) =
14241                self.selection_history.transaction(transaction_id).cloned()
14242            {
14243                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14244                    s.select_anchors(selections.to_vec());
14245                });
14246            } else {
14247                log::error!(
14248                    "No entry in selection_history found for undo. \
14249                     This may correspond to a bug where undo does not update the selection. \
14250                     If this is occurring, please add details to \
14251                     https://github.com/zed-industries/zed/issues/22692"
14252                );
14253            }
14254            self.request_autoscroll(Autoscroll::fit(), cx);
14255            self.unmark_text(window, cx);
14256            self.refresh_edit_prediction(true, false, window, cx);
14257            cx.emit(EditorEvent::Edited { transaction_id });
14258            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14259        }
14260    }
14261
14262    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14263        if self.read_only(cx) {
14264            return;
14265        }
14266
14267        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14268
14269        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14270            if let Some((_, Some(selections))) =
14271                self.selection_history.transaction(transaction_id).cloned()
14272            {
14273                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14274                    s.select_anchors(selections.to_vec());
14275                });
14276            } else {
14277                log::error!(
14278                    "No entry in selection_history found for redo. \
14279                     This may correspond to a bug where undo does not update the selection. \
14280                     If this is occurring, please add details to \
14281                     https://github.com/zed-industries/zed/issues/22692"
14282                );
14283            }
14284            self.request_autoscroll(Autoscroll::fit(), cx);
14285            self.unmark_text(window, cx);
14286            self.refresh_edit_prediction(true, false, window, cx);
14287            cx.emit(EditorEvent::Edited { transaction_id });
14288        }
14289    }
14290
14291    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14292        self.buffer
14293            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14294    }
14295
14296    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14297        self.buffer
14298            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14299    }
14300
14301    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14302        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14303        self.change_selections(Default::default(), window, cx, |s| {
14304            s.move_with(&mut |map, selection| {
14305                let cursor = if selection.is_empty() {
14306                    movement::left(map, selection.start)
14307                } else {
14308                    selection.start
14309                };
14310                selection.collapse_to(cursor, SelectionGoal::None);
14311            });
14312        })
14313    }
14314
14315    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14316        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14317        self.change_selections(Default::default(), window, cx, |s| {
14318            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14319        })
14320    }
14321
14322    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14323        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14324        self.change_selections(Default::default(), window, cx, |s| {
14325            s.move_with(&mut |map, selection| {
14326                let cursor = if selection.is_empty() {
14327                    movement::right(map, selection.end)
14328                } else {
14329                    selection.end
14330                };
14331                selection.collapse_to(cursor, SelectionGoal::None)
14332            });
14333        })
14334    }
14335
14336    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14337        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14338        self.change_selections(Default::default(), window, cx, |s| {
14339            s.move_heads_with(&mut |map, head, _| {
14340                (movement::right(map, head), SelectionGoal::None)
14341            });
14342        });
14343    }
14344
14345    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14346        if self.take_rename(true, window, cx).is_some() {
14347            return;
14348        }
14349
14350        if self.mode.is_single_line() {
14351            cx.propagate();
14352            return;
14353        }
14354
14355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14356
14357        let text_layout_details = &self.text_layout_details(window, cx);
14358        let selection_count = self.selections.count();
14359        let first_selection = self.selections.first_anchor();
14360
14361        self.change_selections(Default::default(), window, cx, |s| {
14362            s.move_with(&mut |map, selection| {
14363                if !selection.is_empty() {
14364                    selection.goal = SelectionGoal::None;
14365                }
14366                let (cursor, goal) = movement::up(
14367                    map,
14368                    selection.start,
14369                    selection.goal,
14370                    false,
14371                    text_layout_details,
14372                );
14373                selection.collapse_to(cursor, goal);
14374            });
14375        });
14376
14377        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14378        {
14379            cx.propagate();
14380        }
14381    }
14382
14383    pub fn move_up_by_lines(
14384        &mut self,
14385        action: &MoveUpByLines,
14386        window: &mut Window,
14387        cx: &mut Context<Self>,
14388    ) {
14389        if self.take_rename(true, window, cx).is_some() {
14390            return;
14391        }
14392
14393        if self.mode.is_single_line() {
14394            cx.propagate();
14395            return;
14396        }
14397
14398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14399
14400        let text_layout_details = &self.text_layout_details(window, cx);
14401
14402        self.change_selections(Default::default(), window, cx, |s| {
14403            s.move_with(&mut |map, selection| {
14404                if !selection.is_empty() {
14405                    selection.goal = SelectionGoal::None;
14406                }
14407                let (cursor, goal) = movement::up_by_rows(
14408                    map,
14409                    selection.start,
14410                    action.lines,
14411                    selection.goal,
14412                    false,
14413                    text_layout_details,
14414                );
14415                selection.collapse_to(cursor, goal);
14416            });
14417        })
14418    }
14419
14420    pub fn move_down_by_lines(
14421        &mut self,
14422        action: &MoveDownByLines,
14423        window: &mut Window,
14424        cx: &mut Context<Self>,
14425    ) {
14426        if self.take_rename(true, window, cx).is_some() {
14427            return;
14428        }
14429
14430        if self.mode.is_single_line() {
14431            cx.propagate();
14432            return;
14433        }
14434
14435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14436
14437        let text_layout_details = &self.text_layout_details(window, cx);
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::down_by_rows(
14445                    map,
14446                    selection.start,
14447                    action.lines,
14448                    selection.goal,
14449                    false,
14450                    text_layout_details,
14451                );
14452                selection.collapse_to(cursor, goal);
14453            });
14454        })
14455    }
14456
14457    pub fn select_down_by_lines(
14458        &mut self,
14459        action: &SelectDownByLines,
14460        window: &mut Window,
14461        cx: &mut Context<Self>,
14462    ) {
14463        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14464        let text_layout_details = &self.text_layout_details(window, cx);
14465        self.change_selections(Default::default(), window, cx, |s| {
14466            s.move_heads_with(&mut |map, head, goal| {
14467                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14468            })
14469        })
14470    }
14471
14472    pub fn select_up_by_lines(
14473        &mut self,
14474        action: &SelectUpByLines,
14475        window: &mut Window,
14476        cx: &mut Context<Self>,
14477    ) {
14478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14479        let text_layout_details = &self.text_layout_details(window, cx);
14480        self.change_selections(Default::default(), window, cx, |s| {
14481            s.move_heads_with(&mut |map, head, goal| {
14482                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14483            })
14484        })
14485    }
14486
14487    pub fn select_page_up(
14488        &mut self,
14489        _: &SelectPageUp,
14490        window: &mut Window,
14491        cx: &mut Context<Self>,
14492    ) {
14493        let Some(row_count) = self.visible_row_count() else {
14494            return;
14495        };
14496
14497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14498
14499        let text_layout_details = &self.text_layout_details(window, cx);
14500
14501        self.change_selections(Default::default(), window, cx, |s| {
14502            s.move_heads_with(&mut |map, head, goal| {
14503                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14504            })
14505        })
14506    }
14507
14508    pub fn move_page_up(
14509        &mut self,
14510        action: &MovePageUp,
14511        window: &mut Window,
14512        cx: &mut Context<Self>,
14513    ) {
14514        if self.take_rename(true, window, cx).is_some() {
14515            return;
14516        }
14517
14518        if self
14519            .context_menu
14520            .borrow_mut()
14521            .as_mut()
14522            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14523            .unwrap_or(false)
14524        {
14525            return;
14526        }
14527
14528        if matches!(self.mode, EditorMode::SingleLine) {
14529            cx.propagate();
14530            return;
14531        }
14532
14533        let Some(row_count) = self.visible_row_count() else {
14534            return;
14535        };
14536
14537        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14538
14539        let effects = if action.center_cursor {
14540            SelectionEffects::scroll(Autoscroll::center())
14541        } else {
14542            SelectionEffects::default()
14543        };
14544
14545        let text_layout_details = &self.text_layout_details(window, cx);
14546
14547        self.change_selections(effects, window, cx, |s| {
14548            s.move_with(&mut |map, selection| {
14549                if !selection.is_empty() {
14550                    selection.goal = SelectionGoal::None;
14551                }
14552                let (cursor, goal) = movement::up_by_rows(
14553                    map,
14554                    selection.end,
14555                    row_count,
14556                    selection.goal,
14557                    false,
14558                    text_layout_details,
14559                );
14560                selection.collapse_to(cursor, goal);
14561            });
14562        });
14563    }
14564
14565    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14567        let text_layout_details = &self.text_layout_details(window, cx);
14568        self.change_selections(Default::default(), window, cx, |s| {
14569            s.move_heads_with(&mut |map, head, goal| {
14570                movement::up(map, head, goal, false, text_layout_details)
14571            })
14572        })
14573    }
14574
14575    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14576        self.take_rename(true, window, cx);
14577
14578        if self.mode.is_single_line() {
14579            cx.propagate();
14580            return;
14581        }
14582
14583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14584
14585        let text_layout_details = &self.text_layout_details(window, cx);
14586        let selection_count = self.selections.count();
14587        let first_selection = self.selections.first_anchor();
14588
14589        self.change_selections(Default::default(), window, cx, |s| {
14590            s.move_with(&mut |map, selection| {
14591                if !selection.is_empty() {
14592                    selection.goal = SelectionGoal::None;
14593                }
14594                let (cursor, goal) = movement::down(
14595                    map,
14596                    selection.end,
14597                    selection.goal,
14598                    false,
14599                    text_layout_details,
14600                );
14601                selection.collapse_to(cursor, goal);
14602            });
14603        });
14604
14605        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14606        {
14607            cx.propagate();
14608        }
14609    }
14610
14611    pub fn select_page_down(
14612        &mut self,
14613        _: &SelectPageDown,
14614        window: &mut Window,
14615        cx: &mut Context<Self>,
14616    ) {
14617        let Some(row_count) = self.visible_row_count() else {
14618            return;
14619        };
14620
14621        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14622
14623        let text_layout_details = &self.text_layout_details(window, cx);
14624
14625        self.change_selections(Default::default(), window, cx, |s| {
14626            s.move_heads_with(&mut |map, head, goal| {
14627                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14628            })
14629        })
14630    }
14631
14632    pub fn move_page_down(
14633        &mut self,
14634        action: &MovePageDown,
14635        window: &mut Window,
14636        cx: &mut Context<Self>,
14637    ) {
14638        if self.take_rename(true, window, cx).is_some() {
14639            return;
14640        }
14641
14642        if self
14643            .context_menu
14644            .borrow_mut()
14645            .as_mut()
14646            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14647            .unwrap_or(false)
14648        {
14649            return;
14650        }
14651
14652        if matches!(self.mode, EditorMode::SingleLine) {
14653            cx.propagate();
14654            return;
14655        }
14656
14657        let Some(row_count) = self.visible_row_count() else {
14658            return;
14659        };
14660
14661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14662
14663        let effects = if action.center_cursor {
14664            SelectionEffects::scroll(Autoscroll::center())
14665        } else {
14666            SelectionEffects::default()
14667        };
14668
14669        let text_layout_details = &self.text_layout_details(window, cx);
14670        self.change_selections(effects, window, cx, |s| {
14671            s.move_with(&mut |map, selection| {
14672                if !selection.is_empty() {
14673                    selection.goal = SelectionGoal::None;
14674                }
14675                let (cursor, goal) = movement::down_by_rows(
14676                    map,
14677                    selection.end,
14678                    row_count,
14679                    selection.goal,
14680                    false,
14681                    text_layout_details,
14682                );
14683                selection.collapse_to(cursor, goal);
14684            });
14685        });
14686    }
14687
14688    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14689        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14690        let text_layout_details = &self.text_layout_details(window, cx);
14691        self.change_selections(Default::default(), window, cx, |s| {
14692            s.move_heads_with(&mut |map, head, goal| {
14693                movement::down(map, head, goal, false, text_layout_details)
14694            })
14695        });
14696    }
14697
14698    pub fn context_menu_first(
14699        &mut self,
14700        _: &ContextMenuFirst,
14701        window: &mut Window,
14702        cx: &mut Context<Self>,
14703    ) {
14704        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14705            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14706        }
14707    }
14708
14709    pub fn context_menu_prev(
14710        &mut self,
14711        _: &ContextMenuPrevious,
14712        window: &mut Window,
14713        cx: &mut Context<Self>,
14714    ) {
14715        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14716            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14717        }
14718    }
14719
14720    pub fn context_menu_next(
14721        &mut self,
14722        _: &ContextMenuNext,
14723        window: &mut Window,
14724        cx: &mut Context<Self>,
14725    ) {
14726        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14727            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14728        }
14729    }
14730
14731    pub fn context_menu_last(
14732        &mut self,
14733        _: &ContextMenuLast,
14734        window: &mut Window,
14735        cx: &mut Context<Self>,
14736    ) {
14737        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14738            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14739        }
14740    }
14741
14742    pub fn signature_help_prev(
14743        &mut self,
14744        _: &SignatureHelpPrevious,
14745        _: &mut Window,
14746        cx: &mut Context<Self>,
14747    ) {
14748        if let Some(popover) = self.signature_help_state.popover_mut() {
14749            if popover.current_signature == 0 {
14750                popover.current_signature = popover.signatures.len() - 1;
14751            } else {
14752                popover.current_signature -= 1;
14753            }
14754            cx.notify();
14755        }
14756    }
14757
14758    pub fn signature_help_next(
14759        &mut self,
14760        _: &SignatureHelpNext,
14761        _: &mut Window,
14762        cx: &mut Context<Self>,
14763    ) {
14764        if let Some(popover) = self.signature_help_state.popover_mut() {
14765            if popover.current_signature + 1 == popover.signatures.len() {
14766                popover.current_signature = 0;
14767            } else {
14768                popover.current_signature += 1;
14769            }
14770            cx.notify();
14771        }
14772    }
14773
14774    pub fn move_to_previous_word_start(
14775        &mut self,
14776        _: &MoveToPreviousWordStart,
14777        window: &mut Window,
14778        cx: &mut Context<Self>,
14779    ) {
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14781        self.change_selections(Default::default(), window, cx, |s| {
14782            s.move_cursors_with(&mut |map, head, _| {
14783                (
14784                    movement::previous_word_start(map, head),
14785                    SelectionGoal::None,
14786                )
14787            });
14788        })
14789    }
14790
14791    pub fn move_to_previous_subword_start(
14792        &mut self,
14793        _: &MoveToPreviousSubwordStart,
14794        window: &mut Window,
14795        cx: &mut Context<Self>,
14796    ) {
14797        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14798        self.change_selections(Default::default(), window, cx, |s| {
14799            s.move_cursors_with(&mut |map, head, _| {
14800                (
14801                    movement::previous_subword_start(map, head),
14802                    SelectionGoal::None,
14803                )
14804            });
14805        })
14806    }
14807
14808    pub fn select_to_previous_word_start(
14809        &mut self,
14810        _: &SelectToPreviousWordStart,
14811        window: &mut Window,
14812        cx: &mut Context<Self>,
14813    ) {
14814        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14815        self.change_selections(Default::default(), window, cx, |s| {
14816            s.move_heads_with(&mut |map, head, _| {
14817                (
14818                    movement::previous_word_start(map, head),
14819                    SelectionGoal::None,
14820                )
14821            });
14822        })
14823    }
14824
14825    pub fn select_to_previous_subword_start(
14826        &mut self,
14827        _: &SelectToPreviousSubwordStart,
14828        window: &mut Window,
14829        cx: &mut Context<Self>,
14830    ) {
14831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14832        self.change_selections(Default::default(), window, cx, |s| {
14833            s.move_heads_with(&mut |map, head, _| {
14834                (
14835                    movement::previous_subword_start(map, head),
14836                    SelectionGoal::None,
14837                )
14838            });
14839        })
14840    }
14841
14842    pub fn delete_to_previous_word_start(
14843        &mut self,
14844        action: &DeleteToPreviousWordStart,
14845        window: &mut Window,
14846        cx: &mut Context<Self>,
14847    ) {
14848        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14849        self.transact(window, cx, |this, window, cx| {
14850            this.select_autoclose_pair(window, cx);
14851            this.change_selections(Default::default(), window, cx, |s| {
14852                s.move_with(&mut |map, selection| {
14853                    if selection.is_empty() {
14854                        let mut cursor = if action.ignore_newlines {
14855                            movement::previous_word_start(map, selection.head())
14856                        } else {
14857                            movement::previous_word_start_or_newline(map, selection.head())
14858                        };
14859                        cursor = movement::adjust_greedy_deletion(
14860                            map,
14861                            selection.head(),
14862                            cursor,
14863                            action.ignore_brackets,
14864                        );
14865                        selection.set_head(cursor, SelectionGoal::None);
14866                    }
14867                });
14868            });
14869            this.insert("", window, cx);
14870        });
14871    }
14872
14873    pub fn delete_to_previous_subword_start(
14874        &mut self,
14875        action: &DeleteToPreviousSubwordStart,
14876        window: &mut Window,
14877        cx: &mut Context<Self>,
14878    ) {
14879        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14880        self.transact(window, cx, |this, window, cx| {
14881            this.select_autoclose_pair(window, cx);
14882            this.change_selections(Default::default(), window, cx, |s| {
14883                s.move_with(&mut |map, selection| {
14884                    if selection.is_empty() {
14885                        let mut cursor = if action.ignore_newlines {
14886                            movement::previous_subword_start(map, selection.head())
14887                        } else {
14888                            movement::previous_subword_start_or_newline(map, selection.head())
14889                        };
14890                        cursor = movement::adjust_greedy_deletion(
14891                            map,
14892                            selection.head(),
14893                            cursor,
14894                            action.ignore_brackets,
14895                        );
14896                        selection.set_head(cursor, SelectionGoal::None);
14897                    }
14898                });
14899            });
14900            this.insert("", window, cx);
14901        });
14902    }
14903
14904    pub fn move_to_next_word_end(
14905        &mut self,
14906        _: &MoveToNextWordEnd,
14907        window: &mut Window,
14908        cx: &mut Context<Self>,
14909    ) {
14910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14911        self.change_selections(Default::default(), window, cx, |s| {
14912            s.move_cursors_with(&mut |map, head, _| {
14913                (movement::next_word_end(map, head), SelectionGoal::None)
14914            });
14915        })
14916    }
14917
14918    pub fn move_to_next_subword_end(
14919        &mut self,
14920        _: &MoveToNextSubwordEnd,
14921        window: &mut Window,
14922        cx: &mut Context<Self>,
14923    ) {
14924        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14925        self.change_selections(Default::default(), window, cx, |s| {
14926            s.move_cursors_with(&mut |map, head, _| {
14927                (movement::next_subword_end(map, head), SelectionGoal::None)
14928            });
14929        })
14930    }
14931
14932    pub fn select_to_next_word_end(
14933        &mut self,
14934        _: &SelectToNextWordEnd,
14935        window: &mut Window,
14936        cx: &mut Context<Self>,
14937    ) {
14938        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14939        self.change_selections(Default::default(), window, cx, |s| {
14940            s.move_heads_with(&mut |map, head, _| {
14941                (movement::next_word_end(map, head), SelectionGoal::None)
14942            });
14943        })
14944    }
14945
14946    pub fn select_to_next_subword_end(
14947        &mut self,
14948        _: &SelectToNextSubwordEnd,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14953        self.change_selections(Default::default(), window, cx, |s| {
14954            s.move_heads_with(&mut |map, head, _| {
14955                (movement::next_subword_end(map, head), SelectionGoal::None)
14956            });
14957        })
14958    }
14959
14960    pub fn delete_to_next_word_end(
14961        &mut self,
14962        action: &DeleteToNextWordEnd,
14963        window: &mut Window,
14964        cx: &mut Context<Self>,
14965    ) {
14966        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14967        self.transact(window, cx, |this, window, cx| {
14968            this.change_selections(Default::default(), window, cx, |s| {
14969                s.move_with(&mut |map, selection| {
14970                    if selection.is_empty() {
14971                        let mut cursor = if action.ignore_newlines {
14972                            movement::next_word_end(map, selection.head())
14973                        } else {
14974                            movement::next_word_end_or_newline(map, selection.head())
14975                        };
14976                        cursor = movement::adjust_greedy_deletion(
14977                            map,
14978                            selection.head(),
14979                            cursor,
14980                            action.ignore_brackets,
14981                        );
14982                        selection.set_head(cursor, SelectionGoal::None);
14983                    }
14984                });
14985            });
14986            this.insert("", window, cx);
14987        });
14988    }
14989
14990    pub fn delete_to_next_subword_end(
14991        &mut self,
14992        action: &DeleteToNextSubwordEnd,
14993        window: &mut Window,
14994        cx: &mut Context<Self>,
14995    ) {
14996        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14997        self.transact(window, cx, |this, window, cx| {
14998            this.change_selections(Default::default(), window, cx, |s| {
14999                s.move_with(&mut |map, selection| {
15000                    if selection.is_empty() {
15001                        let mut cursor = if action.ignore_newlines {
15002                            movement::next_subword_end(map, selection.head())
15003                        } else {
15004                            movement::next_subword_end_or_newline(map, selection.head())
15005                        };
15006                        cursor = movement::adjust_greedy_deletion(
15007                            map,
15008                            selection.head(),
15009                            cursor,
15010                            action.ignore_brackets,
15011                        );
15012                        selection.set_head(cursor, SelectionGoal::None);
15013                    }
15014                });
15015            });
15016            this.insert("", window, cx);
15017        });
15018    }
15019
15020    pub fn move_to_beginning_of_line(
15021        &mut self,
15022        action: &MoveToBeginningOfLine,
15023        window: &mut Window,
15024        cx: &mut Context<Self>,
15025    ) {
15026        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15027        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15028        self.change_selections(Default::default(), window, cx, |s| {
15029            s.move_cursors_with(&mut |map, head, _| {
15030                (
15031                    movement::indented_line_beginning(
15032                        map,
15033                        head,
15034                        action.stop_at_soft_wraps,
15035                        stop_at_indent,
15036                    ),
15037                    SelectionGoal::None,
15038                )
15039            });
15040        })
15041    }
15042
15043    pub fn select_to_beginning_of_line(
15044        &mut self,
15045        action: &SelectToBeginningOfLine,
15046        window: &mut Window,
15047        cx: &mut Context<Self>,
15048    ) {
15049        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15050        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15051        self.change_selections(Default::default(), window, cx, |s| {
15052            s.move_heads_with(&mut |map, head, _| {
15053                (
15054                    movement::indented_line_beginning(
15055                        map,
15056                        head,
15057                        action.stop_at_soft_wraps,
15058                        stop_at_indent,
15059                    ),
15060                    SelectionGoal::None,
15061                )
15062            });
15063        });
15064    }
15065
15066    pub fn delete_to_beginning_of_line(
15067        &mut self,
15068        action: &DeleteToBeginningOfLine,
15069        window: &mut Window,
15070        cx: &mut Context<Self>,
15071    ) {
15072        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15073        self.transact(window, cx, |this, window, cx| {
15074            this.change_selections(Default::default(), window, cx, |s| {
15075                s.move_with(&mut |_, selection| {
15076                    selection.reversed = true;
15077                });
15078            });
15079
15080            this.select_to_beginning_of_line(
15081                &SelectToBeginningOfLine {
15082                    stop_at_soft_wraps: false,
15083                    stop_at_indent: action.stop_at_indent,
15084                },
15085                window,
15086                cx,
15087            );
15088            this.backspace(&Backspace, window, cx);
15089        });
15090    }
15091
15092    pub fn move_to_end_of_line(
15093        &mut self,
15094        action: &MoveToEndOfLine,
15095        window: &mut Window,
15096        cx: &mut Context<Self>,
15097    ) {
15098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15099        self.change_selections(Default::default(), window, cx, |s| {
15100            s.move_cursors_with(&mut |map, head, _| {
15101                (
15102                    movement::line_end(map, head, action.stop_at_soft_wraps),
15103                    SelectionGoal::None,
15104                )
15105            });
15106        })
15107    }
15108
15109    pub fn select_to_end_of_line(
15110        &mut self,
15111        action: &SelectToEndOfLine,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) {
15115        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15116        self.change_selections(Default::default(), window, cx, |s| {
15117            s.move_heads_with(&mut |map, head, _| {
15118                (
15119                    movement::line_end(map, head, action.stop_at_soft_wraps),
15120                    SelectionGoal::None,
15121                )
15122            });
15123        })
15124    }
15125
15126    pub fn delete_to_end_of_line(
15127        &mut self,
15128        _: &DeleteToEndOfLine,
15129        window: &mut Window,
15130        cx: &mut Context<Self>,
15131    ) {
15132        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15133        self.transact(window, cx, |this, window, cx| {
15134            this.select_to_end_of_line(
15135                &SelectToEndOfLine {
15136                    stop_at_soft_wraps: false,
15137                },
15138                window,
15139                cx,
15140            );
15141            this.delete(&Delete, window, cx);
15142        });
15143    }
15144
15145    pub fn cut_to_end_of_line(
15146        &mut self,
15147        action: &CutToEndOfLine,
15148        window: &mut Window,
15149        cx: &mut Context<Self>,
15150    ) {
15151        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15152        self.transact(window, cx, |this, window, cx| {
15153            this.select_to_end_of_line(
15154                &SelectToEndOfLine {
15155                    stop_at_soft_wraps: false,
15156                },
15157                window,
15158                cx,
15159            );
15160            if !action.stop_at_newlines {
15161                this.change_selections(Default::default(), window, cx, |s| {
15162                    s.move_with(&mut |_, sel| {
15163                        if sel.is_empty() {
15164                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15165                        }
15166                    });
15167                });
15168            }
15169            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15170            let item = this.cut_common(false, window, cx);
15171            cx.write_to_clipboard(item);
15172        });
15173    }
15174
15175    pub fn move_to_start_of_paragraph(
15176        &mut self,
15177        _: &MoveToStartOfParagraph,
15178        window: &mut Window,
15179        cx: &mut Context<Self>,
15180    ) {
15181        if matches!(self.mode, EditorMode::SingleLine) {
15182            cx.propagate();
15183            return;
15184        }
15185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15186        self.change_selections(Default::default(), window, cx, |s| {
15187            s.move_with(&mut |map, selection| {
15188                selection.collapse_to(
15189                    movement::start_of_paragraph(map, selection.head(), 1),
15190                    SelectionGoal::None,
15191                )
15192            });
15193        })
15194    }
15195
15196    pub fn move_to_end_of_paragraph(
15197        &mut self,
15198        _: &MoveToEndOfParagraph,
15199        window: &mut Window,
15200        cx: &mut Context<Self>,
15201    ) {
15202        if matches!(self.mode, EditorMode::SingleLine) {
15203            cx.propagate();
15204            return;
15205        }
15206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15207        self.change_selections(Default::default(), window, cx, |s| {
15208            s.move_with(&mut |map, selection| {
15209                selection.collapse_to(
15210                    movement::end_of_paragraph(map, selection.head(), 1),
15211                    SelectionGoal::None,
15212                )
15213            });
15214        })
15215    }
15216
15217    pub fn select_to_start_of_paragraph(
15218        &mut self,
15219        _: &SelectToStartOfParagraph,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) {
15223        if matches!(self.mode, EditorMode::SingleLine) {
15224            cx.propagate();
15225            return;
15226        }
15227        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15228        self.change_selections(Default::default(), window, cx, |s| {
15229            s.move_heads_with(&mut |map, head, _| {
15230                (
15231                    movement::start_of_paragraph(map, head, 1),
15232                    SelectionGoal::None,
15233                )
15234            });
15235        })
15236    }
15237
15238    pub fn select_to_end_of_paragraph(
15239        &mut self,
15240        _: &SelectToEndOfParagraph,
15241        window: &mut Window,
15242        cx: &mut Context<Self>,
15243    ) {
15244        if matches!(self.mode, EditorMode::SingleLine) {
15245            cx.propagate();
15246            return;
15247        }
15248        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15249        self.change_selections(Default::default(), window, cx, |s| {
15250            s.move_heads_with(&mut |map, head, _| {
15251                (
15252                    movement::end_of_paragraph(map, head, 1),
15253                    SelectionGoal::None,
15254                )
15255            });
15256        })
15257    }
15258
15259    pub fn move_to_start_of_excerpt(
15260        &mut self,
15261        _: &MoveToStartOfExcerpt,
15262        window: &mut Window,
15263        cx: &mut Context<Self>,
15264    ) {
15265        if matches!(self.mode, EditorMode::SingleLine) {
15266            cx.propagate();
15267            return;
15268        }
15269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15270        self.change_selections(Default::default(), window, cx, |s| {
15271            s.move_with(&mut |map, selection| {
15272                selection.collapse_to(
15273                    movement::start_of_excerpt(
15274                        map,
15275                        selection.head(),
15276                        workspace::searchable::Direction::Prev,
15277                    ),
15278                    SelectionGoal::None,
15279                )
15280            });
15281        })
15282    }
15283
15284    pub fn move_to_start_of_next_excerpt(
15285        &mut self,
15286        _: &MoveToStartOfNextExcerpt,
15287        window: &mut Window,
15288        cx: &mut Context<Self>,
15289    ) {
15290        if matches!(self.mode, EditorMode::SingleLine) {
15291            cx.propagate();
15292            return;
15293        }
15294
15295        self.change_selections(Default::default(), window, cx, |s| {
15296            s.move_with(&mut |map, selection| {
15297                selection.collapse_to(
15298                    movement::start_of_excerpt(
15299                        map,
15300                        selection.head(),
15301                        workspace::searchable::Direction::Next,
15302                    ),
15303                    SelectionGoal::None,
15304                )
15305            });
15306        })
15307    }
15308
15309    pub fn move_to_end_of_excerpt(
15310        &mut self,
15311        _: &MoveToEndOfExcerpt,
15312        window: &mut Window,
15313        cx: &mut Context<Self>,
15314    ) {
15315        if matches!(self.mode, EditorMode::SingleLine) {
15316            cx.propagate();
15317            return;
15318        }
15319        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15320        self.change_selections(Default::default(), window, cx, |s| {
15321            s.move_with(&mut |map, selection| {
15322                selection.collapse_to(
15323                    movement::end_of_excerpt(
15324                        map,
15325                        selection.head(),
15326                        workspace::searchable::Direction::Next,
15327                    ),
15328                    SelectionGoal::None,
15329                )
15330            });
15331        })
15332    }
15333
15334    pub fn move_to_end_of_previous_excerpt(
15335        &mut self,
15336        _: &MoveToEndOfPreviousExcerpt,
15337        window: &mut Window,
15338        cx: &mut Context<Self>,
15339    ) {
15340        if matches!(self.mode, EditorMode::SingleLine) {
15341            cx.propagate();
15342            return;
15343        }
15344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15345        self.change_selections(Default::default(), window, cx, |s| {
15346            s.move_with(&mut |map, selection| {
15347                selection.collapse_to(
15348                    movement::end_of_excerpt(
15349                        map,
15350                        selection.head(),
15351                        workspace::searchable::Direction::Prev,
15352                    ),
15353                    SelectionGoal::None,
15354                )
15355            });
15356        })
15357    }
15358
15359    pub fn select_to_start_of_excerpt(
15360        &mut self,
15361        _: &SelectToStartOfExcerpt,
15362        window: &mut Window,
15363        cx: &mut Context<Self>,
15364    ) {
15365        if matches!(self.mode, EditorMode::SingleLine) {
15366            cx.propagate();
15367            return;
15368        }
15369        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15370        self.change_selections(Default::default(), window, cx, |s| {
15371            s.move_heads_with(&mut |map, head, _| {
15372                (
15373                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15374                    SelectionGoal::None,
15375                )
15376            });
15377        })
15378    }
15379
15380    pub fn select_to_start_of_next_excerpt(
15381        &mut self,
15382        _: &SelectToStartOfNextExcerpt,
15383        window: &mut Window,
15384        cx: &mut Context<Self>,
15385    ) {
15386        if matches!(self.mode, EditorMode::SingleLine) {
15387            cx.propagate();
15388            return;
15389        }
15390        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15391        self.change_selections(Default::default(), window, cx, |s| {
15392            s.move_heads_with(&mut |map, head, _| {
15393                (
15394                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15395                    SelectionGoal::None,
15396                )
15397            });
15398        })
15399    }
15400
15401    pub fn select_to_end_of_excerpt(
15402        &mut self,
15403        _: &SelectToEndOfExcerpt,
15404        window: &mut Window,
15405        cx: &mut Context<Self>,
15406    ) {
15407        if matches!(self.mode, EditorMode::SingleLine) {
15408            cx.propagate();
15409            return;
15410        }
15411        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15412        self.change_selections(Default::default(), window, cx, |s| {
15413            s.move_heads_with(&mut |map, head, _| {
15414                (
15415                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15416                    SelectionGoal::None,
15417                )
15418            });
15419        })
15420    }
15421
15422    pub fn select_to_end_of_previous_excerpt(
15423        &mut self,
15424        _: &SelectToEndOfPreviousExcerpt,
15425        window: &mut Window,
15426        cx: &mut Context<Self>,
15427    ) {
15428        if matches!(self.mode, EditorMode::SingleLine) {
15429            cx.propagate();
15430            return;
15431        }
15432        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15433        self.change_selections(Default::default(), window, cx, |s| {
15434            s.move_heads_with(&mut |map, head, _| {
15435                (
15436                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15437                    SelectionGoal::None,
15438                )
15439            });
15440        })
15441    }
15442
15443    pub fn move_to_beginning(
15444        &mut self,
15445        _: &MoveToBeginning,
15446        window: &mut Window,
15447        cx: &mut Context<Self>,
15448    ) {
15449        if matches!(self.mode, EditorMode::SingleLine) {
15450            cx.propagate();
15451            return;
15452        }
15453        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15454        self.change_selections(Default::default(), window, cx, |s| {
15455            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
15456        });
15457    }
15458
15459    pub fn select_to_beginning(
15460        &mut self,
15461        _: &SelectToBeginning,
15462        window: &mut Window,
15463        cx: &mut Context<Self>,
15464    ) {
15465        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15466        selection.set_head(Point::zero(), SelectionGoal::None);
15467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15468        self.change_selections(Default::default(), window, cx, |s| {
15469            s.select(vec![selection]);
15470        });
15471    }
15472
15473    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15474        if matches!(self.mode, EditorMode::SingleLine) {
15475            cx.propagate();
15476            return;
15477        }
15478        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15479        let cursor = self.buffer.read(cx).read(cx).len();
15480        self.change_selections(Default::default(), window, cx, |s| {
15481            s.select_ranges(vec![cursor..cursor])
15482        });
15483    }
15484
15485    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15486        self.nav_history = nav_history;
15487    }
15488
15489    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15490        self.nav_history.as_ref()
15491    }
15492
15493    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15494        self.push_to_nav_history(
15495            self.selections.newest_anchor().head(),
15496            None,
15497            false,
15498            true,
15499            cx,
15500        );
15501    }
15502
15503    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15504        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15505        let buffer = self.buffer.read(cx).read(cx);
15506        let cursor_position = cursor_anchor.to_point(&buffer);
15507        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15508        let scroll_top_row = scroll_anchor.top_row(&buffer);
15509        drop(buffer);
15510
15511        NavigationData {
15512            cursor_anchor,
15513            cursor_position,
15514            scroll_anchor,
15515            scroll_top_row,
15516        }
15517    }
15518
15519    fn navigation_entry(
15520        &self,
15521        cursor_anchor: Anchor,
15522        cx: &mut Context<Self>,
15523    ) -> Option<NavigationEntry> {
15524        let Some(history) = self.nav_history.clone() else {
15525            return None;
15526        };
15527        let data = self.navigation_data(cursor_anchor, cx);
15528        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15529    }
15530
15531    fn push_to_nav_history(
15532        &mut self,
15533        cursor_anchor: Anchor,
15534        new_position: Option<Point>,
15535        is_deactivate: bool,
15536        always: bool,
15537        cx: &mut Context<Self>,
15538    ) {
15539        let data = self.navigation_data(cursor_anchor, cx);
15540        if let Some(nav_history) = self.nav_history.as_mut() {
15541            if let Some(new_position) = new_position {
15542                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15543                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15544                    return;
15545                }
15546            }
15547
15548            nav_history.push(Some(data), cx);
15549            cx.emit(EditorEvent::PushedToNavHistory {
15550                anchor: cursor_anchor,
15551                is_deactivate,
15552            })
15553        }
15554    }
15555
15556    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15557        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15558        let buffer = self.buffer.read(cx).snapshot(cx);
15559        let mut selection = self
15560            .selections
15561            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15562        selection.set_head(buffer.len(), SelectionGoal::None);
15563        self.change_selections(Default::default(), window, cx, |s| {
15564            s.select(vec![selection]);
15565        });
15566    }
15567
15568    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15570        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15571            s.select_ranges([Anchor::min()..Anchor::max()]);
15572        });
15573    }
15574
15575    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15576        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15577        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15578        let mut selections = self.selections.all::<Point>(&display_map);
15579        let max_point = display_map.buffer_snapshot().max_point();
15580        for selection in &mut selections {
15581            let rows = selection.spanned_rows(true, &display_map);
15582            selection.start = Point::new(rows.start.0, 0);
15583            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15584            selection.reversed = false;
15585        }
15586        self.change_selections(Default::default(), window, cx, |s| {
15587            s.select(selections);
15588        });
15589    }
15590
15591    pub fn split_selection_into_lines(
15592        &mut self,
15593        action: &SplitSelectionIntoLines,
15594        window: &mut Window,
15595        cx: &mut Context<Self>,
15596    ) {
15597        let selections = self
15598            .selections
15599            .all::<Point>(&self.display_snapshot(cx))
15600            .into_iter()
15601            .map(|selection| selection.start..selection.end)
15602            .collect::<Vec<_>>();
15603        self.unfold_ranges(&selections, true, false, cx);
15604
15605        let mut new_selection_ranges = Vec::new();
15606        {
15607            let buffer = self.buffer.read(cx).read(cx);
15608            for selection in selections {
15609                for row in selection.start.row..selection.end.row {
15610                    let line_start = Point::new(row, 0);
15611                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15612
15613                    if action.keep_selections {
15614                        // Keep the selection range for each line
15615                        let selection_start = if row == selection.start.row {
15616                            selection.start
15617                        } else {
15618                            line_start
15619                        };
15620                        new_selection_ranges.push(selection_start..line_end);
15621                    } else {
15622                        // Collapse to cursor at end of line
15623                        new_selection_ranges.push(line_end..line_end);
15624                    }
15625                }
15626
15627                let is_multiline_selection = selection.start.row != selection.end.row;
15628                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15629                // so this action feels more ergonomic when paired with other selection operations
15630                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15631                if !should_skip_last {
15632                    if action.keep_selections {
15633                        if is_multiline_selection {
15634                            let line_start = Point::new(selection.end.row, 0);
15635                            new_selection_ranges.push(line_start..selection.end);
15636                        } else {
15637                            new_selection_ranges.push(selection.start..selection.end);
15638                        }
15639                    } else {
15640                        new_selection_ranges.push(selection.end..selection.end);
15641                    }
15642                }
15643            }
15644        }
15645        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15646            s.select_ranges(new_selection_ranges);
15647        });
15648    }
15649
15650    pub fn add_selection_above(
15651        &mut self,
15652        action: &AddSelectionAbove,
15653        window: &mut Window,
15654        cx: &mut Context<Self>,
15655    ) {
15656        self.add_selection(true, action.skip_soft_wrap, window, cx);
15657    }
15658
15659    pub fn add_selection_below(
15660        &mut self,
15661        action: &AddSelectionBelow,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) {
15665        self.add_selection(false, action.skip_soft_wrap, window, cx);
15666    }
15667
15668    fn add_selection(
15669        &mut self,
15670        above: bool,
15671        skip_soft_wrap: bool,
15672        window: &mut Window,
15673        cx: &mut Context<Self>,
15674    ) {
15675        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15676
15677        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15678        let all_selections = self.selections.all::<Point>(&display_map);
15679        let text_layout_details = self.text_layout_details(window, cx);
15680
15681        let (mut columnar_selections, new_selections_to_columnarize) = {
15682            if let Some(state) = self.add_selections_state.as_ref() {
15683                let columnar_selection_ids: HashSet<_> = state
15684                    .groups
15685                    .iter()
15686                    .flat_map(|group| group.stack.iter())
15687                    .copied()
15688                    .collect();
15689
15690                all_selections
15691                    .into_iter()
15692                    .partition(|s| columnar_selection_ids.contains(&s.id))
15693            } else {
15694                (Vec::new(), all_selections)
15695            }
15696        };
15697
15698        let mut state = self
15699            .add_selections_state
15700            .take()
15701            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15702
15703        for selection in new_selections_to_columnarize {
15704            let range = selection.display_range(&display_map).sorted();
15705            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15706            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15707            let positions = start_x.min(end_x)..start_x.max(end_x);
15708            let mut stack = Vec::new();
15709            for row in range.start.row().0..=range.end.row().0 {
15710                if let Some(selection) = self.selections.build_columnar_selection(
15711                    &display_map,
15712                    DisplayRow(row),
15713                    &positions,
15714                    selection.reversed,
15715                    &text_layout_details,
15716                ) {
15717                    stack.push(selection.id);
15718                    columnar_selections.push(selection);
15719                }
15720            }
15721            if !stack.is_empty() {
15722                if above {
15723                    stack.reverse();
15724                }
15725                state.groups.push(AddSelectionsGroup { above, stack });
15726            }
15727        }
15728
15729        let mut final_selections = Vec::new();
15730        let end_row = if above {
15731            DisplayRow(0)
15732        } else {
15733            display_map.max_point().row()
15734        };
15735
15736        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15737        // positions to place new selections, so we need to keep track of the
15738        // column range of the oldest selection in each group, because
15739        // intermediate selections may have been clamped to shorter lines.
15740        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15741            let mut map = HashMap::default();
15742            for group in state.groups.iter() {
15743                if let Some(oldest_id) = group.stack.first() {
15744                    if let Some(oldest_selection) =
15745                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15746                    {
15747                        let snapshot = display_map.buffer_snapshot();
15748                        let start_col =
15749                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15750                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15751                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15752                        for id in &group.stack {
15753                            map.insert(*id, goal_columns.clone());
15754                        }
15755                    }
15756                }
15757            }
15758            map
15759        } else {
15760            HashMap::default()
15761        };
15762
15763        let mut last_added_item_per_group = HashMap::default();
15764        for group in state.groups.iter_mut() {
15765            if let Some(last_id) = group.stack.last() {
15766                last_added_item_per_group.insert(*last_id, group);
15767            }
15768        }
15769
15770        for selection in columnar_selections {
15771            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15772                if above == group.above {
15773                    let range = selection.display_range(&display_map).sorted();
15774                    debug_assert_eq!(range.start.row(), range.end.row());
15775                    let row = range.start.row();
15776                    let positions =
15777                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15778                            Pixels::from(start)..Pixels::from(end)
15779                        } else {
15780                            let start_x =
15781                                display_map.x_for_display_point(range.start, &text_layout_details);
15782                            let end_x =
15783                                display_map.x_for_display_point(range.end, &text_layout_details);
15784                            start_x.min(end_x)..start_x.max(end_x)
15785                        };
15786
15787                    let maybe_new_selection = if skip_soft_wrap {
15788                        let goal_columns = goal_columns_by_selection_id
15789                            .remove(&selection.id)
15790                            .unwrap_or_else(|| {
15791                                let snapshot = display_map.buffer_snapshot();
15792                                let start_col =
15793                                    snapshot.point_to_point_utf16(selection.start).column;
15794                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15795                                start_col.min(end_col)..start_col.max(end_col)
15796                            });
15797                        self.selections.find_next_columnar_selection_by_buffer_row(
15798                            &display_map,
15799                            row,
15800                            end_row,
15801                            above,
15802                            &goal_columns,
15803                            selection.reversed,
15804                            &text_layout_details,
15805                        )
15806                    } else {
15807                        self.selections.find_next_columnar_selection_by_display_row(
15808                            &display_map,
15809                            row,
15810                            end_row,
15811                            above,
15812                            &positions,
15813                            selection.reversed,
15814                            &text_layout_details,
15815                        )
15816                    };
15817
15818                    if let Some(new_selection) = maybe_new_selection {
15819                        group.stack.push(new_selection.id);
15820                        if above {
15821                            final_selections.push(new_selection);
15822                            final_selections.push(selection);
15823                        } else {
15824                            final_selections.push(selection);
15825                            final_selections.push(new_selection);
15826                        }
15827                    } else {
15828                        final_selections.push(selection);
15829                    }
15830                } else {
15831                    group.stack.pop();
15832                }
15833            } else {
15834                final_selections.push(selection);
15835            }
15836        }
15837
15838        self.change_selections(Default::default(), window, cx, |s| {
15839            s.select(final_selections);
15840        });
15841
15842        let final_selection_ids: HashSet<_> = self
15843            .selections
15844            .all::<Point>(&display_map)
15845            .iter()
15846            .map(|s| s.id)
15847            .collect();
15848        state.groups.retain_mut(|group| {
15849            // selections might get merged above so we remove invalid items from stacks
15850            group.stack.retain(|id| final_selection_ids.contains(id));
15851
15852            // single selection in stack can be treated as initial state
15853            group.stack.len() > 1
15854        });
15855
15856        if !state.groups.is_empty() {
15857            self.add_selections_state = Some(state);
15858        }
15859    }
15860
15861    pub fn insert_snippet_at_selections(
15862        &mut self,
15863        action: &InsertSnippet,
15864        window: &mut Window,
15865        cx: &mut Context<Self>,
15866    ) {
15867        self.try_insert_snippet_at_selections(action, window, cx)
15868            .log_err();
15869    }
15870
15871    fn try_insert_snippet_at_selections(
15872        &mut self,
15873        action: &InsertSnippet,
15874        window: &mut Window,
15875        cx: &mut Context<Self>,
15876    ) -> Result<()> {
15877        let insertion_ranges = self
15878            .selections
15879            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15880            .into_iter()
15881            .map(|selection| selection.range())
15882            .collect_vec();
15883
15884        let snippet = if let Some(snippet_body) = &action.snippet {
15885            if action.language.is_none() && action.name.is_none() {
15886                Snippet::parse(snippet_body)?
15887            } else {
15888                bail!("`snippet` is mutually exclusive with `language` and `name`")
15889            }
15890        } else if let Some(name) = &action.name {
15891            let project = self.project().context("no project")?;
15892            let snippet_store = project.read(cx).snippets().read(cx);
15893            let snippet = snippet_store
15894                .snippets_for(action.language.clone(), cx)
15895                .into_iter()
15896                .find(|snippet| snippet.name == *name)
15897                .context("snippet not found")?;
15898            Snippet::parse(&snippet.body)?
15899        } else {
15900            // todo(andrew): open modal to select snippet
15901            bail!("`name` or `snippet` is required")
15902        };
15903
15904        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15905    }
15906
15907    fn select_match_ranges(
15908        &mut self,
15909        range: Range<MultiBufferOffset>,
15910        reversed: bool,
15911        replace_newest: bool,
15912        auto_scroll: Option<Autoscroll>,
15913        window: &mut Window,
15914        cx: &mut Context<Editor>,
15915    ) {
15916        self.unfold_ranges(
15917            std::slice::from_ref(&range),
15918            false,
15919            auto_scroll.is_some(),
15920            cx,
15921        );
15922        let effects = if let Some(scroll) = auto_scroll {
15923            SelectionEffects::scroll(scroll)
15924        } else {
15925            SelectionEffects::no_scroll()
15926        };
15927        self.change_selections(effects, window, cx, |s| {
15928            if replace_newest {
15929                s.delete(s.newest_anchor().id);
15930            }
15931            if reversed {
15932                s.insert_range(range.end..range.start);
15933            } else {
15934                s.insert_range(range);
15935            }
15936        });
15937    }
15938
15939    pub fn select_next_match_internal(
15940        &mut self,
15941        display_map: &DisplaySnapshot,
15942        replace_newest: bool,
15943        autoscroll: Option<Autoscroll>,
15944        window: &mut Window,
15945        cx: &mut Context<Self>,
15946    ) -> Result<()> {
15947        let buffer = display_map.buffer_snapshot();
15948        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15949        if let Some(mut select_next_state) = self.select_next_state.take() {
15950            let query = &select_next_state.query;
15951            if !select_next_state.done {
15952                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15953                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15954                let mut next_selected_range = None;
15955
15956                let bytes_after_last_selection =
15957                    buffer.bytes_in_range(last_selection.end..buffer.len());
15958                let bytes_before_first_selection =
15959                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15960                let query_matches = query
15961                    .stream_find_iter(bytes_after_last_selection)
15962                    .map(|result| (last_selection.end, result))
15963                    .chain(
15964                        query
15965                            .stream_find_iter(bytes_before_first_selection)
15966                            .map(|result| (MultiBufferOffset(0), result)),
15967                    );
15968
15969                for (start_offset, query_match) in query_matches {
15970                    let query_match = query_match.unwrap(); // can only fail due to I/O
15971                    let offset_range =
15972                        start_offset + query_match.start()..start_offset + query_match.end();
15973
15974                    if !select_next_state.wordwise
15975                        || (!buffer.is_inside_word(offset_range.start, None)
15976                            && !buffer.is_inside_word(offset_range.end, None))
15977                    {
15978                        let idx = selections
15979                            .partition_point(|selection| selection.end <= offset_range.start);
15980                        let overlaps = selections
15981                            .get(idx)
15982                            .map_or(false, |selection| selection.start < offset_range.end);
15983
15984                        if !overlaps {
15985                            next_selected_range = Some(offset_range);
15986                            break;
15987                        }
15988                    }
15989                }
15990
15991                if let Some(next_selected_range) = next_selected_range {
15992                    self.select_match_ranges(
15993                        next_selected_range,
15994                        last_selection.reversed,
15995                        replace_newest,
15996                        autoscroll,
15997                        window,
15998                        cx,
15999                    );
16000                } else {
16001                    select_next_state.done = true;
16002                }
16003            }
16004
16005            self.select_next_state = Some(select_next_state);
16006        } else {
16007            let mut only_carets = true;
16008            let mut same_text_selected = true;
16009            let mut selected_text = None;
16010
16011            let mut selections_iter = selections.iter().peekable();
16012            while let Some(selection) = selections_iter.next() {
16013                if selection.start != selection.end {
16014                    only_carets = false;
16015                }
16016
16017                if same_text_selected {
16018                    if selected_text.is_none() {
16019                        selected_text =
16020                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16021                    }
16022
16023                    if let Some(next_selection) = selections_iter.peek() {
16024                        if next_selection.len() == selection.len() {
16025                            let next_selected_text = buffer
16026                                .text_for_range(next_selection.range())
16027                                .collect::<String>();
16028                            if Some(next_selected_text) != selected_text {
16029                                same_text_selected = false;
16030                                selected_text = None;
16031                            }
16032                        } else {
16033                            same_text_selected = false;
16034                            selected_text = None;
16035                        }
16036                    }
16037                }
16038            }
16039
16040            if only_carets {
16041                for selection in &mut selections {
16042                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16043                    selection.start = word_range.start;
16044                    selection.end = word_range.end;
16045                    selection.goal = SelectionGoal::None;
16046                    selection.reversed = false;
16047                    self.select_match_ranges(
16048                        selection.start..selection.end,
16049                        selection.reversed,
16050                        replace_newest,
16051                        autoscroll,
16052                        window,
16053                        cx,
16054                    );
16055                }
16056
16057                if selections.len() == 1 {
16058                    let selection = selections
16059                        .last()
16060                        .expect("ensured that there's only one selection");
16061                    let query = buffer
16062                        .text_for_range(selection.start..selection.end)
16063                        .collect::<String>();
16064                    let is_empty = query.is_empty();
16065                    let select_state = SelectNextState {
16066                        query: self.build_query(&[query], cx)?,
16067                        wordwise: true,
16068                        done: is_empty,
16069                    };
16070                    self.select_next_state = Some(select_state);
16071                } else {
16072                    self.select_next_state = None;
16073                }
16074            } else if let Some(selected_text) = selected_text {
16075                self.select_next_state = Some(SelectNextState {
16076                    query: self.build_query(&[selected_text], cx)?,
16077                    wordwise: false,
16078                    done: false,
16079                });
16080                self.select_next_match_internal(
16081                    display_map,
16082                    replace_newest,
16083                    autoscroll,
16084                    window,
16085                    cx,
16086                )?;
16087            }
16088        }
16089        Ok(())
16090    }
16091
16092    pub fn select_all_matches(
16093        &mut self,
16094        _action: &SelectAllMatches,
16095        window: &mut Window,
16096        cx: &mut Context<Self>,
16097    ) -> Result<()> {
16098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16099
16100        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16101
16102        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16103        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16104        else {
16105            return Ok(());
16106        };
16107
16108        let mut new_selections = Vec::new();
16109
16110        let reversed = self
16111            .selections
16112            .oldest::<MultiBufferOffset>(&display_map)
16113            .reversed;
16114        let buffer = display_map.buffer_snapshot();
16115        let query_matches = select_next_state
16116            .query
16117            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16118
16119        for query_match in query_matches.into_iter() {
16120            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16121            let offset_range = if reversed {
16122                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16123            } else {
16124                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16125            };
16126
16127            if !select_next_state.wordwise
16128                || (!buffer.is_inside_word(offset_range.start, None)
16129                    && !buffer.is_inside_word(offset_range.end, None))
16130            {
16131                new_selections.push(offset_range.start..offset_range.end);
16132            }
16133        }
16134
16135        select_next_state.done = true;
16136
16137        if new_selections.is_empty() {
16138            log::error!("bug: new_selections is empty in select_all_matches");
16139            return Ok(());
16140        }
16141
16142        self.unfold_ranges(&new_selections, false, false, cx);
16143        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16144            selections.select_ranges(new_selections)
16145        });
16146
16147        Ok(())
16148    }
16149
16150    pub fn select_next(
16151        &mut self,
16152        action: &SelectNext,
16153        window: &mut Window,
16154        cx: &mut Context<Self>,
16155    ) -> Result<()> {
16156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16157        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16158        self.select_next_match_internal(
16159            &display_map,
16160            action.replace_newest,
16161            Some(Autoscroll::newest()),
16162            window,
16163            cx,
16164        )
16165    }
16166
16167    pub fn select_previous(
16168        &mut self,
16169        action: &SelectPrevious,
16170        window: &mut Window,
16171        cx: &mut Context<Self>,
16172    ) -> Result<()> {
16173        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16174        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16175        let buffer = display_map.buffer_snapshot();
16176        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16177        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16178            let query = &select_prev_state.query;
16179            if !select_prev_state.done {
16180                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16181                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16182                let mut next_selected_range = None;
16183                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16184                let bytes_before_last_selection =
16185                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16186                let bytes_after_first_selection =
16187                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16188                let query_matches = query
16189                    .stream_find_iter(bytes_before_last_selection)
16190                    .map(|result| (last_selection.start, result))
16191                    .chain(
16192                        query
16193                            .stream_find_iter(bytes_after_first_selection)
16194                            .map(|result| (buffer.len(), result)),
16195                    );
16196                for (end_offset, query_match) in query_matches {
16197                    let query_match = query_match.unwrap(); // can only fail due to I/O
16198                    let offset_range =
16199                        end_offset - query_match.end()..end_offset - query_match.start();
16200
16201                    if !select_prev_state.wordwise
16202                        || (!buffer.is_inside_word(offset_range.start, None)
16203                            && !buffer.is_inside_word(offset_range.end, None))
16204                    {
16205                        next_selected_range = Some(offset_range);
16206                        break;
16207                    }
16208                }
16209
16210                if let Some(next_selected_range) = next_selected_range {
16211                    self.select_match_ranges(
16212                        next_selected_range,
16213                        last_selection.reversed,
16214                        action.replace_newest,
16215                        Some(Autoscroll::newest()),
16216                        window,
16217                        cx,
16218                    );
16219                } else {
16220                    select_prev_state.done = true;
16221                }
16222            }
16223
16224            self.select_prev_state = Some(select_prev_state);
16225        } else {
16226            let mut only_carets = true;
16227            let mut same_text_selected = true;
16228            let mut selected_text = None;
16229
16230            let mut selections_iter = selections.iter().peekable();
16231            while let Some(selection) = selections_iter.next() {
16232                if selection.start != selection.end {
16233                    only_carets = false;
16234                }
16235
16236                if same_text_selected {
16237                    if selected_text.is_none() {
16238                        selected_text =
16239                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16240                    }
16241
16242                    if let Some(next_selection) = selections_iter.peek() {
16243                        if next_selection.len() == selection.len() {
16244                            let next_selected_text = buffer
16245                                .text_for_range(next_selection.range())
16246                                .collect::<String>();
16247                            if Some(next_selected_text) != selected_text {
16248                                same_text_selected = false;
16249                                selected_text = None;
16250                            }
16251                        } else {
16252                            same_text_selected = false;
16253                            selected_text = None;
16254                        }
16255                    }
16256                }
16257            }
16258
16259            if only_carets {
16260                for selection in &mut selections {
16261                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16262                    selection.start = word_range.start;
16263                    selection.end = word_range.end;
16264                    selection.goal = SelectionGoal::None;
16265                    selection.reversed = false;
16266                    self.select_match_ranges(
16267                        selection.start..selection.end,
16268                        selection.reversed,
16269                        action.replace_newest,
16270                        Some(Autoscroll::newest()),
16271                        window,
16272                        cx,
16273                    );
16274                }
16275                if selections.len() == 1 {
16276                    let selection = selections
16277                        .last()
16278                        .expect("ensured that there's only one selection");
16279                    let query = buffer
16280                        .text_for_range(selection.start..selection.end)
16281                        .collect::<String>();
16282                    let is_empty = query.is_empty();
16283                    let select_state = SelectNextState {
16284                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16285                        wordwise: true,
16286                        done: is_empty,
16287                    };
16288                    self.select_prev_state = Some(select_state);
16289                } else {
16290                    self.select_prev_state = None;
16291                }
16292            } else if let Some(selected_text) = selected_text {
16293                self.select_prev_state = Some(SelectNextState {
16294                    query: self
16295                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16296                    wordwise: false,
16297                    done: false,
16298                });
16299                self.select_previous(action, window, cx)?;
16300            }
16301        }
16302        Ok(())
16303    }
16304
16305    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16306    /// setting the case sensitivity based on the global
16307    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16308    /// editor's settings.
16309    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16310    where
16311        I: IntoIterator<Item = P>,
16312        P: AsRef<[u8]>,
16313    {
16314        let case_sensitive = self
16315            .select_next_is_case_sensitive
16316            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16317
16318        let mut builder = AhoCorasickBuilder::new();
16319        builder.ascii_case_insensitive(!case_sensitive);
16320        builder.build(patterns)
16321    }
16322
16323    pub fn find_next_match(
16324        &mut self,
16325        _: &FindNextMatch,
16326        window: &mut Window,
16327        cx: &mut Context<Self>,
16328    ) -> Result<()> {
16329        let selections = self.selections.disjoint_anchors_arc();
16330        match selections.first() {
16331            Some(first) if selections.len() >= 2 => {
16332                self.change_selections(Default::default(), window, cx, |s| {
16333                    s.select_ranges([first.range()]);
16334                });
16335            }
16336            _ => self.select_next(
16337                &SelectNext {
16338                    replace_newest: true,
16339                },
16340                window,
16341                cx,
16342            )?,
16343        }
16344        Ok(())
16345    }
16346
16347    pub fn find_previous_match(
16348        &mut self,
16349        _: &FindPreviousMatch,
16350        window: &mut Window,
16351        cx: &mut Context<Self>,
16352    ) -> Result<()> {
16353        let selections = self.selections.disjoint_anchors_arc();
16354        match selections.last() {
16355            Some(last) if selections.len() >= 2 => {
16356                self.change_selections(Default::default(), window, cx, |s| {
16357                    s.select_ranges([last.range()]);
16358                });
16359            }
16360            _ => self.select_previous(
16361                &SelectPrevious {
16362                    replace_newest: true,
16363                },
16364                window,
16365                cx,
16366            )?,
16367        }
16368        Ok(())
16369    }
16370
16371    pub fn toggle_comments(
16372        &mut self,
16373        action: &ToggleComments,
16374        window: &mut Window,
16375        cx: &mut Context<Self>,
16376    ) {
16377        if self.read_only(cx) {
16378            return;
16379        }
16380        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16381        let text_layout_details = &self.text_layout_details(window, cx);
16382        self.transact(window, cx, |this, window, cx| {
16383            let mut selections = this
16384                .selections
16385                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16386            let mut edits = Vec::new();
16387            let mut selection_edit_ranges = Vec::new();
16388            let mut last_toggled_row = None;
16389            let snapshot = this.buffer.read(cx).read(cx);
16390            let empty_str: Arc<str> = Arc::default();
16391            let mut suffixes_inserted = Vec::new();
16392            let ignore_indent = action.ignore_indent;
16393
16394            fn comment_prefix_range(
16395                snapshot: &MultiBufferSnapshot,
16396                row: MultiBufferRow,
16397                comment_prefix: &str,
16398                comment_prefix_whitespace: &str,
16399                ignore_indent: bool,
16400            ) -> Range<Point> {
16401                let indent_size = if ignore_indent {
16402                    0
16403                } else {
16404                    snapshot.indent_size_for_line(row).len
16405                };
16406
16407                let start = Point::new(row.0, indent_size);
16408
16409                let mut line_bytes = snapshot
16410                    .bytes_in_range(start..snapshot.max_point())
16411                    .flatten()
16412                    .copied();
16413
16414                // If this line currently begins with the line comment prefix, then record
16415                // the range containing the prefix.
16416                if line_bytes
16417                    .by_ref()
16418                    .take(comment_prefix.len())
16419                    .eq(comment_prefix.bytes())
16420                {
16421                    // Include any whitespace that matches the comment prefix.
16422                    let matching_whitespace_len = line_bytes
16423                        .zip(comment_prefix_whitespace.bytes())
16424                        .take_while(|(a, b)| a == b)
16425                        .count() as u32;
16426                    let end = Point::new(
16427                        start.row,
16428                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16429                    );
16430                    start..end
16431                } else {
16432                    start..start
16433                }
16434            }
16435
16436            fn comment_suffix_range(
16437                snapshot: &MultiBufferSnapshot,
16438                row: MultiBufferRow,
16439                comment_suffix: &str,
16440                comment_suffix_has_leading_space: bool,
16441            ) -> Range<Point> {
16442                let end = Point::new(row.0, snapshot.line_len(row));
16443                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16444
16445                let mut line_end_bytes = snapshot
16446                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16447                    .flatten()
16448                    .copied();
16449
16450                let leading_space_len = if suffix_start_column > 0
16451                    && line_end_bytes.next() == Some(b' ')
16452                    && comment_suffix_has_leading_space
16453                {
16454                    1
16455                } else {
16456                    0
16457                };
16458
16459                // If this line currently begins with the line comment prefix, then record
16460                // the range containing the prefix.
16461                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16462                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16463                    start..end
16464                } else {
16465                    end..end
16466                }
16467            }
16468
16469            // TODO: Handle selections that cross excerpts
16470            for selection in &mut selections {
16471                let start_column = snapshot
16472                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16473                    .len;
16474                let language = if let Some(language) =
16475                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16476                {
16477                    language
16478                } else {
16479                    continue;
16480                };
16481
16482                selection_edit_ranges.clear();
16483
16484                // If multiple selections contain a given row, avoid processing that
16485                // row more than once.
16486                let mut start_row = MultiBufferRow(selection.start.row);
16487                if last_toggled_row == Some(start_row) {
16488                    start_row = start_row.next_row();
16489                }
16490                let end_row =
16491                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16492                        MultiBufferRow(selection.end.row - 1)
16493                    } else {
16494                        MultiBufferRow(selection.end.row)
16495                    };
16496                last_toggled_row = Some(end_row);
16497
16498                if start_row > end_row {
16499                    continue;
16500                }
16501
16502                // If the language has line comments, toggle those.
16503                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16504
16505                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16506                if ignore_indent {
16507                    full_comment_prefixes = full_comment_prefixes
16508                        .into_iter()
16509                        .map(|s| Arc::from(s.trim_end()))
16510                        .collect();
16511                }
16512
16513                if !full_comment_prefixes.is_empty() {
16514                    let first_prefix = full_comment_prefixes
16515                        .first()
16516                        .expect("prefixes is non-empty");
16517                    let prefix_trimmed_lengths = full_comment_prefixes
16518                        .iter()
16519                        .map(|p| p.trim_end_matches(' ').len())
16520                        .collect::<SmallVec<[usize; 4]>>();
16521
16522                    let mut all_selection_lines_are_comments = true;
16523
16524                    for row in start_row.0..=end_row.0 {
16525                        let row = MultiBufferRow(row);
16526                        if start_row < end_row && snapshot.is_line_blank(row) {
16527                            continue;
16528                        }
16529
16530                        let prefix_range = full_comment_prefixes
16531                            .iter()
16532                            .zip(prefix_trimmed_lengths.iter().copied())
16533                            .map(|(prefix, trimmed_prefix_len)| {
16534                                comment_prefix_range(
16535                                    snapshot.deref(),
16536                                    row,
16537                                    &prefix[..trimmed_prefix_len],
16538                                    &prefix[trimmed_prefix_len..],
16539                                    ignore_indent,
16540                                )
16541                            })
16542                            .max_by_key(|range| range.end.column - range.start.column)
16543                            .expect("prefixes is non-empty");
16544
16545                        if prefix_range.is_empty() {
16546                            all_selection_lines_are_comments = false;
16547                        }
16548
16549                        selection_edit_ranges.push(prefix_range);
16550                    }
16551
16552                    if all_selection_lines_are_comments {
16553                        edits.extend(
16554                            selection_edit_ranges
16555                                .iter()
16556                                .cloned()
16557                                .map(|range| (range, empty_str.clone())),
16558                        );
16559                    } else {
16560                        let min_column = selection_edit_ranges
16561                            .iter()
16562                            .map(|range| range.start.column)
16563                            .min()
16564                            .unwrap_or(0);
16565                        edits.extend(selection_edit_ranges.iter().map(|range| {
16566                            let position = Point::new(range.start.row, min_column);
16567                            (position..position, first_prefix.clone())
16568                        }));
16569                    }
16570                } else if let Some(BlockCommentConfig {
16571                    start: full_comment_prefix,
16572                    end: comment_suffix,
16573                    ..
16574                }) = language.block_comment()
16575                {
16576                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16577                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16578                    let prefix_range = comment_prefix_range(
16579                        snapshot.deref(),
16580                        start_row,
16581                        comment_prefix,
16582                        comment_prefix_whitespace,
16583                        ignore_indent,
16584                    );
16585                    let suffix_range = comment_suffix_range(
16586                        snapshot.deref(),
16587                        end_row,
16588                        comment_suffix.trim_start_matches(' '),
16589                        comment_suffix.starts_with(' '),
16590                    );
16591
16592                    if prefix_range.is_empty() || suffix_range.is_empty() {
16593                        edits.push((
16594                            prefix_range.start..prefix_range.start,
16595                            full_comment_prefix.clone(),
16596                        ));
16597                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16598                        suffixes_inserted.push((end_row, comment_suffix.len()));
16599                    } else {
16600                        edits.push((prefix_range, empty_str.clone()));
16601                        edits.push((suffix_range, empty_str.clone()));
16602                    }
16603                } else {
16604                    continue;
16605                }
16606            }
16607
16608            drop(snapshot);
16609            this.buffer.update(cx, |buffer, cx| {
16610                buffer.edit(edits, None, cx);
16611            });
16612
16613            // Adjust selections so that they end before any comment suffixes that
16614            // were inserted.
16615            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16616            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16617            let snapshot = this.buffer.read(cx).read(cx);
16618            for selection in &mut selections {
16619                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16620                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16621                        Ordering::Less => {
16622                            suffixes_inserted.next();
16623                            continue;
16624                        }
16625                        Ordering::Greater => break,
16626                        Ordering::Equal => {
16627                            if selection.end.column == snapshot.line_len(row) {
16628                                if selection.is_empty() {
16629                                    selection.start.column -= suffix_len as u32;
16630                                }
16631                                selection.end.column -= suffix_len as u32;
16632                            }
16633                            break;
16634                        }
16635                    }
16636                }
16637            }
16638
16639            drop(snapshot);
16640            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16641
16642            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16643            let selections_on_single_row = selections.windows(2).all(|selections| {
16644                selections[0].start.row == selections[1].start.row
16645                    && selections[0].end.row == selections[1].end.row
16646                    && selections[0].start.row == selections[0].end.row
16647            });
16648            let selections_selecting = selections
16649                .iter()
16650                .any(|selection| selection.start != selection.end);
16651            let advance_downwards = action.advance_downwards
16652                && selections_on_single_row
16653                && !selections_selecting
16654                && !matches!(this.mode, EditorMode::SingleLine);
16655
16656            if advance_downwards {
16657                let snapshot = this.buffer.read(cx).snapshot(cx);
16658
16659                this.change_selections(Default::default(), window, cx, |s| {
16660                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16661                        let mut point = display_point.to_point(display_snapshot);
16662                        point.row += 1;
16663                        point = snapshot.clip_point(point, Bias::Left);
16664                        let display_point = point.to_display_point(display_snapshot);
16665                        let goal = SelectionGoal::HorizontalPosition(
16666                            display_snapshot
16667                                .x_for_display_point(display_point, text_layout_details)
16668                                .into(),
16669                        );
16670                        (display_point, goal)
16671                    })
16672                });
16673            }
16674        });
16675    }
16676
16677    pub fn select_enclosing_symbol(
16678        &mut self,
16679        _: &SelectEnclosingSymbol,
16680        window: &mut Window,
16681        cx: &mut Context<Self>,
16682    ) {
16683        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16684
16685        let buffer = self.buffer.read(cx).snapshot(cx);
16686        let old_selections = self
16687            .selections
16688            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16689            .into_boxed_slice();
16690
16691        fn update_selection(
16692            selection: &Selection<MultiBufferOffset>,
16693            buffer_snap: &MultiBufferSnapshot,
16694        ) -> Option<Selection<MultiBufferOffset>> {
16695            let cursor = selection.head();
16696            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16697            for symbol in symbols.iter().rev() {
16698                let start = symbol.range.start.to_offset(buffer_snap);
16699                let end = symbol.range.end.to_offset(buffer_snap);
16700                let new_range = start..end;
16701                if start < selection.start || end > selection.end {
16702                    return Some(Selection {
16703                        id: selection.id,
16704                        start: new_range.start,
16705                        end: new_range.end,
16706                        goal: SelectionGoal::None,
16707                        reversed: selection.reversed,
16708                    });
16709                }
16710            }
16711            None
16712        }
16713
16714        let mut selected_larger_symbol = false;
16715        let new_selections = old_selections
16716            .iter()
16717            .map(|selection| match update_selection(selection, &buffer) {
16718                Some(new_selection) => {
16719                    if new_selection.range() != selection.range() {
16720                        selected_larger_symbol = true;
16721                    }
16722                    new_selection
16723                }
16724                None => selection.clone(),
16725            })
16726            .collect::<Vec<_>>();
16727
16728        if selected_larger_symbol {
16729            self.change_selections(Default::default(), window, cx, |s| {
16730                s.select(new_selections);
16731            });
16732        }
16733    }
16734
16735    pub fn select_larger_syntax_node(
16736        &mut self,
16737        _: &SelectLargerSyntaxNode,
16738        window: &mut Window,
16739        cx: &mut Context<Self>,
16740    ) {
16741        let Some(visible_row_count) = self.visible_row_count() else {
16742            return;
16743        };
16744        let old_selections: Box<[_]> = self
16745            .selections
16746            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16747            .into();
16748        if old_selections.is_empty() {
16749            return;
16750        }
16751
16752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16753
16754        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16755        let buffer = self.buffer.read(cx).snapshot(cx);
16756
16757        let mut selected_larger_node = false;
16758        let mut new_selections = old_selections
16759            .iter()
16760            .map(|selection| {
16761                let old_range = selection.start..selection.end;
16762
16763                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16764                    // manually select word at selection
16765                    if ["string_content", "inline"].contains(&node.kind()) {
16766                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16767                        // ignore if word is already selected
16768                        if !word_range.is_empty() && old_range != word_range {
16769                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16770                            // only select word if start and end point belongs to same word
16771                            if word_range == last_word_range {
16772                                selected_larger_node = true;
16773                                return Selection {
16774                                    id: selection.id,
16775                                    start: word_range.start,
16776                                    end: word_range.end,
16777                                    goal: SelectionGoal::None,
16778                                    reversed: selection.reversed,
16779                                };
16780                            }
16781                        }
16782                    }
16783                }
16784
16785                let mut new_range = old_range.clone();
16786                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16787                    new_range = range;
16788                    if !node.is_named() {
16789                        continue;
16790                    }
16791                    if !display_map.intersects_fold(new_range.start)
16792                        && !display_map.intersects_fold(new_range.end)
16793                    {
16794                        break;
16795                    }
16796                }
16797
16798                selected_larger_node |= new_range != old_range;
16799                Selection {
16800                    id: selection.id,
16801                    start: new_range.start,
16802                    end: new_range.end,
16803                    goal: SelectionGoal::None,
16804                    reversed: selection.reversed,
16805                }
16806            })
16807            .collect::<Vec<_>>();
16808
16809        if !selected_larger_node {
16810            return; // don't put this call in the history
16811        }
16812
16813        // scroll based on transformation done to the last selection created by the user
16814        let (last_old, last_new) = old_selections
16815            .last()
16816            .zip(new_selections.last().cloned())
16817            .expect("old_selections isn't empty");
16818
16819        let is_selection_reversed = if new_selections.len() == 1 {
16820            let should_be_reversed = last_old.start != last_new.start;
16821            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
16822            should_be_reversed
16823        } else {
16824            last_new.reversed
16825        };
16826
16827        if selected_larger_node {
16828            self.select_syntax_node_history.disable_clearing = true;
16829            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16830                s.select(new_selections.clone());
16831            });
16832            self.select_syntax_node_history.disable_clearing = false;
16833        }
16834
16835        let start_row = last_new.start.to_display_point(&display_map).row().0;
16836        let end_row = last_new.end.to_display_point(&display_map).row().0;
16837        let selection_height = end_row - start_row + 1;
16838        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16839
16840        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16841        let scroll_behavior = if fits_on_the_screen {
16842            self.request_autoscroll(Autoscroll::fit(), cx);
16843            SelectSyntaxNodeScrollBehavior::FitSelection
16844        } else if is_selection_reversed {
16845            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16846            SelectSyntaxNodeScrollBehavior::CursorTop
16847        } else {
16848            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16849            SelectSyntaxNodeScrollBehavior::CursorBottom
16850        };
16851
16852        let old_selections: Box<[Selection<Anchor>]> = old_selections
16853            .iter()
16854            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16855            .collect();
16856        self.select_syntax_node_history.push((
16857            old_selections,
16858            scroll_behavior,
16859            is_selection_reversed,
16860        ));
16861    }
16862
16863    pub fn select_smaller_syntax_node(
16864        &mut self,
16865        _: &SelectSmallerSyntaxNode,
16866        window: &mut Window,
16867        cx: &mut Context<Self>,
16868    ) {
16869        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16870
16871        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16872            self.select_syntax_node_history.pop()
16873        {
16874            if let Some(selection) = selections.last_mut() {
16875                selection.reversed = is_selection_reversed;
16876            }
16877
16878            let snapshot = self.buffer.read(cx).snapshot(cx);
16879            let selections: Vec<Selection<MultiBufferOffset>> = selections
16880                .iter()
16881                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16882                .collect();
16883
16884            self.select_syntax_node_history.disable_clearing = true;
16885            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16886                s.select(selections);
16887            });
16888            self.select_syntax_node_history.disable_clearing = false;
16889
16890            match scroll_behavior {
16891                SelectSyntaxNodeScrollBehavior::CursorTop => {
16892                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16893                }
16894                SelectSyntaxNodeScrollBehavior::FitSelection => {
16895                    self.request_autoscroll(Autoscroll::fit(), cx);
16896                }
16897                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16898                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16899                }
16900            }
16901        }
16902    }
16903
16904    pub fn unwrap_syntax_node(
16905        &mut self,
16906        _: &UnwrapSyntaxNode,
16907        window: &mut Window,
16908        cx: &mut Context<Self>,
16909    ) {
16910        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16911
16912        let buffer = self.buffer.read(cx).snapshot(cx);
16913        let selections = self
16914            .selections
16915            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16916            .into_iter()
16917            // subtracting the offset requires sorting
16918            .sorted_by_key(|i| i.start);
16919
16920        let full_edits = selections
16921            .into_iter()
16922            .filter_map(|selection| {
16923                let child = if selection.is_empty()
16924                    && let Some((_, ancestor_range)) =
16925                        buffer.syntax_ancestor(selection.start..selection.end)
16926                {
16927                    ancestor_range
16928                } else {
16929                    selection.range()
16930                };
16931
16932                let mut parent = child.clone();
16933                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16934                    parent = ancestor_range;
16935                    if parent.start < child.start || parent.end > child.end {
16936                        break;
16937                    }
16938                }
16939
16940                if parent == child {
16941                    return None;
16942                }
16943                let text = buffer.text_for_range(child).collect::<String>();
16944                Some((selection.id, parent, text))
16945            })
16946            .collect::<Vec<_>>();
16947        if full_edits.is_empty() {
16948            return;
16949        }
16950
16951        self.transact(window, cx, |this, window, cx| {
16952            this.buffer.update(cx, |buffer, cx| {
16953                buffer.edit(
16954                    full_edits
16955                        .iter()
16956                        .map(|(_, p, t)| (p.clone(), t.clone()))
16957                        .collect::<Vec<_>>(),
16958                    None,
16959                    cx,
16960                );
16961            });
16962            this.change_selections(Default::default(), window, cx, |s| {
16963                let mut offset = 0;
16964                let mut selections = vec![];
16965                for (id, parent, text) in full_edits {
16966                    let start = parent.start - offset;
16967                    offset += (parent.end - parent.start) - text.len();
16968                    selections.push(Selection {
16969                        id,
16970                        start,
16971                        end: start + text.len(),
16972                        reversed: false,
16973                        goal: Default::default(),
16974                    });
16975                }
16976                s.select(selections);
16977            });
16978        });
16979    }
16980
16981    pub fn select_next_syntax_node(
16982        &mut self,
16983        _: &SelectNextSyntaxNode,
16984        window: &mut Window,
16985        cx: &mut Context<Self>,
16986    ) {
16987        let old_selections: Box<[_]> = self
16988            .selections
16989            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16990            .into();
16991        if old_selections.is_empty() {
16992            return;
16993        }
16994
16995        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16996
16997        let buffer = self.buffer.read(cx).snapshot(cx);
16998        let mut selected_sibling = false;
16999
17000        let new_selections = old_selections
17001            .iter()
17002            .map(|selection| {
17003                let old_range = selection.start..selection.end;
17004
17005                let old_range =
17006                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
17007                let excerpt = buffer.excerpt_containing(old_range.clone());
17008
17009                if let Some(mut excerpt) = excerpt
17010                    && let Some(node) = excerpt
17011                        .buffer()
17012                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
17013                {
17014                    let new_range = excerpt.map_range_from_buffer(
17015                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
17016                    );
17017                    selected_sibling = true;
17018                    Selection {
17019                        id: selection.id,
17020                        start: new_range.start,
17021                        end: new_range.end,
17022                        goal: SelectionGoal::None,
17023                        reversed: selection.reversed,
17024                    }
17025                } else {
17026                    selection.clone()
17027                }
17028            })
17029            .collect::<Vec<_>>();
17030
17031        if selected_sibling {
17032            self.change_selections(
17033                SelectionEffects::scroll(Autoscroll::fit()),
17034                window,
17035                cx,
17036                |s| {
17037                    s.select(new_selections);
17038                },
17039            );
17040        }
17041    }
17042
17043    pub fn select_prev_syntax_node(
17044        &mut self,
17045        _: &SelectPreviousSyntaxNode,
17046        window: &mut Window,
17047        cx: &mut Context<Self>,
17048    ) {
17049        let old_selections: Box<[_]> = self
17050            .selections
17051            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17052            .into();
17053        if old_selections.is_empty() {
17054            return;
17055        }
17056
17057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17058
17059        let buffer = self.buffer.read(cx).snapshot(cx);
17060        let mut selected_sibling = false;
17061
17062        let new_selections = old_selections
17063            .iter()
17064            .map(|selection| {
17065                let old_range = selection.start..selection.end;
17066                let old_range =
17067                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
17068                let excerpt = buffer.excerpt_containing(old_range.clone());
17069
17070                if let Some(mut excerpt) = excerpt
17071                    && let Some(node) = excerpt
17072                        .buffer()
17073                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
17074                {
17075                    let new_range = excerpt.map_range_from_buffer(
17076                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
17077                    );
17078                    selected_sibling = true;
17079                    Selection {
17080                        id: selection.id,
17081                        start: new_range.start,
17082                        end: new_range.end,
17083                        goal: SelectionGoal::None,
17084                        reversed: selection.reversed,
17085                    }
17086                } else {
17087                    selection.clone()
17088                }
17089            })
17090            .collect::<Vec<_>>();
17091
17092        if selected_sibling {
17093            self.change_selections(
17094                SelectionEffects::scroll(Autoscroll::fit()),
17095                window,
17096                cx,
17097                |s| {
17098                    s.select(new_selections);
17099                },
17100            );
17101        }
17102    }
17103
17104    pub fn move_to_start_of_larger_syntax_node(
17105        &mut self,
17106        _: &MoveToStartOfLargerSyntaxNode,
17107        window: &mut Window,
17108        cx: &mut Context<Self>,
17109    ) {
17110        self.move_cursors_to_syntax_nodes(window, cx, false);
17111    }
17112
17113    pub fn move_to_end_of_larger_syntax_node(
17114        &mut self,
17115        _: &MoveToEndOfLargerSyntaxNode,
17116        window: &mut Window,
17117        cx: &mut Context<Self>,
17118    ) {
17119        self.move_cursors_to_syntax_nodes(window, cx, true);
17120    }
17121
17122    fn find_syntax_node_boundary(
17123        &self,
17124        selection_pos: MultiBufferOffset,
17125        move_to_end: bool,
17126        display_map: &DisplaySnapshot,
17127        buffer: &MultiBufferSnapshot,
17128    ) -> MultiBufferOffset {
17129        let old_range = selection_pos..selection_pos;
17130        let mut new_pos = selection_pos;
17131        let mut search_range = old_range;
17132        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17133            search_range = range.clone();
17134            if !node.is_named()
17135                || display_map.intersects_fold(range.start)
17136                || display_map.intersects_fold(range.end)
17137                // If cursor is already at the end of the syntax node, continue searching
17138                || (move_to_end && range.end == selection_pos)
17139                // If cursor is already at the start of the syntax node, continue searching
17140                || (!move_to_end && range.start == selection_pos)
17141            {
17142                continue;
17143            }
17144
17145            // If we found a string_content node, find the largest parent that is still string_content
17146            // Enables us to skip to the end of strings without taking multiple steps inside the string
17147            let (_, final_range) = if node.kind() == "string_content" {
17148                let mut current_node = node;
17149                let mut current_range = range;
17150                while let Some((parent, parent_range)) =
17151                    buffer.syntax_ancestor(current_range.clone())
17152                {
17153                    if parent.kind() == "string_content" {
17154                        current_node = parent;
17155                        current_range = parent_range;
17156                    } else {
17157                        break;
17158                    }
17159                }
17160
17161                (current_node, current_range)
17162            } else {
17163                (node, range)
17164            };
17165
17166            new_pos = if move_to_end {
17167                final_range.end
17168            } else {
17169                final_range.start
17170            };
17171
17172            break;
17173        }
17174
17175        new_pos
17176    }
17177
17178    fn move_cursors_to_syntax_nodes(
17179        &mut self,
17180        window: &mut Window,
17181        cx: &mut Context<Self>,
17182        move_to_end: bool,
17183    ) -> bool {
17184        let old_selections: Box<[_]> = self
17185            .selections
17186            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17187            .into();
17188        if old_selections.is_empty() {
17189            return false;
17190        }
17191
17192        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17193
17194        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17195        let buffer = self.buffer.read(cx).snapshot(cx);
17196
17197        let mut any_cursor_moved = false;
17198        let new_selections = old_selections
17199            .iter()
17200            .map(|selection| {
17201                if !selection.is_empty() {
17202                    return selection.clone();
17203                }
17204
17205                let selection_pos = selection.head();
17206                let new_pos = self.find_syntax_node_boundary(
17207                    selection_pos,
17208                    move_to_end,
17209                    &display_map,
17210                    &buffer,
17211                );
17212
17213                any_cursor_moved |= new_pos != selection_pos;
17214
17215                Selection {
17216                    id: selection.id,
17217                    start: new_pos,
17218                    end: new_pos,
17219                    goal: SelectionGoal::None,
17220                    reversed: false,
17221                }
17222            })
17223            .collect::<Vec<_>>();
17224
17225        self.change_selections(Default::default(), window, cx, |s| {
17226            s.select(new_selections);
17227        });
17228        self.request_autoscroll(Autoscroll::newest(), cx);
17229
17230        any_cursor_moved
17231    }
17232
17233    pub fn select_to_start_of_larger_syntax_node(
17234        &mut self,
17235        _: &SelectToStartOfLargerSyntaxNode,
17236        window: &mut Window,
17237        cx: &mut Context<Self>,
17238    ) {
17239        self.select_to_syntax_nodes(window, cx, false);
17240    }
17241
17242    pub fn select_to_end_of_larger_syntax_node(
17243        &mut self,
17244        _: &SelectToEndOfLargerSyntaxNode,
17245        window: &mut Window,
17246        cx: &mut Context<Self>,
17247    ) {
17248        self.select_to_syntax_nodes(window, cx, true);
17249    }
17250
17251    fn select_to_syntax_nodes(
17252        &mut self,
17253        window: &mut Window,
17254        cx: &mut Context<Self>,
17255        move_to_end: bool,
17256    ) {
17257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17258
17259        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17260        let buffer = self.buffer.read(cx).snapshot(cx);
17261        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17262
17263        let new_selections = old_selections
17264            .iter()
17265            .map(|selection| {
17266                let new_pos = self.find_syntax_node_boundary(
17267                    selection.head(),
17268                    move_to_end,
17269                    &display_map,
17270                    &buffer,
17271                );
17272
17273                let mut new_selection = selection.clone();
17274                new_selection.set_head(new_pos, SelectionGoal::None);
17275                new_selection
17276            })
17277            .collect::<Vec<_>>();
17278
17279        self.change_selections(Default::default(), window, cx, |s| {
17280            s.select(new_selections);
17281        });
17282    }
17283
17284    pub fn move_to_enclosing_bracket(
17285        &mut self,
17286        _: &MoveToEnclosingBracket,
17287        window: &mut Window,
17288        cx: &mut Context<Self>,
17289    ) {
17290        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17291        self.change_selections(Default::default(), window, cx, |s| {
17292            s.move_offsets_with(&mut |snapshot, selection| {
17293                let Some(enclosing_bracket_ranges) =
17294                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17295                else {
17296                    return;
17297                };
17298
17299                let mut best_length = usize::MAX;
17300                let mut best_inside = false;
17301                let mut best_in_bracket_range = false;
17302                let mut best_destination = None;
17303                for (open, close) in enclosing_bracket_ranges {
17304                    let close = close.to_inclusive();
17305                    let length = *close.end() - open.start;
17306                    let inside = selection.start >= open.end && selection.end <= *close.start();
17307                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17308                        || close.contains(&selection.head());
17309
17310                    // If best is next to a bracket and current isn't, skip
17311                    if !in_bracket_range && best_in_bracket_range {
17312                        continue;
17313                    }
17314
17315                    // Prefer smaller lengths unless best is inside and current isn't
17316                    if length > best_length && (best_inside || !inside) {
17317                        continue;
17318                    }
17319
17320                    best_length = length;
17321                    best_inside = inside;
17322                    best_in_bracket_range = in_bracket_range;
17323                    best_destination = Some(
17324                        if close.contains(&selection.start) && close.contains(&selection.end) {
17325                            if inside { open.end } else { open.start }
17326                        } else if inside {
17327                            *close.start()
17328                        } else {
17329                            *close.end()
17330                        },
17331                    );
17332                }
17333
17334                if let Some(destination) = best_destination {
17335                    selection.collapse_to(destination, SelectionGoal::None);
17336                }
17337            })
17338        });
17339    }
17340
17341    pub fn undo_selection(
17342        &mut self,
17343        _: &UndoSelection,
17344        window: &mut Window,
17345        cx: &mut Context<Self>,
17346    ) {
17347        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17348        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17349            self.selection_history.mode = SelectionHistoryMode::Undoing;
17350            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17351                this.end_selection(window, cx);
17352                this.change_selections(
17353                    SelectionEffects::scroll(Autoscroll::newest()),
17354                    window,
17355                    cx,
17356                    |s| s.select_anchors(entry.selections.to_vec()),
17357                );
17358            });
17359            self.selection_history.mode = SelectionHistoryMode::Normal;
17360
17361            self.select_next_state = entry.select_next_state;
17362            self.select_prev_state = entry.select_prev_state;
17363            self.add_selections_state = entry.add_selections_state;
17364        }
17365    }
17366
17367    pub fn redo_selection(
17368        &mut self,
17369        _: &RedoSelection,
17370        window: &mut Window,
17371        cx: &mut Context<Self>,
17372    ) {
17373        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17374        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17375            self.selection_history.mode = SelectionHistoryMode::Redoing;
17376            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17377                this.end_selection(window, cx);
17378                this.change_selections(
17379                    SelectionEffects::scroll(Autoscroll::newest()),
17380                    window,
17381                    cx,
17382                    |s| s.select_anchors(entry.selections.to_vec()),
17383                );
17384            });
17385            self.selection_history.mode = SelectionHistoryMode::Normal;
17386
17387            self.select_next_state = entry.select_next_state;
17388            self.select_prev_state = entry.select_prev_state;
17389            self.add_selections_state = entry.add_selections_state;
17390        }
17391    }
17392
17393    pub fn expand_excerpts(
17394        &mut self,
17395        action: &ExpandExcerpts,
17396        _: &mut Window,
17397        cx: &mut Context<Self>,
17398    ) {
17399        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17400    }
17401
17402    pub fn expand_excerpts_down(
17403        &mut self,
17404        action: &ExpandExcerptsDown,
17405        _: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17409    }
17410
17411    pub fn expand_excerpts_up(
17412        &mut self,
17413        action: &ExpandExcerptsUp,
17414        _: &mut Window,
17415        cx: &mut Context<Self>,
17416    ) {
17417        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17418    }
17419
17420    pub fn expand_excerpts_for_direction(
17421        &mut self,
17422        lines: u32,
17423        direction: ExpandExcerptDirection,
17424        cx: &mut Context<Self>,
17425    ) {
17426        let selections = self.selections.disjoint_anchors_arc();
17427
17428        let lines = if lines == 0 {
17429            EditorSettings::get_global(cx).expand_excerpt_lines
17430        } else {
17431            lines
17432        };
17433
17434        let snapshot = self.buffer.read(cx).snapshot(cx);
17435        let excerpt_ids = selections
17436            .iter()
17437            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17438            .unique()
17439            .sorted()
17440            .collect::<Vec<_>>();
17441
17442        if self.delegate_expand_excerpts {
17443            cx.emit(EditorEvent::ExpandExcerptsRequested {
17444                excerpt_ids,
17445                lines,
17446                direction,
17447            });
17448            return;
17449        }
17450
17451        self.buffer.update(cx, |buffer, cx| {
17452            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17453        })
17454    }
17455
17456    pub fn expand_excerpt(
17457        &mut self,
17458        excerpt: ExcerptId,
17459        direction: ExpandExcerptDirection,
17460        window: &mut Window,
17461        cx: &mut Context<Self>,
17462    ) {
17463        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17464
17465        if self.delegate_expand_excerpts {
17466            cx.emit(EditorEvent::ExpandExcerptsRequested {
17467                excerpt_ids: vec![excerpt],
17468                lines: lines_to_expand,
17469                direction,
17470            });
17471            return;
17472        }
17473
17474        let current_scroll_position = self.scroll_position(cx);
17475        let mut scroll = None;
17476
17477        if direction == ExpandExcerptDirection::Down {
17478            let multi_buffer = self.buffer.read(cx);
17479            let snapshot = multi_buffer.snapshot(cx);
17480            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17481                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17482                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17483            {
17484                let buffer_snapshot = buffer.read(cx).snapshot();
17485                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17486                let last_row = buffer_snapshot.max_point().row;
17487                let lines_below = last_row.saturating_sub(excerpt_end_row);
17488                if lines_below >= lines_to_expand {
17489                    scroll = Some(
17490                        current_scroll_position
17491                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17492                    );
17493                }
17494            }
17495        }
17496        if direction == ExpandExcerptDirection::Up
17497            && self
17498                .buffer
17499                .read(cx)
17500                .snapshot(cx)
17501                .excerpt_before(excerpt)
17502                .is_none()
17503        {
17504            scroll = Some(current_scroll_position);
17505        }
17506
17507        self.buffer.update(cx, |buffer, cx| {
17508            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17509        });
17510
17511        if let Some(new_scroll_position) = scroll {
17512            self.set_scroll_position(new_scroll_position, window, cx);
17513        }
17514    }
17515
17516    pub fn go_to_singleton_buffer_point(
17517        &mut self,
17518        point: Point,
17519        window: &mut Window,
17520        cx: &mut Context<Self>,
17521    ) {
17522        self.go_to_singleton_buffer_range(point..point, window, cx);
17523    }
17524
17525    pub fn go_to_singleton_buffer_range(
17526        &mut self,
17527        range: Range<Point>,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        let multibuffer = self.buffer().read(cx);
17532        let Some(buffer) = multibuffer.as_singleton() else {
17533            return;
17534        };
17535        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17536            return;
17537        };
17538        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17539            return;
17540        };
17541        self.change_selections(
17542            SelectionEffects::default().nav_history(true),
17543            window,
17544            cx,
17545            |s| s.select_anchor_ranges([start..end]),
17546        );
17547    }
17548
17549    pub fn go_to_diagnostic(
17550        &mut self,
17551        action: &GoToDiagnostic,
17552        window: &mut Window,
17553        cx: &mut Context<Self>,
17554    ) {
17555        if !self.diagnostics_enabled() {
17556            return;
17557        }
17558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17559        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17560    }
17561
17562    pub fn go_to_prev_diagnostic(
17563        &mut self,
17564        action: &GoToPreviousDiagnostic,
17565        window: &mut Window,
17566        cx: &mut Context<Self>,
17567    ) {
17568        if !self.diagnostics_enabled() {
17569            return;
17570        }
17571        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17572        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17573    }
17574
17575    pub fn go_to_diagnostic_impl(
17576        &mut self,
17577        direction: Direction,
17578        severity: GoToDiagnosticSeverityFilter,
17579        window: &mut Window,
17580        cx: &mut Context<Self>,
17581    ) {
17582        let buffer = self.buffer.read(cx).snapshot(cx);
17583        let selection = self
17584            .selections
17585            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17586
17587        let mut active_group_id = None;
17588        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17589            && active_group.active_range.start.to_offset(&buffer) == selection.start
17590        {
17591            active_group_id = Some(active_group.group_id);
17592        }
17593
17594        fn filtered<'a>(
17595            severity: GoToDiagnosticSeverityFilter,
17596            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17597        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17598            diagnostics
17599                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17600                .filter(|entry| entry.range.start != entry.range.end)
17601                .filter(|entry| !entry.diagnostic.is_unnecessary)
17602        }
17603
17604        let before = filtered(
17605            severity,
17606            buffer
17607                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17608                .filter(|entry| entry.range.start <= selection.start),
17609        );
17610        let after = filtered(
17611            severity,
17612            buffer
17613                .diagnostics_in_range(selection.start..buffer.len())
17614                .filter(|entry| entry.range.start >= selection.start),
17615        );
17616
17617        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17618        if direction == Direction::Prev {
17619            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17620            {
17621                for diagnostic in prev_diagnostics.into_iter().rev() {
17622                    if diagnostic.range.start != selection.start
17623                        || active_group_id
17624                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17625                    {
17626                        found = Some(diagnostic);
17627                        break 'outer;
17628                    }
17629                }
17630            }
17631        } else {
17632            for diagnostic in after.chain(before) {
17633                if diagnostic.range.start != selection.start
17634                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17635                {
17636                    found = Some(diagnostic);
17637                    break;
17638                }
17639            }
17640        }
17641        let Some(next_diagnostic) = found else {
17642            return;
17643        };
17644
17645        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17646        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17647            return;
17648        };
17649        let snapshot = self.snapshot(window, cx);
17650        if snapshot.intersects_fold(next_diagnostic.range.start) {
17651            self.unfold_ranges(
17652                std::slice::from_ref(&next_diagnostic.range),
17653                true,
17654                false,
17655                cx,
17656            );
17657        }
17658        self.change_selections(Default::default(), window, cx, |s| {
17659            s.select_ranges(vec![
17660                next_diagnostic.range.start..next_diagnostic.range.start,
17661            ])
17662        });
17663        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17664        self.refresh_edit_prediction(false, true, window, cx);
17665    }
17666
17667    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17669        let snapshot = self.snapshot(window, cx);
17670        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17671        self.go_to_hunk_before_or_after_position(
17672            &snapshot,
17673            selection.head(),
17674            Direction::Next,
17675            true,
17676            window,
17677            cx,
17678        );
17679    }
17680
17681    pub fn go_to_hunk_before_or_after_position(
17682        &mut self,
17683        snapshot: &EditorSnapshot,
17684        position: Point,
17685        direction: Direction,
17686        wrap_around: bool,
17687        window: &mut Window,
17688        cx: &mut Context<Editor>,
17689    ) {
17690        let row = if direction == Direction::Next {
17691            self.hunk_after_position(snapshot, position, wrap_around)
17692                .map(|hunk| hunk.row_range.start)
17693        } else {
17694            self.hunk_before_position(snapshot, position, wrap_around)
17695        };
17696
17697        if let Some(row) = row {
17698            let destination = Point::new(row.0, 0);
17699            let autoscroll = Autoscroll::center();
17700
17701            self.unfold_ranges(&[destination..destination], false, false, cx);
17702            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17703                s.select_ranges([destination..destination]);
17704            });
17705        }
17706    }
17707
17708    fn hunk_after_position(
17709        &mut self,
17710        snapshot: &EditorSnapshot,
17711        position: Point,
17712        wrap_around: bool,
17713    ) -> Option<MultiBufferDiffHunk> {
17714        let result = snapshot
17715            .buffer_snapshot()
17716            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17717            .find(|hunk| hunk.row_range.start.0 > position.row);
17718
17719        if wrap_around {
17720            result.or_else(|| {
17721                snapshot
17722                    .buffer_snapshot()
17723                    .diff_hunks_in_range(Point::zero()..position)
17724                    .find(|hunk| hunk.row_range.end.0 < position.row)
17725            })
17726        } else {
17727            result
17728        }
17729    }
17730
17731    fn go_to_prev_hunk(
17732        &mut self,
17733        _: &GoToPreviousHunk,
17734        window: &mut Window,
17735        cx: &mut Context<Self>,
17736    ) {
17737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17738        let snapshot = self.snapshot(window, cx);
17739        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17740        self.go_to_hunk_before_or_after_position(
17741            &snapshot,
17742            selection.head(),
17743            Direction::Prev,
17744            true,
17745            window,
17746            cx,
17747        );
17748    }
17749
17750    fn hunk_before_position(
17751        &mut self,
17752        snapshot: &EditorSnapshot,
17753        position: Point,
17754        wrap_around: bool,
17755    ) -> Option<MultiBufferRow> {
17756        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17757
17758        if wrap_around {
17759            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17760        } else {
17761            result
17762        }
17763    }
17764
17765    fn go_to_next_change(
17766        &mut self,
17767        _: &GoToNextChange,
17768        window: &mut Window,
17769        cx: &mut Context<Self>,
17770    ) {
17771        if let Some(selections) = self
17772            .change_list
17773            .next_change(1, Direction::Next)
17774            .map(|s| s.to_vec())
17775        {
17776            self.change_selections(Default::default(), window, cx, |s| {
17777                let map = s.display_snapshot();
17778                s.select_display_ranges(selections.iter().map(|a| {
17779                    let point = a.to_display_point(&map);
17780                    point..point
17781                }))
17782            })
17783        }
17784    }
17785
17786    fn go_to_previous_change(
17787        &mut self,
17788        _: &GoToPreviousChange,
17789        window: &mut Window,
17790        cx: &mut Context<Self>,
17791    ) {
17792        if let Some(selections) = self
17793            .change_list
17794            .next_change(1, Direction::Prev)
17795            .map(|s| s.to_vec())
17796        {
17797            self.change_selections(Default::default(), window, cx, |s| {
17798                let map = s.display_snapshot();
17799                s.select_display_ranges(selections.iter().map(|a| {
17800                    let point = a.to_display_point(&map);
17801                    point..point
17802                }))
17803            })
17804        }
17805    }
17806
17807    pub fn go_to_next_document_highlight(
17808        &mut self,
17809        _: &GoToNextDocumentHighlight,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17814    }
17815
17816    pub fn go_to_prev_document_highlight(
17817        &mut self,
17818        _: &GoToPreviousDocumentHighlight,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17823    }
17824
17825    pub fn go_to_document_highlight_before_or_after_position(
17826        &mut self,
17827        direction: Direction,
17828        window: &mut Window,
17829        cx: &mut Context<Editor>,
17830    ) {
17831        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17832        let snapshot = self.snapshot(window, cx);
17833        let buffer = &snapshot.buffer_snapshot();
17834        let position = self
17835            .selections
17836            .newest::<Point>(&snapshot.display_snapshot)
17837            .head();
17838        let anchor_position = buffer.anchor_after(position);
17839
17840        // Get all document highlights (both read and write)
17841        let mut all_highlights = Vec::new();
17842
17843        if let Some((_, read_highlights)) = self
17844            .background_highlights
17845            .get(&HighlightKey::DocumentHighlightRead)
17846        {
17847            all_highlights.extend(read_highlights.iter());
17848        }
17849
17850        if let Some((_, write_highlights)) = self
17851            .background_highlights
17852            .get(&HighlightKey::DocumentHighlightWrite)
17853        {
17854            all_highlights.extend(write_highlights.iter());
17855        }
17856
17857        if all_highlights.is_empty() {
17858            return;
17859        }
17860
17861        // Sort highlights by position
17862        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17863
17864        let target_highlight = match direction {
17865            Direction::Next => {
17866                // Find the first highlight after the current position
17867                all_highlights
17868                    .iter()
17869                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17870            }
17871            Direction::Prev => {
17872                // Find the last highlight before the current position
17873                all_highlights
17874                    .iter()
17875                    .rev()
17876                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17877            }
17878        };
17879
17880        if let Some(highlight) = target_highlight {
17881            let destination = highlight.start.to_point(buffer);
17882            let autoscroll = Autoscroll::center();
17883
17884            self.unfold_ranges(&[destination..destination], false, false, cx);
17885            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17886                s.select_ranges([destination..destination]);
17887            });
17888        }
17889    }
17890
17891    fn go_to_line<T: 'static>(
17892        &mut self,
17893        position: Anchor,
17894        highlight_color: Option<Hsla>,
17895        window: &mut Window,
17896        cx: &mut Context<Self>,
17897    ) {
17898        let snapshot = self.snapshot(window, cx).display_snapshot;
17899        let position = position.to_point(&snapshot.buffer_snapshot());
17900        let start = snapshot
17901            .buffer_snapshot()
17902            .clip_point(Point::new(position.row, 0), Bias::Left);
17903        let end = start + Point::new(1, 0);
17904        let start = snapshot.buffer_snapshot().anchor_before(start);
17905        let end = snapshot.buffer_snapshot().anchor_before(end);
17906
17907        self.highlight_rows::<T>(
17908            start..end,
17909            highlight_color
17910                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17911            Default::default(),
17912            cx,
17913        );
17914
17915        if self.buffer.read(cx).is_singleton() {
17916            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17917        }
17918    }
17919
17920    pub fn go_to_definition(
17921        &mut self,
17922        _: &GoToDefinition,
17923        window: &mut Window,
17924        cx: &mut Context<Self>,
17925    ) -> Task<Result<Navigated>> {
17926        let definition =
17927            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17928        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17929        cx.spawn_in(window, async move |editor, cx| {
17930            if definition.await? == Navigated::Yes {
17931                return Ok(Navigated::Yes);
17932            }
17933            match fallback_strategy {
17934                GoToDefinitionFallback::None => Ok(Navigated::No),
17935                GoToDefinitionFallback::FindAllReferences => {
17936                    match editor.update_in(cx, |editor, window, cx| {
17937                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17938                    })? {
17939                        Some(references) => references.await,
17940                        None => Ok(Navigated::No),
17941                    }
17942                }
17943            }
17944        })
17945    }
17946
17947    pub fn go_to_declaration(
17948        &mut self,
17949        _: &GoToDeclaration,
17950        window: &mut Window,
17951        cx: &mut Context<Self>,
17952    ) -> Task<Result<Navigated>> {
17953        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17954    }
17955
17956    pub fn go_to_declaration_split(
17957        &mut self,
17958        _: &GoToDeclaration,
17959        window: &mut Window,
17960        cx: &mut Context<Self>,
17961    ) -> Task<Result<Navigated>> {
17962        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17963    }
17964
17965    pub fn go_to_implementation(
17966        &mut self,
17967        _: &GoToImplementation,
17968        window: &mut Window,
17969        cx: &mut Context<Self>,
17970    ) -> Task<Result<Navigated>> {
17971        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17972    }
17973
17974    pub fn go_to_implementation_split(
17975        &mut self,
17976        _: &GoToImplementationSplit,
17977        window: &mut Window,
17978        cx: &mut Context<Self>,
17979    ) -> Task<Result<Navigated>> {
17980        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17981    }
17982
17983    pub fn go_to_type_definition(
17984        &mut self,
17985        _: &GoToTypeDefinition,
17986        window: &mut Window,
17987        cx: &mut Context<Self>,
17988    ) -> Task<Result<Navigated>> {
17989        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17990    }
17991
17992    pub fn go_to_definition_split(
17993        &mut self,
17994        _: &GoToDefinitionSplit,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) -> Task<Result<Navigated>> {
17998        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17999    }
18000
18001    pub fn go_to_type_definition_split(
18002        &mut self,
18003        _: &GoToTypeDefinitionSplit,
18004        window: &mut Window,
18005        cx: &mut Context<Self>,
18006    ) -> Task<Result<Navigated>> {
18007        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18008    }
18009
18010    fn go_to_definition_of_kind(
18011        &mut self,
18012        kind: GotoDefinitionKind,
18013        split: bool,
18014        window: &mut Window,
18015        cx: &mut Context<Self>,
18016    ) -> Task<Result<Navigated>> {
18017        let Some(provider) = self.semantics_provider.clone() else {
18018            return Task::ready(Ok(Navigated::No));
18019        };
18020        let head = self
18021            .selections
18022            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18023            .head();
18024        let buffer = self.buffer.read(cx);
18025        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18026            return Task::ready(Ok(Navigated::No));
18027        };
18028        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18029            return Task::ready(Ok(Navigated::No));
18030        };
18031
18032        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18033
18034        cx.spawn_in(window, async move |editor, cx| {
18035            let Some(definitions) = definitions.await? else {
18036                return Ok(Navigated::No);
18037            };
18038            let navigated = editor
18039                .update_in(cx, |editor, window, cx| {
18040                    editor.navigate_to_hover_links(
18041                        Some(kind),
18042                        definitions
18043                            .into_iter()
18044                            .filter(|location| {
18045                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18046                            })
18047                            .map(HoverLink::Text)
18048                            .collect::<Vec<_>>(),
18049                        nav_entry,
18050                        split,
18051                        window,
18052                        cx,
18053                    )
18054                })?
18055                .await?;
18056            anyhow::Ok(navigated)
18057        })
18058    }
18059
18060    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18061        let selection = self.selections.newest_anchor();
18062        let head = selection.head();
18063        let tail = selection.tail();
18064
18065        let Some((buffer, start_position)) =
18066            self.buffer.read(cx).text_anchor_for_position(head, cx)
18067        else {
18068            return;
18069        };
18070
18071        let end_position = if head != tail {
18072            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18073                return;
18074            };
18075            Some(pos)
18076        } else {
18077            None
18078        };
18079
18080        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18081            let url = if let Some(end_pos) = end_position {
18082                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18083            } else {
18084                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18085            };
18086
18087            if let Some(url) = url {
18088                cx.update(|window, cx| {
18089                    if parse_zed_link(&url, cx).is_some() {
18090                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18091                    } else {
18092                        cx.open_url(&url);
18093                    }
18094                })?;
18095            }
18096
18097            anyhow::Ok(())
18098        });
18099
18100        url_finder.detach();
18101    }
18102
18103    pub fn open_selected_filename(
18104        &mut self,
18105        _: &OpenSelectedFilename,
18106        window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        let Some(workspace) = self.workspace() else {
18110            return;
18111        };
18112
18113        let position = self.selections.newest_anchor().head();
18114
18115        let Some((buffer, buffer_position)) =
18116            self.buffer.read(cx).text_anchor_for_position(position, cx)
18117        else {
18118            return;
18119        };
18120
18121        let project = self.project.clone();
18122
18123        cx.spawn_in(window, async move |_, cx| {
18124            let result = find_file(&buffer, project, buffer_position, cx).await;
18125
18126            if let Some((_, path)) = result {
18127                workspace
18128                    .update_in(cx, |workspace, window, cx| {
18129                        workspace.open_resolved_path(path, window, cx)
18130                    })?
18131                    .await?;
18132            }
18133            anyhow::Ok(())
18134        })
18135        .detach();
18136    }
18137
18138    pub(crate) fn navigate_to_hover_links(
18139        &mut self,
18140        kind: Option<GotoDefinitionKind>,
18141        definitions: Vec<HoverLink>,
18142        origin: Option<NavigationEntry>,
18143        split: bool,
18144        window: &mut Window,
18145        cx: &mut Context<Editor>,
18146    ) -> Task<Result<Navigated>> {
18147        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18148        let mut first_url_or_file = None;
18149        let definitions: Vec<_> = definitions
18150            .into_iter()
18151            .filter_map(|def| match def {
18152                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18153                HoverLink::InlayHint(lsp_location, server_id) => {
18154                    let computation =
18155                        self.compute_target_location(lsp_location, server_id, window, cx);
18156                    Some(cx.background_spawn(computation))
18157                }
18158                HoverLink::Url(url) => {
18159                    first_url_or_file = Some(Either::Left(url));
18160                    None
18161                }
18162                HoverLink::File(path) => {
18163                    first_url_or_file = Some(Either::Right(path));
18164                    None
18165                }
18166            })
18167            .collect();
18168
18169        let workspace = self.workspace();
18170
18171        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18172        cx.spawn_in(window, async move |editor, cx| {
18173            let locations: Vec<Location> = future::join_all(definitions)
18174                .await
18175                .into_iter()
18176                .filter_map(|location| location.transpose())
18177                .collect::<Result<_>>()
18178                .context("location tasks")?;
18179            let mut locations = cx.update(|_, cx| {
18180                locations
18181                    .into_iter()
18182                    .map(|location| {
18183                        let buffer = location.buffer.read(cx);
18184                        (location.buffer, location.range.to_point(buffer))
18185                    })
18186                    .into_group_map()
18187            })?;
18188            let mut num_locations = 0;
18189            for ranges in locations.values_mut() {
18190                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18191                ranges.dedup();
18192                let fits_in_one_excerpt = ranges
18193                    .iter()
18194                    .tuple_windows()
18195                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18196                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18197            }
18198
18199            if num_locations > 1 {
18200                let tab_kind = match kind {
18201                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18202                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18203                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18204                    Some(GotoDefinitionKind::Type) => "Types",
18205                };
18206                let title = editor
18207                    .update_in(cx, |_, _, cx| {
18208                        let target = locations
18209                            .iter()
18210                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18211                            .map(|(buffer, location)| {
18212                                buffer
18213                                    .read(cx)
18214                                    .text_for_range(location.clone())
18215                                    .collect::<String>()
18216                            })
18217                            .filter(|text| !text.contains('\n'))
18218                            .unique()
18219                            .take(3)
18220                            .join(", ");
18221                        if target.is_empty() {
18222                            tab_kind.to_owned()
18223                        } else {
18224                            format!("{tab_kind} for {target}")
18225                        }
18226                    })
18227                    .context("buffer title")?;
18228
18229                let Some(workspace) = workspace else {
18230                    return Ok(Navigated::No);
18231                };
18232
18233                let opened = workspace
18234                    .update_in(cx, |workspace, window, cx| {
18235                        let allow_preview = PreviewTabsSettings::get_global(cx)
18236                            .enable_preview_multibuffer_from_code_navigation;
18237                        if let Some((target_editor, target_pane)) =
18238                            Self::open_locations_in_multibuffer(
18239                                workspace,
18240                                locations,
18241                                title,
18242                                split,
18243                                allow_preview,
18244                                MultibufferSelectionMode::First,
18245                                window,
18246                                cx,
18247                            )
18248                        {
18249                            // We create our own nav history instead of using
18250                            // `target_editor.nav_history` because `nav_history`
18251                            // seems to be populated asynchronously when an item
18252                            // is added to a pane
18253                            let mut nav_history = target_pane
18254                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18255                            target_editor.update(cx, |editor, cx| {
18256                                let nav_data = editor
18257                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18258                                let target =
18259                                    Some(nav_history.navigation_entry(Some(
18260                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18261                                    )));
18262                                nav_history.push_tag(origin, target);
18263                            })
18264                        }
18265                    })
18266                    .is_ok();
18267
18268                anyhow::Ok(Navigated::from_bool(opened))
18269            } else if num_locations == 0 {
18270                // If there is one url or file, open it directly
18271                match first_url_or_file {
18272                    Some(Either::Left(url)) => {
18273                        cx.update(|window, cx| {
18274                            if parse_zed_link(&url, cx).is_some() {
18275                                window
18276                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18277                            } else {
18278                                cx.open_url(&url);
18279                            }
18280                        })?;
18281                        Ok(Navigated::Yes)
18282                    }
18283                    Some(Either::Right(path)) => {
18284                        // TODO(andrew): respect preview tab settings
18285                        //               `enable_keep_preview_on_code_navigation` and
18286                        //               `enable_preview_file_from_code_navigation`
18287                        let Some(workspace) = workspace else {
18288                            return Ok(Navigated::No);
18289                        };
18290                        workspace
18291                            .update_in(cx, |workspace, window, cx| {
18292                                workspace.open_resolved_path(path, window, cx)
18293                            })?
18294                            .await?;
18295                        Ok(Navigated::Yes)
18296                    }
18297                    None => Ok(Navigated::No),
18298                }
18299            } else {
18300                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18301
18302                editor.update_in(cx, |editor, window, cx| {
18303                    let target_ranges = target_ranges
18304                        .into_iter()
18305                        .map(|r| editor.range_for_match(&r))
18306                        .map(collapse_multiline_range)
18307                        .collect::<Vec<_>>();
18308                    if !split
18309                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18310                    {
18311                        let multibuffer = editor.buffer.read(cx);
18312                        let target_ranges = target_ranges
18313                            .into_iter()
18314                            .filter_map(|r| {
18315                                let start = multibuffer.buffer_point_to_anchor(
18316                                    &target_buffer,
18317                                    r.start,
18318                                    cx,
18319                                )?;
18320                                let end = multibuffer.buffer_point_to_anchor(
18321                                    &target_buffer,
18322                                    r.end,
18323                                    cx,
18324                                )?;
18325                                Some(start..end)
18326                            })
18327                            .collect::<Vec<_>>();
18328                        if target_ranges.is_empty() {
18329                            return Navigated::No;
18330                        }
18331
18332                        editor.change_selections(
18333                            SelectionEffects::default().nav_history(true),
18334                            window,
18335                            cx,
18336                            |s| s.select_anchor_ranges(target_ranges),
18337                        );
18338
18339                        let target =
18340                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18341                        if let Some(mut nav_history) = editor.nav_history.clone() {
18342                            nav_history.push_tag(origin, target);
18343                        }
18344                    } else {
18345                        let Some(workspace) = workspace else {
18346                            return Navigated::No;
18347                        };
18348                        let pane = workspace.read(cx).active_pane().clone();
18349                        window.defer(cx, move |window, cx| {
18350                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18351                                workspace.update(cx, |workspace, cx| {
18352                                    let pane = if split {
18353                                        workspace.adjacent_pane(window, cx)
18354                                    } else {
18355                                        workspace.active_pane().clone()
18356                                    };
18357
18358                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18359                                    let keep_old_preview = preview_tabs_settings
18360                                        .enable_keep_preview_on_code_navigation;
18361                                    let allow_new_preview = preview_tabs_settings
18362                                        .enable_preview_file_from_code_navigation;
18363
18364                                    let editor = workspace.open_project_item(
18365                                        pane.clone(),
18366                                        target_buffer.clone(),
18367                                        true,
18368                                        true,
18369                                        keep_old_preview,
18370                                        allow_new_preview,
18371                                        window,
18372                                        cx,
18373                                    );
18374                                    (editor, pane)
18375                                });
18376                            // We create our own nav history instead of using
18377                            // `target_editor.nav_history` because `nav_history`
18378                            // seems to be populated asynchronously when an item
18379                            // is added to a pane
18380                            let mut nav_history = target_pane
18381                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18382                            target_editor.update(cx, |target_editor, cx| {
18383                                // When selecting a definition in a different buffer, disable the nav history
18384                                // to avoid creating a history entry at the previous cursor location.
18385                                pane.update(cx, |pane, _| pane.disable_history());
18386
18387                                let multibuffer = target_editor.buffer.read(cx);
18388                                let Some(target_buffer) = multibuffer.as_singleton() else {
18389                                    return Navigated::No;
18390                                };
18391                                let target_ranges = target_ranges
18392                                    .into_iter()
18393                                    .filter_map(|r| {
18394                                        let start = multibuffer.buffer_point_to_anchor(
18395                                            &target_buffer,
18396                                            r.start,
18397                                            cx,
18398                                        )?;
18399                                        let end = multibuffer.buffer_point_to_anchor(
18400                                            &target_buffer,
18401                                            r.end,
18402                                            cx,
18403                                        )?;
18404                                        Some(start..end)
18405                                    })
18406                                    .collect::<Vec<_>>();
18407                                if target_ranges.is_empty() {
18408                                    return Navigated::No;
18409                                }
18410
18411                                target_editor.change_selections(
18412                                    SelectionEffects::default().nav_history(true),
18413                                    window,
18414                                    cx,
18415                                    |s| s.select_anchor_ranges(target_ranges),
18416                                );
18417
18418                                let nav_data = target_editor.navigation_data(
18419                                    target_editor.selections.newest_anchor().head(),
18420                                    cx,
18421                                );
18422                                let target =
18423                                    Some(nav_history.navigation_entry(Some(
18424                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18425                                    )));
18426                                nav_history.push_tag(origin, target);
18427                                pane.update(cx, |pane, _| pane.enable_history());
18428                                Navigated::Yes
18429                            });
18430                        });
18431                    }
18432                    Navigated::Yes
18433                })
18434            }
18435        })
18436    }
18437
18438    fn compute_target_location(
18439        &self,
18440        lsp_location: lsp::Location,
18441        server_id: LanguageServerId,
18442        window: &mut Window,
18443        cx: &mut Context<Self>,
18444    ) -> Task<anyhow::Result<Option<Location>>> {
18445        let Some(project) = self.project.clone() else {
18446            return Task::ready(Ok(None));
18447        };
18448
18449        cx.spawn_in(window, async move |editor, cx| {
18450            let location_task = editor.update(cx, |_, cx| {
18451                project.update(cx, |project, cx| {
18452                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18453                })
18454            })?;
18455            let location = Some({
18456                let target_buffer_handle = location_task.await.context("open local buffer")?;
18457                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18458                    let target_start = target_buffer
18459                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18460                    let target_end = target_buffer
18461                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18462                    target_buffer.anchor_after(target_start)
18463                        ..target_buffer.anchor_before(target_end)
18464                });
18465                Location {
18466                    buffer: target_buffer_handle,
18467                    range,
18468                }
18469            });
18470            Ok(location)
18471        })
18472    }
18473
18474    fn go_to_next_reference(
18475        &mut self,
18476        _: &GoToNextReference,
18477        window: &mut Window,
18478        cx: &mut Context<Self>,
18479    ) {
18480        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18481        if let Some(task) = task {
18482            task.detach();
18483        };
18484    }
18485
18486    fn go_to_prev_reference(
18487        &mut self,
18488        _: &GoToPreviousReference,
18489        window: &mut Window,
18490        cx: &mut Context<Self>,
18491    ) {
18492        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18493        if let Some(task) = task {
18494            task.detach();
18495        };
18496    }
18497
18498    fn go_to_symbol_by_offset(
18499        &mut self,
18500        window: &mut Window,
18501        cx: &mut Context<Self>,
18502        offset: i8,
18503    ) -> Task<Result<()>> {
18504        let editor_snapshot = self.snapshot(window, cx);
18505
18506        // We don't care about multi-buffer symbols
18507        let Some((excerpt_id, _, _)) = editor_snapshot.as_singleton() else {
18508            return Task::ready(Ok(()));
18509        };
18510
18511        let cursor_offset = self
18512            .selections
18513            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18514            .head();
18515
18516        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18517            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18518                let buffer = ed.buffer.read(cx).as_singleton()?;
18519                Some(buffer.read(cx).remote_id())
18520            }) else {
18521                return Ok(());
18522            };
18523
18524            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18525            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18526
18527            let multi_snapshot = editor_snapshot.buffer();
18528            let buffer_range = |range: &Range<_>| {
18529                Anchor::range_in_buffer(excerpt_id, range.clone()).to_offset(multi_snapshot)
18530            };
18531
18532            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18533                let current_idx = outline_items
18534                    .iter()
18535                    .enumerate()
18536                    .filter_map(|(idx, item)| {
18537                        // Find the closest outline item by distance between outline text and cursor location
18538                        let source_range = buffer_range(&item.source_range_for_text);
18539                        let distance_to_closest_endpoint = cmp::min(
18540                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18541                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18542                        );
18543
18544                        let item_towards_offset =
18545                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18546                                == (offset as isize).signum();
18547
18548                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18549
18550                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18551                        // we should not already be within the outline's source range. We then pick the closest outline
18552                        // item.
18553                        (item_towards_offset && !source_range_contains_cursor)
18554                            .then_some((distance_to_closest_endpoint, idx))
18555                    })
18556                    .min()
18557                    .map(|(_, idx)| idx);
18558
18559                let Some(idx) = current_idx else {
18560                    return;
18561                };
18562
18563                let range = buffer_range(&outline_items[idx].source_range_for_text);
18564                let selection = [range.start..range.start];
18565
18566                let _ = editor
18567                    .update(acx, |editor, ecx| {
18568                        editor.change_selections(
18569                            SelectionEffects::scroll(Autoscroll::newest()),
18570                            window,
18571                            ecx,
18572                            |s| s.select_ranges(selection),
18573                        );
18574                    })
18575                    .ok();
18576            })?;
18577
18578            Ok(())
18579        })
18580    }
18581
18582    fn go_to_next_symbol(
18583        &mut self,
18584        _: &GoToNextSymbol,
18585        window: &mut Window,
18586        cx: &mut Context<Self>,
18587    ) {
18588        self.go_to_symbol_by_offset(window, cx, 1).detach();
18589    }
18590
18591    fn go_to_previous_symbol(
18592        &mut self,
18593        _: &GoToPreviousSymbol,
18594        window: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        self.go_to_symbol_by_offset(window, cx, -1).detach();
18598    }
18599
18600    pub fn go_to_reference_before_or_after_position(
18601        &mut self,
18602        direction: Direction,
18603        count: usize,
18604        window: &mut Window,
18605        cx: &mut Context<Self>,
18606    ) -> Option<Task<Result<()>>> {
18607        let selection = self.selections.newest_anchor();
18608        let head = selection.head();
18609
18610        let multi_buffer = self.buffer.read(cx);
18611
18612        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18613        let workspace = self.workspace()?;
18614        let project = workspace.read(cx).project().clone();
18615        let references =
18616            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18617        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18618            let Some(locations) = references.await? else {
18619                return Ok(());
18620            };
18621
18622            if locations.is_empty() {
18623                // totally normal - the cursor may be on something which is not
18624                // a symbol (e.g. a keyword)
18625                log::info!("no references found under cursor");
18626                return Ok(());
18627            }
18628
18629            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18630
18631            let (locations, current_location_index) =
18632                multi_buffer.update(cx, |multi_buffer, cx| {
18633                    let mut locations = locations
18634                        .into_iter()
18635                        .filter_map(|loc| {
18636                            let start = multi_buffer.buffer_anchor_to_anchor(
18637                                &loc.buffer,
18638                                loc.range.start,
18639                                cx,
18640                            )?;
18641                            let end = multi_buffer.buffer_anchor_to_anchor(
18642                                &loc.buffer,
18643                                loc.range.end,
18644                                cx,
18645                            )?;
18646                            Some(start..end)
18647                        })
18648                        .collect::<Vec<_>>();
18649
18650                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18651                    // There is an O(n) implementation, but given this list will be
18652                    // small (usually <100 items), the extra O(log(n)) factor isn't
18653                    // worth the (surprisingly large amount of) extra complexity.
18654                    locations
18655                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18656
18657                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18658
18659                    let current_location_index = locations.iter().position(|loc| {
18660                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18661                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18662                    });
18663
18664                    (locations, current_location_index)
18665                });
18666
18667            let Some(current_location_index) = current_location_index else {
18668                // This indicates something has gone wrong, because we already
18669                // handle the "no references" case above
18670                log::error!(
18671                    "failed to find current reference under cursor. Total references: {}",
18672                    locations.len()
18673                );
18674                return Ok(());
18675            };
18676
18677            let destination_location_index = match direction {
18678                Direction::Next => (current_location_index + count) % locations.len(),
18679                Direction::Prev => {
18680                    (current_location_index + locations.len() - count % locations.len())
18681                        % locations.len()
18682                }
18683            };
18684
18685            // TODO(cameron): is this needed?
18686            // the thinking is to avoid "jumping to the current location" (avoid
18687            // polluting "jumplist" in vim terms)
18688            if current_location_index == destination_location_index {
18689                return Ok(());
18690            }
18691
18692            let Range { start, end } = locations[destination_location_index];
18693
18694            editor.update_in(cx, |editor, window, cx| {
18695                let effects = SelectionEffects::default();
18696
18697                editor.unfold_ranges(&[start..end], false, false, cx);
18698                editor.change_selections(effects, window, cx, |s| {
18699                    s.select_ranges([start..start]);
18700                });
18701            })?;
18702
18703            Ok(())
18704        }))
18705    }
18706
18707    pub fn find_all_references(
18708        &mut self,
18709        action: &FindAllReferences,
18710        window: &mut Window,
18711        cx: &mut Context<Self>,
18712    ) -> Option<Task<Result<Navigated>>> {
18713        let always_open_multibuffer = action.always_open_multibuffer;
18714        let selection = self.selections.newest_anchor();
18715        let multi_buffer = self.buffer.read(cx);
18716        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18717        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18718        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18719        let head = selection_offset.head();
18720
18721        let head_anchor = multi_buffer_snapshot.anchor_at(
18722            head,
18723            if head < selection_offset.tail() {
18724                Bias::Right
18725            } else {
18726                Bias::Left
18727            },
18728        );
18729
18730        match self
18731            .find_all_references_task_sources
18732            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18733        {
18734            Ok(_) => {
18735                log::info!(
18736                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18737                );
18738                return None;
18739            }
18740            Err(i) => {
18741                self.find_all_references_task_sources.insert(i, head_anchor);
18742            }
18743        }
18744
18745        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18746        let workspace = self.workspace()?;
18747        let project = workspace.read(cx).project().clone();
18748        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18749        Some(cx.spawn_in(window, async move |editor, cx| {
18750            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18751                if let Ok(i) = editor
18752                    .find_all_references_task_sources
18753                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18754                {
18755                    editor.find_all_references_task_sources.remove(i);
18756                }
18757            });
18758
18759            let Some(locations) = references.await? else {
18760                return anyhow::Ok(Navigated::No);
18761            };
18762            let mut locations = cx.update(|_, cx| {
18763                locations
18764                    .into_iter()
18765                    .map(|location| {
18766                        let buffer = location.buffer.read(cx);
18767                        (location.buffer, location.range.to_point(buffer))
18768                    })
18769                    // if special-casing the single-match case, remove ranges
18770                    // that intersect current selection
18771                    .filter(|(location_buffer, location)| {
18772                        if always_open_multibuffer || &buffer != location_buffer {
18773                            return true;
18774                        }
18775
18776                        !location.contains_inclusive(&selection_point.range())
18777                    })
18778                    .into_group_map()
18779            })?;
18780            if locations.is_empty() {
18781                return anyhow::Ok(Navigated::No);
18782            }
18783            for ranges in locations.values_mut() {
18784                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18785                ranges.dedup();
18786            }
18787            let mut num_locations = 0;
18788            for ranges in locations.values_mut() {
18789                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18790                ranges.dedup();
18791                num_locations += ranges.len();
18792            }
18793
18794            if num_locations == 1 && !always_open_multibuffer {
18795                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18796                let target_range = target_ranges.first().unwrap().clone();
18797
18798                return editor.update_in(cx, |editor, window, cx| {
18799                    let range = target_range.to_point(target_buffer.read(cx));
18800                    let range = editor.range_for_match(&range);
18801                    let range = range.start..range.start;
18802
18803                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18804                        editor.go_to_singleton_buffer_range(range, window, cx);
18805                    } else {
18806                        let pane = workspace.read(cx).active_pane().clone();
18807                        window.defer(cx, move |window, cx| {
18808                            let target_editor: Entity<Self> =
18809                                workspace.update(cx, |workspace, cx| {
18810                                    let pane = workspace.active_pane().clone();
18811
18812                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18813                                    let keep_old_preview = preview_tabs_settings
18814                                        .enable_keep_preview_on_code_navigation;
18815                                    let allow_new_preview = preview_tabs_settings
18816                                        .enable_preview_file_from_code_navigation;
18817
18818                                    workspace.open_project_item(
18819                                        pane,
18820                                        target_buffer.clone(),
18821                                        true,
18822                                        true,
18823                                        keep_old_preview,
18824                                        allow_new_preview,
18825                                        window,
18826                                        cx,
18827                                    )
18828                                });
18829                            target_editor.update(cx, |target_editor, cx| {
18830                                // When selecting a definition in a different buffer, disable the nav history
18831                                // to avoid creating a history entry at the previous cursor location.
18832                                pane.update(cx, |pane, _| pane.disable_history());
18833                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18834                                pane.update(cx, |pane, _| pane.enable_history());
18835                            });
18836                        });
18837                    }
18838                    Navigated::No
18839                });
18840            }
18841
18842            workspace.update_in(cx, |workspace, window, cx| {
18843                let target = locations
18844                    .iter()
18845                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18846                    .map(|(buffer, location)| {
18847                        buffer
18848                            .read(cx)
18849                            .text_for_range(location.clone())
18850                            .collect::<String>()
18851                    })
18852                    .filter(|text| !text.contains('\n'))
18853                    .unique()
18854                    .take(3)
18855                    .join(", ");
18856                let title = if target.is_empty() {
18857                    "References".to_owned()
18858                } else {
18859                    format!("References to {target}")
18860                };
18861                let allow_preview = PreviewTabsSettings::get_global(cx)
18862                    .enable_preview_multibuffer_from_code_navigation;
18863                Self::open_locations_in_multibuffer(
18864                    workspace,
18865                    locations,
18866                    title,
18867                    false,
18868                    allow_preview,
18869                    MultibufferSelectionMode::First,
18870                    window,
18871                    cx,
18872                );
18873                Navigated::Yes
18874            })
18875        }))
18876    }
18877
18878    /// Opens a multibuffer with the given project locations in it.
18879    pub fn open_locations_in_multibuffer(
18880        workspace: &mut Workspace,
18881        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18882        title: String,
18883        split: bool,
18884        allow_preview: bool,
18885        multibuffer_selection_mode: MultibufferSelectionMode,
18886        window: &mut Window,
18887        cx: &mut Context<Workspace>,
18888    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18889        if locations.is_empty() {
18890            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18891            return None;
18892        }
18893
18894        let capability = workspace.project().read(cx).capability();
18895        let mut ranges = <Vec<Range<Anchor>>>::new();
18896
18897        // a key to find existing multibuffer editors with the same set of locations
18898        // to prevent us from opening more and more multibuffer tabs for searches and the like
18899        let mut key = (title.clone(), vec![]);
18900        let excerpt_buffer = cx.new(|cx| {
18901            let key = &mut key.1;
18902            let mut multibuffer = MultiBuffer::new(capability);
18903            for (buffer, mut ranges_for_buffer) in locations {
18904                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18905                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18906                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18907                    PathKey::for_buffer(&buffer, cx),
18908                    buffer.clone(),
18909                    ranges_for_buffer,
18910                    multibuffer_context_lines(cx),
18911                    cx,
18912                );
18913                ranges.extend(new_ranges)
18914            }
18915
18916            multibuffer.with_title(title)
18917        });
18918        let existing = workspace.active_pane().update(cx, |pane, cx| {
18919            pane.items()
18920                .filter_map(|item| item.downcast::<Editor>())
18921                .find(|editor| {
18922                    editor
18923                        .read(cx)
18924                        .lookup_key
18925                        .as_ref()
18926                        .and_then(|it| {
18927                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18928                        })
18929                        .is_some_and(|it| *it == key)
18930                })
18931        });
18932        let was_existing = existing.is_some();
18933        let editor = existing.unwrap_or_else(|| {
18934            cx.new(|cx| {
18935                let mut editor = Editor::for_multibuffer(
18936                    excerpt_buffer,
18937                    Some(workspace.project().clone()),
18938                    window,
18939                    cx,
18940                );
18941                editor.lookup_key = Some(Box::new(key));
18942                editor
18943            })
18944        });
18945        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18946            MultibufferSelectionMode::First => {
18947                if let Some(first_range) = ranges.first() {
18948                    editor.change_selections(
18949                        SelectionEffects::no_scroll(),
18950                        window,
18951                        cx,
18952                        |selections| {
18953                            selections.clear_disjoint();
18954                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18955                        },
18956                    );
18957                }
18958                editor.highlight_background(
18959                    HighlightKey::Editor,
18960                    &ranges,
18961                    |_, theme| theme.colors().editor_highlighted_line_background,
18962                    cx,
18963                );
18964            }
18965            MultibufferSelectionMode::All => {
18966                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18967                    selections.clear_disjoint();
18968                    selections.select_anchor_ranges(ranges);
18969                });
18970            }
18971        });
18972
18973        let item = Box::new(editor.clone());
18974
18975        let pane = if split {
18976            workspace.adjacent_pane(window, cx)
18977        } else {
18978            workspace.active_pane().clone()
18979        };
18980        let activate_pane = split;
18981
18982        let mut destination_index = None;
18983        pane.update(cx, |pane, cx| {
18984            if allow_preview && !was_existing {
18985                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18986            }
18987            if was_existing && !allow_preview {
18988                pane.unpreview_item_if_preview(item.item_id());
18989            }
18990            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18991        });
18992
18993        Some((editor, pane))
18994    }
18995
18996    pub fn rename(
18997        &mut self,
18998        _: &Rename,
18999        window: &mut Window,
19000        cx: &mut Context<Self>,
19001    ) -> Option<Task<Result<()>>> {
19002        use language::ToOffset as _;
19003
19004        let provider = self.semantics_provider.clone()?;
19005        let selection = self.selections.newest_anchor().clone();
19006        let (cursor_buffer, cursor_buffer_position) = self
19007            .buffer
19008            .read(cx)
19009            .text_anchor_for_position(selection.head(), cx)?;
19010        let (tail_buffer, cursor_buffer_position_end) = self
19011            .buffer
19012            .read(cx)
19013            .text_anchor_for_position(selection.tail(), cx)?;
19014        if tail_buffer != cursor_buffer {
19015            return None;
19016        }
19017
19018        let snapshot = cursor_buffer.read(cx).snapshot();
19019        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19020        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19021        let prepare_rename = provider
19022            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
19023            .unwrap_or_else(|| Task::ready(Ok(None)));
19024        drop(snapshot);
19025
19026        Some(cx.spawn_in(window, async move |this, cx| {
19027            let rename_range = if let Some(range) = prepare_rename.await? {
19028                Some(range)
19029            } else {
19030                this.update(cx, |this, cx| {
19031                    let buffer = this.buffer.read(cx).snapshot(cx);
19032                    let mut buffer_highlights = this
19033                        .document_highlights_for_position(selection.head(), &buffer)
19034                        .filter(|highlight| {
19035                            highlight.start.excerpt_id == selection.head().excerpt_id
19036                                && highlight.end.excerpt_id == selection.head().excerpt_id
19037                        });
19038                    buffer_highlights
19039                        .next()
19040                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
19041                })?
19042            };
19043            if let Some(rename_range) = rename_range {
19044                this.update_in(cx, |this, window, cx| {
19045                    let snapshot = cursor_buffer.read(cx).snapshot();
19046                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19047                    let cursor_offset_in_rename_range =
19048                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19049                    let cursor_offset_in_rename_range_end =
19050                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19051
19052                    this.take_rename(false, window, cx);
19053                    let buffer = this.buffer.read(cx).read(cx);
19054                    let cursor_offset = selection.head().to_offset(&buffer);
19055                    let rename_start =
19056                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19057                    let rename_end = rename_start + rename_buffer_range.len();
19058                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19059                    let mut old_highlight_id = None;
19060                    let old_name: Arc<str> = buffer
19061                        .chunks(rename_start..rename_end, true)
19062                        .map(|chunk| {
19063                            if old_highlight_id.is_none() {
19064                                old_highlight_id = chunk.syntax_highlight_id;
19065                            }
19066                            chunk.text
19067                        })
19068                        .collect::<String>()
19069                        .into();
19070
19071                    drop(buffer);
19072
19073                    // Position the selection in the rename editor so that it matches the current selection.
19074                    this.show_local_selections = false;
19075                    let rename_editor = cx.new(|cx| {
19076                        let mut editor = Editor::single_line(window, cx);
19077                        editor.buffer.update(cx, |buffer, cx| {
19078                            buffer.edit(
19079                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19080                                None,
19081                                cx,
19082                            )
19083                        });
19084                        let cursor_offset_in_rename_range =
19085                            MultiBufferOffset(cursor_offset_in_rename_range);
19086                        let cursor_offset_in_rename_range_end =
19087                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19088                        let rename_selection_range = match cursor_offset_in_rename_range
19089                            .cmp(&cursor_offset_in_rename_range_end)
19090                        {
19091                            Ordering::Equal => {
19092                                editor.select_all(&SelectAll, window, cx);
19093                                return editor;
19094                            }
19095                            Ordering::Less => {
19096                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19097                            }
19098                            Ordering::Greater => {
19099                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19100                            }
19101                        };
19102                        if rename_selection_range.end.0 > old_name.len() {
19103                            editor.select_all(&SelectAll, window, cx);
19104                        } else {
19105                            editor.change_selections(Default::default(), window, cx, |s| {
19106                                s.select_ranges([rename_selection_range]);
19107                            });
19108                        }
19109                        editor
19110                    });
19111                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19112                        if e == &EditorEvent::Focused {
19113                            cx.emit(EditorEvent::FocusedIn)
19114                        }
19115                    })
19116                    .detach();
19117
19118                    let write_highlights =
19119                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19120                    let read_highlights =
19121                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19122                    let ranges = write_highlights
19123                        .iter()
19124                        .flat_map(|(_, ranges)| ranges.iter())
19125                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19126                        .cloned()
19127                        .collect();
19128
19129                    this.highlight_text(
19130                        HighlightKey::Rename,
19131                        ranges,
19132                        HighlightStyle {
19133                            fade_out: Some(0.6),
19134                            ..Default::default()
19135                        },
19136                        cx,
19137                    );
19138                    let rename_focus_handle = rename_editor.focus_handle(cx);
19139                    window.focus(&rename_focus_handle, cx);
19140                    let block_id = this.insert_blocks(
19141                        [BlockProperties {
19142                            style: BlockStyle::Flex,
19143                            placement: BlockPlacement::Below(range.start),
19144                            height: Some(1),
19145                            render: Arc::new({
19146                                let rename_editor = rename_editor.clone();
19147                                move |cx: &mut BlockContext| {
19148                                    let mut text_style = cx.editor_style.text.clone();
19149                                    if let Some(highlight_style) = old_highlight_id
19150                                        .and_then(|h| h.style(&cx.editor_style.syntax))
19151                                    {
19152                                        text_style = text_style.highlight(highlight_style);
19153                                    }
19154                                    div()
19155                                        .block_mouse_except_scroll()
19156                                        .pl(cx.anchor_x)
19157                                        .child(EditorElement::new(
19158                                            &rename_editor,
19159                                            EditorStyle {
19160                                                background: cx.theme().system().transparent,
19161                                                local_player: cx.editor_style.local_player,
19162                                                text: text_style,
19163                                                scrollbar_width: cx.editor_style.scrollbar_width,
19164                                                syntax: cx.editor_style.syntax.clone(),
19165                                                status: cx.editor_style.status.clone(),
19166                                                inlay_hints_style: HighlightStyle {
19167                                                    font_weight: Some(FontWeight::BOLD),
19168                                                    ..make_inlay_hints_style(cx.app)
19169                                                },
19170                                                edit_prediction_styles: make_suggestion_styles(
19171                                                    cx.app,
19172                                                ),
19173                                                ..EditorStyle::default()
19174                                            },
19175                                        ))
19176                                        .into_any_element()
19177                                }
19178                            }),
19179                            priority: 0,
19180                        }],
19181                        Some(Autoscroll::fit()),
19182                        cx,
19183                    )[0];
19184                    this.pending_rename = Some(RenameState {
19185                        range,
19186                        old_name,
19187                        editor: rename_editor,
19188                        block_id,
19189                    });
19190                })?;
19191            }
19192
19193            Ok(())
19194        }))
19195    }
19196
19197    pub fn confirm_rename(
19198        &mut self,
19199        _: &ConfirmRename,
19200        window: &mut Window,
19201        cx: &mut Context<Self>,
19202    ) -> Option<Task<Result<()>>> {
19203        let rename = self.take_rename(false, window, cx)?;
19204        let workspace = self.workspace()?.downgrade();
19205        let (buffer, start) = self
19206            .buffer
19207            .read(cx)
19208            .text_anchor_for_position(rename.range.start, cx)?;
19209        let (end_buffer, _) = self
19210            .buffer
19211            .read(cx)
19212            .text_anchor_for_position(rename.range.end, cx)?;
19213        if buffer != end_buffer {
19214            return None;
19215        }
19216
19217        let old_name = rename.old_name;
19218        let new_name = rename.editor.read(cx).text(cx);
19219
19220        let rename = self.semantics_provider.as_ref()?.perform_rename(
19221            &buffer,
19222            start,
19223            new_name.clone(),
19224            cx,
19225        )?;
19226
19227        Some(cx.spawn_in(window, async move |editor, cx| {
19228            let project_transaction = rename.await?;
19229            Self::open_project_transaction(
19230                &editor,
19231                workspace,
19232                project_transaction,
19233                format!("Rename: {}{}", old_name, new_name),
19234                cx,
19235            )
19236            .await?;
19237
19238            editor.update(cx, |editor, cx| {
19239                editor.refresh_document_highlights(cx);
19240            })?;
19241            Ok(())
19242        }))
19243    }
19244
19245    fn take_rename(
19246        &mut self,
19247        moving_cursor: bool,
19248        window: &mut Window,
19249        cx: &mut Context<Self>,
19250    ) -> Option<RenameState> {
19251        let rename = self.pending_rename.take()?;
19252        if rename.editor.focus_handle(cx).is_focused(window) {
19253            window.focus(&self.focus_handle, cx);
19254        }
19255
19256        self.remove_blocks(
19257            [rename.block_id].into_iter().collect(),
19258            Some(Autoscroll::fit()),
19259            cx,
19260        );
19261        self.clear_highlights(HighlightKey::Rename, cx);
19262        self.show_local_selections = true;
19263
19264        if moving_cursor {
19265            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19266                editor
19267                    .selections
19268                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19269                    .head()
19270            });
19271
19272            // Update the selection to match the position of the selection inside
19273            // the rename editor.
19274            let snapshot = self.buffer.read(cx).read(cx);
19275            let rename_range = rename.range.to_offset(&snapshot);
19276            let cursor_in_editor = snapshot
19277                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19278                .min(rename_range.end);
19279            drop(snapshot);
19280
19281            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19282                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19283            });
19284        } else {
19285            self.refresh_document_highlights(cx);
19286        }
19287
19288        Some(rename)
19289    }
19290
19291    pub fn pending_rename(&self) -> Option<&RenameState> {
19292        self.pending_rename.as_ref()
19293    }
19294
19295    fn format(
19296        &mut self,
19297        _: &Format,
19298        window: &mut Window,
19299        cx: &mut Context<Self>,
19300    ) -> Option<Task<Result<()>>> {
19301        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19302
19303        let project = match &self.project {
19304            Some(project) => project.clone(),
19305            None => return None,
19306        };
19307
19308        Some(self.perform_format(
19309            project,
19310            FormatTrigger::Manual,
19311            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19312            window,
19313            cx,
19314        ))
19315    }
19316
19317    fn format_selections(
19318        &mut self,
19319        _: &FormatSelections,
19320        window: &mut Window,
19321        cx: &mut Context<Self>,
19322    ) -> Option<Task<Result<()>>> {
19323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19324
19325        let project = match &self.project {
19326            Some(project) => project.clone(),
19327            None => return None,
19328        };
19329
19330        let ranges = self
19331            .selections
19332            .all_adjusted(&self.display_snapshot(cx))
19333            .into_iter()
19334            .map(|selection| selection.range())
19335            .collect_vec();
19336
19337        Some(self.perform_format(
19338            project,
19339            FormatTrigger::Manual,
19340            FormatTarget::Ranges(ranges),
19341            window,
19342            cx,
19343        ))
19344    }
19345
19346    fn perform_format(
19347        &mut self,
19348        project: Entity<Project>,
19349        trigger: FormatTrigger,
19350        target: FormatTarget,
19351        window: &mut Window,
19352        cx: &mut Context<Self>,
19353    ) -> Task<Result<()>> {
19354        let buffer = self.buffer.clone();
19355        let (buffers, target) = match target {
19356            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19357            FormatTarget::Ranges(selection_ranges) => {
19358                let multi_buffer = buffer.read(cx);
19359                let snapshot = multi_buffer.read(cx);
19360                let mut buffers = HashSet::default();
19361                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19362                    BTreeMap::new();
19363                for selection_range in selection_ranges {
19364                    for (buffer, buffer_range, _) in
19365                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
19366                    {
19367                        let buffer_id = buffer.remote_id();
19368                        let start = buffer.anchor_before(buffer_range.start);
19369                        let end = buffer.anchor_after(buffer_range.end);
19370                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19371                        buffer_id_to_ranges
19372                            .entry(buffer_id)
19373                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19374                            .or_insert_with(|| vec![start..end]);
19375                    }
19376                }
19377                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19378            }
19379        };
19380
19381        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19382        let selections_prev = transaction_id_prev
19383            .and_then(|transaction_id_prev| {
19384                // default to selections as they were after the last edit, if we have them,
19385                // instead of how they are now.
19386                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19387                // will take you back to where you made the last edit, instead of staying where you scrolled
19388                self.selection_history
19389                    .transaction(transaction_id_prev)
19390                    .map(|t| t.0.clone())
19391            })
19392            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19393
19394        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19395        let format = project.update(cx, |project, cx| {
19396            project.format(buffers, target, true, trigger, cx)
19397        });
19398
19399        cx.spawn_in(window, async move |editor, cx| {
19400            let transaction = futures::select_biased! {
19401                transaction = format.log_err().fuse() => transaction,
19402                () = timeout => {
19403                    log::warn!("timed out waiting for formatting");
19404                    None
19405                }
19406            };
19407
19408            buffer.update(cx, |buffer, cx| {
19409                if let Some(transaction) = transaction
19410                    && !buffer.is_singleton()
19411                {
19412                    buffer.push_transaction(&transaction.0, cx);
19413                }
19414                cx.notify();
19415            });
19416
19417            if let Some(transaction_id_now) =
19418                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19419            {
19420                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19421                if has_new_transaction {
19422                    editor
19423                        .update(cx, |editor, _| {
19424                            editor
19425                                .selection_history
19426                                .insert_transaction(transaction_id_now, selections_prev);
19427                        })
19428                        .ok();
19429                }
19430            }
19431
19432            Ok(())
19433        })
19434    }
19435
19436    fn organize_imports(
19437        &mut self,
19438        _: &OrganizeImports,
19439        window: &mut Window,
19440        cx: &mut Context<Self>,
19441    ) -> Option<Task<Result<()>>> {
19442        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19443        let project = match &self.project {
19444            Some(project) => project.clone(),
19445            None => return None,
19446        };
19447        Some(self.perform_code_action_kind(
19448            project,
19449            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19450            window,
19451            cx,
19452        ))
19453    }
19454
19455    fn perform_code_action_kind(
19456        &mut self,
19457        project: Entity<Project>,
19458        kind: CodeActionKind,
19459        window: &mut Window,
19460        cx: &mut Context<Self>,
19461    ) -> Task<Result<()>> {
19462        let buffer = self.buffer.clone();
19463        let buffers = buffer.read(cx).all_buffers();
19464        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19465        let apply_action = project.update(cx, |project, cx| {
19466            project.apply_code_action_kind(buffers, kind, true, cx)
19467        });
19468        cx.spawn_in(window, async move |_, cx| {
19469            let transaction = futures::select_biased! {
19470                () = timeout => {
19471                    log::warn!("timed out waiting for executing code action");
19472                    None
19473                }
19474                transaction = apply_action.log_err().fuse() => transaction,
19475            };
19476            buffer.update(cx, |buffer, cx| {
19477                // check if we need this
19478                if let Some(transaction) = transaction
19479                    && !buffer.is_singleton()
19480                {
19481                    buffer.push_transaction(&transaction.0, cx);
19482                }
19483                cx.notify();
19484            });
19485            Ok(())
19486        })
19487    }
19488
19489    pub fn restart_language_server(
19490        &mut self,
19491        _: &RestartLanguageServer,
19492        _: &mut Window,
19493        cx: &mut Context<Self>,
19494    ) {
19495        if let Some(project) = self.project.clone() {
19496            self.buffer.update(cx, |multi_buffer, cx| {
19497                project.update(cx, |project, cx| {
19498                    project.restart_language_servers_for_buffers(
19499                        multi_buffer.all_buffers().into_iter().collect(),
19500                        HashSet::default(),
19501                        cx,
19502                    );
19503                });
19504            })
19505        }
19506    }
19507
19508    pub fn stop_language_server(
19509        &mut self,
19510        _: &StopLanguageServer,
19511        _: &mut Window,
19512        cx: &mut Context<Self>,
19513    ) {
19514        if let Some(project) = self.project.clone() {
19515            self.buffer.update(cx, |multi_buffer, cx| {
19516                project.update(cx, |project, cx| {
19517                    project.stop_language_servers_for_buffers(
19518                        multi_buffer.all_buffers().into_iter().collect(),
19519                        HashSet::default(),
19520                        cx,
19521                    );
19522                });
19523            });
19524        }
19525    }
19526
19527    fn cancel_language_server_work(
19528        workspace: &mut Workspace,
19529        _: &actions::CancelLanguageServerWork,
19530        _: &mut Window,
19531        cx: &mut Context<Workspace>,
19532    ) {
19533        let project = workspace.project();
19534        let buffers = workspace
19535            .active_item(cx)
19536            .and_then(|item| item.act_as::<Editor>(cx))
19537            .map_or(HashSet::default(), |editor| {
19538                editor.read(cx).buffer.read(cx).all_buffers()
19539            });
19540        project.update(cx, |project, cx| {
19541            project.cancel_language_server_work_for_buffers(buffers, cx);
19542        });
19543    }
19544
19545    fn show_character_palette(
19546        &mut self,
19547        _: &ShowCharacterPalette,
19548        window: &mut Window,
19549        _: &mut Context<Self>,
19550    ) {
19551        window.show_character_palette();
19552    }
19553
19554    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19555        if !self.diagnostics_enabled() {
19556            return;
19557        }
19558
19559        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19560            let buffer = self.buffer.read(cx).snapshot(cx);
19561            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19562            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19563            let is_valid = buffer
19564                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19565                .any(|entry| {
19566                    entry.diagnostic.is_primary
19567                        && !entry.range.is_empty()
19568                        && entry.range.start == primary_range_start
19569                        && entry.diagnostic.message == active_diagnostics.active_message
19570                });
19571
19572            if !is_valid {
19573                self.dismiss_diagnostics(cx);
19574            }
19575        }
19576    }
19577
19578    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19579        match &self.active_diagnostics {
19580            ActiveDiagnostic::Group(group) => Some(group),
19581            _ => None,
19582        }
19583    }
19584
19585    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19586        if !self.diagnostics_enabled() {
19587            return;
19588        }
19589        self.dismiss_diagnostics(cx);
19590        self.active_diagnostics = ActiveDiagnostic::All;
19591    }
19592
19593    fn activate_diagnostics(
19594        &mut self,
19595        buffer_id: BufferId,
19596        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19597        window: &mut Window,
19598        cx: &mut Context<Self>,
19599    ) {
19600        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19601            return;
19602        }
19603        self.dismiss_diagnostics(cx);
19604        let snapshot = self.snapshot(window, cx);
19605        let buffer = self.buffer.read(cx).snapshot(cx);
19606        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19607            return;
19608        };
19609
19610        let diagnostic_group = buffer
19611            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19612            .collect::<Vec<_>>();
19613
19614        let language_registry = self
19615            .project()
19616            .map(|project| project.read(cx).languages().clone());
19617
19618        let blocks = renderer.render_group(
19619            diagnostic_group,
19620            buffer_id,
19621            snapshot,
19622            cx.weak_entity(),
19623            language_registry,
19624            cx,
19625        );
19626
19627        let blocks = self.display_map.update(cx, |display_map, cx| {
19628            display_map.insert_blocks(blocks, cx).into_iter().collect()
19629        });
19630        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19631            active_range: buffer.anchor_before(diagnostic.range.start)
19632                ..buffer.anchor_after(diagnostic.range.end),
19633            active_message: diagnostic.diagnostic.message.clone(),
19634            group_id: diagnostic.diagnostic.group_id,
19635            blocks,
19636        });
19637        cx.notify();
19638    }
19639
19640    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19641        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19642            return;
19643        };
19644
19645        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19646        if let ActiveDiagnostic::Group(group) = prev {
19647            self.display_map.update(cx, |display_map, cx| {
19648                display_map.remove_blocks(group.blocks, cx);
19649            });
19650            cx.notify();
19651        }
19652    }
19653
19654    /// Disable inline diagnostics rendering for this editor.
19655    pub fn disable_inline_diagnostics(&mut self) {
19656        self.inline_diagnostics_enabled = false;
19657        self.inline_diagnostics_update = Task::ready(());
19658        self.inline_diagnostics.clear();
19659    }
19660
19661    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19662        self.diagnostics_enabled = false;
19663        self.dismiss_diagnostics(cx);
19664        self.inline_diagnostics_update = Task::ready(());
19665        self.inline_diagnostics.clear();
19666    }
19667
19668    pub fn disable_word_completions(&mut self) {
19669        self.word_completions_enabled = false;
19670    }
19671
19672    pub fn diagnostics_enabled(&self) -> bool {
19673        self.diagnostics_enabled && self.lsp_data_enabled()
19674    }
19675
19676    pub fn inline_diagnostics_enabled(&self) -> bool {
19677        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19678    }
19679
19680    pub fn show_inline_diagnostics(&self) -> bool {
19681        self.show_inline_diagnostics
19682    }
19683
19684    pub fn toggle_inline_diagnostics(
19685        &mut self,
19686        _: &ToggleInlineDiagnostics,
19687        window: &mut Window,
19688        cx: &mut Context<Editor>,
19689    ) {
19690        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19691        self.refresh_inline_diagnostics(false, window, cx);
19692    }
19693
19694    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19695        self.diagnostics_max_severity = severity;
19696        self.display_map.update(cx, |display_map, _| {
19697            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19698        });
19699    }
19700
19701    pub fn toggle_diagnostics(
19702        &mut self,
19703        _: &ToggleDiagnostics,
19704        window: &mut Window,
19705        cx: &mut Context<Editor>,
19706    ) {
19707        if !self.diagnostics_enabled() {
19708            return;
19709        }
19710
19711        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19712            EditorSettings::get_global(cx)
19713                .diagnostics_max_severity
19714                .filter(|severity| severity != &DiagnosticSeverity::Off)
19715                .unwrap_or(DiagnosticSeverity::Hint)
19716        } else {
19717            DiagnosticSeverity::Off
19718        };
19719        self.set_max_diagnostics_severity(new_severity, cx);
19720        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19721            self.active_diagnostics = ActiveDiagnostic::None;
19722            self.inline_diagnostics_update = Task::ready(());
19723            self.inline_diagnostics.clear();
19724        } else {
19725            self.refresh_inline_diagnostics(false, window, cx);
19726        }
19727
19728        cx.notify();
19729    }
19730
19731    pub fn toggle_minimap(
19732        &mut self,
19733        _: &ToggleMinimap,
19734        window: &mut Window,
19735        cx: &mut Context<Editor>,
19736    ) {
19737        if self.supports_minimap(cx) {
19738            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19739        }
19740    }
19741
19742    fn refresh_inline_diagnostics(
19743        &mut self,
19744        debounce: bool,
19745        window: &mut Window,
19746        cx: &mut Context<Self>,
19747    ) {
19748        let max_severity = ProjectSettings::get_global(cx)
19749            .diagnostics
19750            .inline
19751            .max_severity
19752            .unwrap_or(self.diagnostics_max_severity);
19753
19754        if !self.inline_diagnostics_enabled()
19755            || !self.diagnostics_enabled()
19756            || !self.show_inline_diagnostics
19757            || max_severity == DiagnosticSeverity::Off
19758        {
19759            self.inline_diagnostics_update = Task::ready(());
19760            self.inline_diagnostics.clear();
19761            return;
19762        }
19763
19764        let debounce_ms = ProjectSettings::get_global(cx)
19765            .diagnostics
19766            .inline
19767            .update_debounce_ms;
19768        let debounce = if debounce && debounce_ms > 0 {
19769            Some(Duration::from_millis(debounce_ms))
19770        } else {
19771            None
19772        };
19773        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19774            if let Some(debounce) = debounce {
19775                cx.background_executor().timer(debounce).await;
19776            }
19777            let Some(snapshot) = editor.upgrade().map(|editor| {
19778                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19779            }) else {
19780                return;
19781            };
19782
19783            let new_inline_diagnostics = cx
19784                .background_spawn(async move {
19785                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19786                    for diagnostic_entry in
19787                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19788                    {
19789                        let message = diagnostic_entry
19790                            .diagnostic
19791                            .message
19792                            .split_once('\n')
19793                            .map(|(line, _)| line)
19794                            .map(SharedString::new)
19795                            .unwrap_or_else(|| {
19796                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19797                            });
19798                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19799                        let (Ok(i) | Err(i)) = inline_diagnostics
19800                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19801                        inline_diagnostics.insert(
19802                            i,
19803                            (
19804                                start_anchor,
19805                                InlineDiagnostic {
19806                                    message,
19807                                    group_id: diagnostic_entry.diagnostic.group_id,
19808                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19809                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19810                                    severity: diagnostic_entry.diagnostic.severity,
19811                                },
19812                            ),
19813                        );
19814                    }
19815                    inline_diagnostics
19816                })
19817                .await;
19818
19819            editor
19820                .update(cx, |editor, cx| {
19821                    editor.inline_diagnostics = new_inline_diagnostics;
19822                    cx.notify();
19823                })
19824                .ok();
19825        });
19826    }
19827
19828    fn pull_diagnostics(
19829        &mut self,
19830        buffer_id: BufferId,
19831        _window: &Window,
19832        cx: &mut Context<Self>,
19833    ) -> Option<()> {
19834        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19835        // skip any LSP updates for it.
19836
19837        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19838            return None;
19839        }
19840        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19841            .diagnostics
19842            .lsp_pull_diagnostics;
19843        if !pull_diagnostics_settings.enabled {
19844            return None;
19845        }
19846        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19847        let project = self.project()?.downgrade();
19848        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19849
19850        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19851            cx.background_executor().timer(debounce).await;
19852            if let Ok(task) = project.update(cx, |project, cx| {
19853                project.lsp_store().update(cx, |lsp_store, cx| {
19854                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19855                })
19856            }) {
19857                task.await.log_err();
19858            }
19859            project
19860                .update(cx, |project, cx| {
19861                    project.lsp_store().update(cx, |lsp_store, cx| {
19862                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19863                    })
19864                })
19865                .log_err();
19866        });
19867
19868        Some(())
19869    }
19870
19871    pub fn set_selections_from_remote(
19872        &mut self,
19873        selections: Vec<Selection<Anchor>>,
19874        pending_selection: Option<Selection<Anchor>>,
19875        window: &mut Window,
19876        cx: &mut Context<Self>,
19877    ) {
19878        let old_cursor_position = self.selections.newest_anchor().head();
19879        self.selections
19880            .change_with(&self.display_snapshot(cx), |s| {
19881                s.select_anchors(selections);
19882                if let Some(pending_selection) = pending_selection {
19883                    s.set_pending(pending_selection, SelectMode::Character);
19884                } else {
19885                    s.clear_pending();
19886                }
19887            });
19888        self.selections_did_change(
19889            false,
19890            &old_cursor_position,
19891            SelectionEffects::default(),
19892            window,
19893            cx,
19894        );
19895    }
19896
19897    pub fn transact(
19898        &mut self,
19899        window: &mut Window,
19900        cx: &mut Context<Self>,
19901        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19902    ) -> Option<TransactionId> {
19903        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19904            this.start_transaction_at(Instant::now(), window, cx);
19905            update(this, window, cx);
19906            this.end_transaction_at(Instant::now(), cx)
19907        })
19908    }
19909
19910    pub fn start_transaction_at(
19911        &mut self,
19912        now: Instant,
19913        window: &mut Window,
19914        cx: &mut Context<Self>,
19915    ) -> Option<TransactionId> {
19916        self.end_selection(window, cx);
19917        if let Some(tx_id) = self
19918            .buffer
19919            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19920        {
19921            self.selection_history
19922                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19923            cx.emit(EditorEvent::TransactionBegun {
19924                transaction_id: tx_id,
19925            });
19926            Some(tx_id)
19927        } else {
19928            None
19929        }
19930    }
19931
19932    pub fn end_transaction_at(
19933        &mut self,
19934        now: Instant,
19935        cx: &mut Context<Self>,
19936    ) -> Option<TransactionId> {
19937        if let Some(transaction_id) = self
19938            .buffer
19939            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19940        {
19941            if let Some((_, end_selections)) =
19942                self.selection_history.transaction_mut(transaction_id)
19943            {
19944                *end_selections = Some(self.selections.disjoint_anchors_arc());
19945            } else {
19946                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19947            }
19948
19949            cx.emit(EditorEvent::Edited { transaction_id });
19950            Some(transaction_id)
19951        } else {
19952            None
19953        }
19954    }
19955
19956    pub fn modify_transaction_selection_history(
19957        &mut self,
19958        transaction_id: TransactionId,
19959        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19960    ) -> bool {
19961        self.selection_history
19962            .transaction_mut(transaction_id)
19963            .map(modify)
19964            .is_some()
19965    }
19966
19967    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19968        if self.selection_mark_mode {
19969            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19970                s.move_with(&mut |_, sel| {
19971                    sel.collapse_to(sel.head(), SelectionGoal::None);
19972                });
19973            })
19974        }
19975        self.selection_mark_mode = true;
19976        cx.notify();
19977    }
19978
19979    pub fn swap_selection_ends(
19980        &mut self,
19981        _: &actions::SwapSelectionEnds,
19982        window: &mut Window,
19983        cx: &mut Context<Self>,
19984    ) {
19985        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19986            s.move_with(&mut |_, sel| {
19987                if sel.start != sel.end {
19988                    sel.reversed = !sel.reversed
19989                }
19990            });
19991        });
19992        self.request_autoscroll(Autoscroll::newest(), cx);
19993        cx.notify();
19994    }
19995
19996    pub fn toggle_focus(
19997        workspace: &mut Workspace,
19998        _: &actions::ToggleFocus,
19999        window: &mut Window,
20000        cx: &mut Context<Workspace>,
20001    ) {
20002        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20003            return;
20004        };
20005        workspace.activate_item(&item, true, true, window, cx);
20006    }
20007
20008    pub fn toggle_fold(
20009        &mut self,
20010        _: &actions::ToggleFold,
20011        window: &mut Window,
20012        cx: &mut Context<Self>,
20013    ) {
20014        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20015            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20016            let selection = self.selections.newest::<Point>(&display_map);
20017
20018            let range = if selection.is_empty() {
20019                let point = selection.head().to_display_point(&display_map);
20020                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20021                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20022                    .to_point(&display_map);
20023                start..end
20024            } else {
20025                selection.range()
20026            };
20027            if display_map.folds_in_range(range).next().is_some() {
20028                self.unfold_lines(&Default::default(), window, cx)
20029            } else {
20030                self.fold(&Default::default(), window, cx)
20031            }
20032        } else {
20033            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20034            let buffer_ids: HashSet<_> = self
20035                .selections
20036                .disjoint_anchor_ranges()
20037                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20038                .collect();
20039
20040            let should_unfold = buffer_ids
20041                .iter()
20042                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20043
20044            for buffer_id in buffer_ids {
20045                if should_unfold {
20046                    self.unfold_buffer(buffer_id, cx);
20047                } else {
20048                    self.fold_buffer(buffer_id, cx);
20049                }
20050            }
20051        }
20052    }
20053
20054    pub fn toggle_fold_recursive(
20055        &mut self,
20056        _: &actions::ToggleFoldRecursive,
20057        window: &mut Window,
20058        cx: &mut Context<Self>,
20059    ) {
20060        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20061
20062        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20063        let range = if selection.is_empty() {
20064            let point = selection.head().to_display_point(&display_map);
20065            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20066            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20067                .to_point(&display_map);
20068            start..end
20069        } else {
20070            selection.range()
20071        };
20072        if display_map.folds_in_range(range).next().is_some() {
20073            self.unfold_recursive(&Default::default(), window, cx)
20074        } else {
20075            self.fold_recursive(&Default::default(), window, cx)
20076        }
20077    }
20078
20079    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20080        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20081            let mut to_fold = Vec::new();
20082            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20083            let selections = self.selections.all_adjusted(&display_map);
20084
20085            for selection in selections {
20086                let range = selection.range().sorted();
20087                let buffer_start_row = range.start.row;
20088
20089                if range.start.row != range.end.row {
20090                    let mut found = false;
20091                    let mut row = range.start.row;
20092                    while row <= range.end.row {
20093                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20094                        {
20095                            found = true;
20096                            row = crease.range().end.row + 1;
20097                            to_fold.push(crease);
20098                        } else {
20099                            row += 1
20100                        }
20101                    }
20102                    if found {
20103                        continue;
20104                    }
20105                }
20106
20107                for row in (0..=range.start.row).rev() {
20108                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20109                        && crease.range().end.row >= buffer_start_row
20110                    {
20111                        to_fold.push(crease);
20112                        if row <= range.start.row {
20113                            break;
20114                        }
20115                    }
20116                }
20117            }
20118
20119            self.fold_creases(to_fold, true, window, cx);
20120        } else {
20121            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20122            let buffer_ids = self
20123                .selections
20124                .disjoint_anchor_ranges()
20125                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20126                .collect::<HashSet<_>>();
20127            for buffer_id in buffer_ids {
20128                self.fold_buffer(buffer_id, cx);
20129            }
20130        }
20131    }
20132
20133    pub fn toggle_fold_all(
20134        &mut self,
20135        _: &actions::ToggleFoldAll,
20136        window: &mut Window,
20137        cx: &mut Context<Self>,
20138    ) {
20139        let has_folds = if self.buffer.read(cx).is_singleton() {
20140            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20141            let has_folds = display_map
20142                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20143                .next()
20144                .is_some();
20145            has_folds
20146        } else {
20147            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
20148            let has_folds = buffer_ids
20149                .iter()
20150                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20151            has_folds
20152        };
20153
20154        if has_folds {
20155            self.unfold_all(&actions::UnfoldAll, window, cx);
20156        } else {
20157            self.fold_all(&actions::FoldAll, window, cx);
20158        }
20159    }
20160
20161    fn fold_at_level(
20162        &mut self,
20163        fold_at: &FoldAtLevel,
20164        window: &mut Window,
20165        cx: &mut Context<Self>,
20166    ) {
20167        if !self.buffer.read(cx).is_singleton() {
20168            return;
20169        }
20170
20171        let fold_at_level = fold_at.0;
20172        let snapshot = self.buffer.read(cx).snapshot(cx);
20173        let mut to_fold = Vec::new();
20174        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20175
20176        let row_ranges_to_keep: Vec<Range<u32>> = self
20177            .selections
20178            .all::<Point>(&self.display_snapshot(cx))
20179            .into_iter()
20180            .map(|sel| sel.start.row..sel.end.row)
20181            .collect();
20182
20183        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20184            while start_row < end_row {
20185                match self
20186                    .snapshot(window, cx)
20187                    .crease_for_buffer_row(MultiBufferRow(start_row))
20188                {
20189                    Some(crease) => {
20190                        let nested_start_row = crease.range().start.row + 1;
20191                        let nested_end_row = crease.range().end.row;
20192
20193                        if current_level < fold_at_level {
20194                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20195                        } else if current_level == fold_at_level {
20196                            // Fold iff there is no selection completely contained within the fold region
20197                            if !row_ranges_to_keep.iter().any(|selection| {
20198                                selection.end >= nested_start_row
20199                                    && selection.start <= nested_end_row
20200                            }) {
20201                                to_fold.push(crease);
20202                            }
20203                        }
20204
20205                        start_row = nested_end_row + 1;
20206                    }
20207                    None => start_row += 1,
20208                }
20209            }
20210        }
20211
20212        self.fold_creases(to_fold, true, window, cx);
20213    }
20214
20215    pub fn fold_at_level_1(
20216        &mut self,
20217        _: &actions::FoldAtLevel1,
20218        window: &mut Window,
20219        cx: &mut Context<Self>,
20220    ) {
20221        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20222    }
20223
20224    pub fn fold_at_level_2(
20225        &mut self,
20226        _: &actions::FoldAtLevel2,
20227        window: &mut Window,
20228        cx: &mut Context<Self>,
20229    ) {
20230        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20231    }
20232
20233    pub fn fold_at_level_3(
20234        &mut self,
20235        _: &actions::FoldAtLevel3,
20236        window: &mut Window,
20237        cx: &mut Context<Self>,
20238    ) {
20239        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20240    }
20241
20242    pub fn fold_at_level_4(
20243        &mut self,
20244        _: &actions::FoldAtLevel4,
20245        window: &mut Window,
20246        cx: &mut Context<Self>,
20247    ) {
20248        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20249    }
20250
20251    pub fn fold_at_level_5(
20252        &mut self,
20253        _: &actions::FoldAtLevel5,
20254        window: &mut Window,
20255        cx: &mut Context<Self>,
20256    ) {
20257        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20258    }
20259
20260    pub fn fold_at_level_6(
20261        &mut self,
20262        _: &actions::FoldAtLevel6,
20263        window: &mut Window,
20264        cx: &mut Context<Self>,
20265    ) {
20266        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20267    }
20268
20269    pub fn fold_at_level_7(
20270        &mut self,
20271        _: &actions::FoldAtLevel7,
20272        window: &mut Window,
20273        cx: &mut Context<Self>,
20274    ) {
20275        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20276    }
20277
20278    pub fn fold_at_level_8(
20279        &mut self,
20280        _: &actions::FoldAtLevel8,
20281        window: &mut Window,
20282        cx: &mut Context<Self>,
20283    ) {
20284        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20285    }
20286
20287    pub fn fold_at_level_9(
20288        &mut self,
20289        _: &actions::FoldAtLevel9,
20290        window: &mut Window,
20291        cx: &mut Context<Self>,
20292    ) {
20293        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20294    }
20295
20296    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20297        if self.buffer.read(cx).is_singleton() {
20298            let mut fold_ranges = Vec::new();
20299            let snapshot = self.buffer.read(cx).snapshot(cx);
20300
20301            for row in 0..snapshot.max_row().0 {
20302                if let Some(foldable_range) = self
20303                    .snapshot(window, cx)
20304                    .crease_for_buffer_row(MultiBufferRow(row))
20305                {
20306                    fold_ranges.push(foldable_range);
20307                }
20308            }
20309
20310            self.fold_creases(fold_ranges, true, window, cx);
20311        } else {
20312            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20313                editor
20314                    .update_in(cx, |editor, _, cx| {
20315                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20316                            editor.fold_buffer(buffer_id, cx);
20317                        }
20318                    })
20319                    .ok();
20320            });
20321        }
20322    }
20323
20324    pub fn fold_function_bodies(
20325        &mut self,
20326        _: &actions::FoldFunctionBodies,
20327        window: &mut Window,
20328        cx: &mut Context<Self>,
20329    ) {
20330        let snapshot = self.buffer.read(cx).snapshot(cx);
20331
20332        let ranges = snapshot
20333            .text_object_ranges(
20334                MultiBufferOffset(0)..snapshot.len(),
20335                TreeSitterOptions::default(),
20336            )
20337            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20338            .collect::<Vec<_>>();
20339
20340        let creases = ranges
20341            .into_iter()
20342            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20343            .collect();
20344
20345        self.fold_creases(creases, true, window, cx);
20346    }
20347
20348    pub fn fold_recursive(
20349        &mut self,
20350        _: &actions::FoldRecursive,
20351        window: &mut Window,
20352        cx: &mut Context<Self>,
20353    ) {
20354        let mut to_fold = Vec::new();
20355        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20356        let selections = self.selections.all_adjusted(&display_map);
20357
20358        for selection in selections {
20359            let range = selection.range().sorted();
20360            let buffer_start_row = range.start.row;
20361
20362            if range.start.row != range.end.row {
20363                let mut found = false;
20364                for row in range.start.row..=range.end.row {
20365                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20366                        found = true;
20367                        to_fold.push(crease);
20368                    }
20369                }
20370                if found {
20371                    continue;
20372                }
20373            }
20374
20375            for row in (0..=range.start.row).rev() {
20376                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20377                    if crease.range().end.row >= buffer_start_row {
20378                        to_fold.push(crease);
20379                    } else {
20380                        break;
20381                    }
20382                }
20383            }
20384        }
20385
20386        self.fold_creases(to_fold, true, window, cx);
20387    }
20388
20389    pub fn fold_at(
20390        &mut self,
20391        buffer_row: MultiBufferRow,
20392        window: &mut Window,
20393        cx: &mut Context<Self>,
20394    ) {
20395        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20396
20397        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20398            let autoscroll = self
20399                .selections
20400                .all::<Point>(&display_map)
20401                .iter()
20402                .any(|selection| crease.range().overlaps(&selection.range()));
20403
20404            self.fold_creases(vec![crease], autoscroll, window, cx);
20405        }
20406    }
20407
20408    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20409        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20410            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20411            let buffer = display_map.buffer_snapshot();
20412            let selections = self.selections.all::<Point>(&display_map);
20413            let ranges = selections
20414                .iter()
20415                .map(|s| {
20416                    let range = s.display_range(&display_map).sorted();
20417                    let mut start = range.start.to_point(&display_map);
20418                    let mut end = range.end.to_point(&display_map);
20419                    start.column = 0;
20420                    end.column = buffer.line_len(MultiBufferRow(end.row));
20421                    start..end
20422                })
20423                .collect::<Vec<_>>();
20424
20425            self.unfold_ranges(&ranges, true, true, cx);
20426        } else {
20427            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20428            let buffer_ids = self
20429                .selections
20430                .disjoint_anchor_ranges()
20431                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20432                .collect::<HashSet<_>>();
20433            for buffer_id in buffer_ids {
20434                self.unfold_buffer(buffer_id, cx);
20435            }
20436        }
20437    }
20438
20439    pub fn unfold_recursive(
20440        &mut self,
20441        _: &UnfoldRecursive,
20442        _window: &mut Window,
20443        cx: &mut Context<Self>,
20444    ) {
20445        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20446        let selections = self.selections.all::<Point>(&display_map);
20447        let ranges = selections
20448            .iter()
20449            .map(|s| {
20450                let mut range = s.display_range(&display_map).sorted();
20451                *range.start.column_mut() = 0;
20452                *range.end.column_mut() = display_map.line_len(range.end.row());
20453                let start = range.start.to_point(&display_map);
20454                let end = range.end.to_point(&display_map);
20455                start..end
20456            })
20457            .collect::<Vec<_>>();
20458
20459        self.unfold_ranges(&ranges, true, true, cx);
20460    }
20461
20462    pub fn unfold_at(
20463        &mut self,
20464        buffer_row: MultiBufferRow,
20465        _window: &mut Window,
20466        cx: &mut Context<Self>,
20467    ) {
20468        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20469
20470        let intersection_range = Point::new(buffer_row.0, 0)
20471            ..Point::new(
20472                buffer_row.0,
20473                display_map.buffer_snapshot().line_len(buffer_row),
20474            );
20475
20476        let autoscroll = self
20477            .selections
20478            .all::<Point>(&display_map)
20479            .iter()
20480            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20481
20482        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20483    }
20484
20485    pub fn unfold_all(
20486        &mut self,
20487        _: &actions::UnfoldAll,
20488        _window: &mut Window,
20489        cx: &mut Context<Self>,
20490    ) {
20491        if self.buffer.read(cx).is_singleton() {
20492            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20493            self.unfold_ranges(
20494                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20495                true,
20496                true,
20497                cx,
20498            );
20499        } else {
20500            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20501                editor
20502                    .update(cx, |editor, cx| {
20503                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20504                            editor.unfold_buffer(buffer_id, cx);
20505                        }
20506                    })
20507                    .ok();
20508            });
20509        }
20510    }
20511
20512    pub fn fold_selected_ranges(
20513        &mut self,
20514        _: &FoldSelectedRanges,
20515        window: &mut Window,
20516        cx: &mut Context<Self>,
20517    ) {
20518        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20519        let selections = self.selections.all_adjusted(&display_map);
20520        let ranges = selections
20521            .into_iter()
20522            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20523            .collect::<Vec<_>>();
20524        self.fold_creases(ranges, true, window, cx);
20525    }
20526
20527    pub fn fold_ranges<T: ToOffset + Clone>(
20528        &mut self,
20529        ranges: Vec<Range<T>>,
20530        auto_scroll: bool,
20531        window: &mut Window,
20532        cx: &mut Context<Self>,
20533    ) {
20534        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20535        let ranges = ranges
20536            .into_iter()
20537            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20538            .collect::<Vec<_>>();
20539        self.fold_creases(ranges, auto_scroll, window, cx);
20540    }
20541
20542    pub fn fold_creases<T: ToOffset + Clone>(
20543        &mut self,
20544        creases: Vec<Crease<T>>,
20545        auto_scroll: bool,
20546        window: &mut Window,
20547        cx: &mut Context<Self>,
20548    ) {
20549        if creases.is_empty() {
20550            return;
20551        }
20552
20553        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20554
20555        if auto_scroll {
20556            self.request_autoscroll(Autoscroll::fit(), cx);
20557        }
20558
20559        cx.notify();
20560
20561        self.scrollbar_marker_state.dirty = true;
20562        self.update_data_on_scroll(window, cx);
20563        self.folds_did_change(cx);
20564    }
20565
20566    /// Removes any folds whose ranges intersect any of the given ranges.
20567    pub fn unfold_ranges<T: ToOffset + Clone>(
20568        &mut self,
20569        ranges: &[Range<T>],
20570        inclusive: bool,
20571        auto_scroll: bool,
20572        cx: &mut Context<Self>,
20573    ) {
20574        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20575            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20576        });
20577        self.folds_did_change(cx);
20578    }
20579
20580    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20581        self.fold_buffers([buffer_id], cx);
20582    }
20583
20584    pub fn fold_buffers(
20585        &mut self,
20586        buffer_ids: impl IntoIterator<Item = BufferId>,
20587        cx: &mut Context<Self>,
20588    ) {
20589        if self.buffer().read(cx).is_singleton() {
20590            return;
20591        }
20592
20593        let ids_to_fold: Vec<BufferId> = buffer_ids
20594            .into_iter()
20595            .filter(|id| !self.is_buffer_folded(*id, cx))
20596            .collect();
20597
20598        if ids_to_fold.is_empty() {
20599            return;
20600        }
20601
20602        let mut all_folded_excerpt_ids = Vec::new();
20603        for buffer_id in &ids_to_fold {
20604            let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(*buffer_id, cx);
20605            all_folded_excerpt_ids.extend(folded_excerpts.into_iter().map(|(id, _, _)| id));
20606        }
20607
20608        self.display_map.update(cx, |display_map, cx| {
20609            display_map.fold_buffers(ids_to_fold.clone(), cx)
20610        });
20611
20612        let snapshot = self.display_snapshot(cx);
20613        self.selections.change_with(&snapshot, |selections| {
20614            for buffer_id in ids_to_fold {
20615                selections.remove_selections_from_buffer(buffer_id);
20616            }
20617        });
20618
20619        cx.emit(EditorEvent::BufferFoldToggled {
20620            ids: all_folded_excerpt_ids,
20621            folded: true,
20622        });
20623        cx.notify();
20624    }
20625
20626    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20627        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20628            return;
20629        }
20630        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20631        self.display_map.update(cx, |display_map, cx| {
20632            display_map.unfold_buffers([buffer_id], cx);
20633        });
20634        cx.emit(EditorEvent::BufferFoldToggled {
20635            ids: unfolded_excerpts.iter().map(|&(id, _, _)| id).collect(),
20636            folded: false,
20637        });
20638        cx.notify();
20639    }
20640
20641    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20642        self.display_map.read(cx).is_buffer_folded(buffer)
20643    }
20644
20645    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20646        if self.buffer().read(cx).is_singleton() {
20647            return false;
20648        }
20649        !self.folded_buffers(cx).is_empty()
20650    }
20651
20652    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20653        self.display_map.read(cx).folded_buffers()
20654    }
20655
20656    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20657        self.display_map.update(cx, |display_map, cx| {
20658            display_map.disable_header_for_buffer(buffer_id, cx);
20659        });
20660        cx.notify();
20661    }
20662
20663    /// Removes any folds with the given ranges.
20664    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20665        &mut self,
20666        ranges: &[Range<T>],
20667        type_id: TypeId,
20668        auto_scroll: bool,
20669        cx: &mut Context<Self>,
20670    ) {
20671        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20672            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20673        });
20674        self.folds_did_change(cx);
20675    }
20676
20677    fn remove_folds_with<T: ToOffset + Clone>(
20678        &mut self,
20679        ranges: &[Range<T>],
20680        auto_scroll: bool,
20681        cx: &mut Context<Self>,
20682        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20683    ) {
20684        if ranges.is_empty() {
20685            return;
20686        }
20687
20688        let mut buffers_affected = HashSet::default();
20689        let multi_buffer = self.buffer().read(cx);
20690        for range in ranges {
20691            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20692                buffers_affected.insert(buffer.read(cx).remote_id());
20693            };
20694        }
20695
20696        self.display_map.update(cx, update);
20697
20698        if auto_scroll {
20699            self.request_autoscroll(Autoscroll::fit(), cx);
20700        }
20701
20702        cx.notify();
20703        self.scrollbar_marker_state.dirty = true;
20704        self.active_indent_guides_state.dirty = true;
20705    }
20706
20707    pub fn update_renderer_widths(
20708        &mut self,
20709        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20710        cx: &mut Context<Self>,
20711    ) -> bool {
20712        self.display_map
20713            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20714    }
20715
20716    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20717        self.display_map.read(cx).fold_placeholder.clone()
20718    }
20719
20720    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20721        self.buffer.update(cx, |buffer, cx| {
20722            buffer.set_all_diff_hunks_expanded(cx);
20723        });
20724    }
20725
20726    pub fn expand_all_diff_hunks(
20727        &mut self,
20728        _: &ExpandAllDiffHunks,
20729        _window: &mut Window,
20730        cx: &mut Context<Self>,
20731    ) {
20732        self.buffer.update(cx, |buffer, cx| {
20733            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20734        });
20735    }
20736
20737    pub fn collapse_all_diff_hunks(
20738        &mut self,
20739        _: &CollapseAllDiffHunks,
20740        _window: &mut Window,
20741        cx: &mut Context<Self>,
20742    ) {
20743        self.buffer.update(cx, |buffer, cx| {
20744            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20745        });
20746    }
20747
20748    pub fn toggle_selected_diff_hunks(
20749        &mut self,
20750        _: &ToggleSelectedDiffHunks,
20751        _window: &mut Window,
20752        cx: &mut Context<Self>,
20753    ) {
20754        let ranges: Vec<_> = self
20755            .selections
20756            .disjoint_anchors()
20757            .iter()
20758            .map(|s| s.range())
20759            .collect();
20760        self.toggle_diff_hunks_in_ranges(ranges, cx);
20761    }
20762
20763    pub fn diff_hunks_in_ranges<'a>(
20764        &'a self,
20765        ranges: &'a [Range<Anchor>],
20766        buffer: &'a MultiBufferSnapshot,
20767    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20768        ranges.iter().flat_map(move |range| {
20769            let end_excerpt_id = range.end.excerpt_id;
20770            let range = range.to_point(buffer);
20771            let mut peek_end = range.end;
20772            if range.end.row < buffer.max_row().0 {
20773                peek_end = Point::new(range.end.row + 1, 0);
20774            }
20775            buffer
20776                .diff_hunks_in_range(range.start..peek_end)
20777                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20778        })
20779    }
20780
20781    pub fn has_stageable_diff_hunks_in_ranges(
20782        &self,
20783        ranges: &[Range<Anchor>],
20784        snapshot: &MultiBufferSnapshot,
20785    ) -> bool {
20786        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20787        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20788    }
20789
20790    pub fn toggle_staged_selected_diff_hunks(
20791        &mut self,
20792        _: &::git::ToggleStaged,
20793        _: &mut Window,
20794        cx: &mut Context<Self>,
20795    ) {
20796        let snapshot = self.buffer.read(cx).snapshot(cx);
20797        let ranges: Vec<_> = self
20798            .selections
20799            .disjoint_anchors()
20800            .iter()
20801            .map(|s| s.range())
20802            .collect();
20803        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20804        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20805    }
20806
20807    pub fn set_render_diff_hunk_controls(
20808        &mut self,
20809        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20810        cx: &mut Context<Self>,
20811    ) {
20812        self.render_diff_hunk_controls = render_diff_hunk_controls;
20813        cx.notify();
20814    }
20815
20816    pub fn stage_and_next(
20817        &mut self,
20818        _: &::git::StageAndNext,
20819        window: &mut Window,
20820        cx: &mut Context<Self>,
20821    ) {
20822        self.do_stage_or_unstage_and_next(true, window, cx);
20823    }
20824
20825    pub fn unstage_and_next(
20826        &mut self,
20827        _: &::git::UnstageAndNext,
20828        window: &mut Window,
20829        cx: &mut Context<Self>,
20830    ) {
20831        self.do_stage_or_unstage_and_next(false, window, cx);
20832    }
20833
20834    pub fn stage_or_unstage_diff_hunks(
20835        &mut self,
20836        stage: bool,
20837        ranges: Vec<Range<Anchor>>,
20838        cx: &mut Context<Self>,
20839    ) {
20840        if self.delegate_stage_and_restore {
20841            let snapshot = self.buffer.read(cx).snapshot(cx);
20842            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20843            if !hunks.is_empty() {
20844                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20845            }
20846            return;
20847        }
20848        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20849        cx.spawn(async move |this, cx| {
20850            task.await?;
20851            this.update(cx, |this, cx| {
20852                let snapshot = this.buffer.read(cx).snapshot(cx);
20853                let chunk_by = this
20854                    .diff_hunks_in_ranges(&ranges, &snapshot)
20855                    .chunk_by(|hunk| hunk.buffer_id);
20856                for (buffer_id, hunks) in &chunk_by {
20857                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20858                }
20859            })
20860        })
20861        .detach_and_log_err(cx);
20862    }
20863
20864    fn save_buffers_for_ranges_if_needed(
20865        &mut self,
20866        ranges: &[Range<Anchor>],
20867        cx: &mut Context<Editor>,
20868    ) -> Task<Result<()>> {
20869        let multibuffer = self.buffer.read(cx);
20870        let snapshot = multibuffer.read(cx);
20871        let buffer_ids: HashSet<_> = ranges
20872            .iter()
20873            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20874            .collect();
20875        drop(snapshot);
20876
20877        let mut buffers = HashSet::default();
20878        for buffer_id in buffer_ids {
20879            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20880                let buffer = buffer_entity.read(cx);
20881                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20882                {
20883                    buffers.insert(buffer_entity);
20884                }
20885            }
20886        }
20887
20888        if let Some(project) = &self.project {
20889            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20890        } else {
20891            Task::ready(Ok(()))
20892        }
20893    }
20894
20895    fn do_stage_or_unstage_and_next(
20896        &mut self,
20897        stage: bool,
20898        window: &mut Window,
20899        cx: &mut Context<Self>,
20900    ) {
20901        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20902
20903        if ranges.iter().any(|range| range.start != range.end) {
20904            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20905            return;
20906        }
20907
20908        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20909
20910        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20911        let wrap_around = !all_diff_hunks_expanded;
20912        let snapshot = self.snapshot(window, cx);
20913        let position = self
20914            .selections
20915            .newest::<Point>(&snapshot.display_snapshot)
20916            .head();
20917
20918        self.go_to_hunk_before_or_after_position(
20919            &snapshot,
20920            position,
20921            Direction::Next,
20922            wrap_around,
20923            window,
20924            cx,
20925        );
20926    }
20927
20928    pub(crate) fn do_stage_or_unstage(
20929        &self,
20930        stage: bool,
20931        buffer_id: BufferId,
20932        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20933        cx: &mut App,
20934    ) -> Option<()> {
20935        let project = self.project()?;
20936        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20937        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20938        let buffer_snapshot = buffer.read(cx).snapshot();
20939        let file_exists = buffer_snapshot
20940            .file()
20941            .is_some_and(|file| file.disk_state().exists());
20942        diff.update(cx, |diff, cx| {
20943            diff.stage_or_unstage_hunks(
20944                stage,
20945                &hunks
20946                    .map(|hunk| buffer_diff::DiffHunk {
20947                        buffer_range: hunk.buffer_range,
20948                        // We don't need to pass in word diffs here because they're only used for rendering and
20949                        // this function changes internal state
20950                        base_word_diffs: Vec::default(),
20951                        buffer_word_diffs: Vec::default(),
20952                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20953                            ..hunk.diff_base_byte_range.end.0,
20954                        secondary_status: hunk.status.secondary,
20955                        range: Point::zero()..Point::zero(), // unused
20956                    })
20957                    .collect::<Vec<_>>(),
20958                &buffer_snapshot,
20959                file_exists,
20960                cx,
20961            )
20962        });
20963        None
20964    }
20965
20966    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20967        let ranges: Vec<_> = self
20968            .selections
20969            .disjoint_anchors()
20970            .iter()
20971            .map(|s| s.range())
20972            .collect();
20973        self.buffer
20974            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20975    }
20976
20977    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20978        self.buffer.update(cx, |buffer, cx| {
20979            let ranges = vec![Anchor::min()..Anchor::max()];
20980            if !buffer.all_diff_hunks_expanded()
20981                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20982            {
20983                buffer.collapse_diff_hunks(ranges, cx);
20984                true
20985            } else {
20986                false
20987            }
20988        })
20989    }
20990
20991    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20992        if self.buffer.read(cx).all_diff_hunks_expanded() {
20993            return true;
20994        }
20995        let ranges = vec![Anchor::min()..Anchor::max()];
20996        self.buffer
20997            .read(cx)
20998            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20999    }
21000
21001    fn toggle_diff_hunks_in_ranges(
21002        &mut self,
21003        ranges: Vec<Range<Anchor>>,
21004        cx: &mut Context<Editor>,
21005    ) {
21006        self.buffer.update(cx, |buffer, cx| {
21007            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21008            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21009        })
21010    }
21011
21012    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21013        self.buffer.update(cx, |buffer, cx| {
21014            buffer.toggle_single_diff_hunk(range, cx);
21015        })
21016    }
21017
21018    pub(crate) fn apply_all_diff_hunks(
21019        &mut self,
21020        _: &ApplyAllDiffHunks,
21021        window: &mut Window,
21022        cx: &mut Context<Self>,
21023    ) {
21024        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21025
21026        let buffers = self.buffer.read(cx).all_buffers();
21027        for branch_buffer in buffers {
21028            branch_buffer.update(cx, |branch_buffer, cx| {
21029                branch_buffer.merge_into_base(Vec::new(), cx);
21030            });
21031        }
21032
21033        if let Some(project) = self.project.clone() {
21034            self.save(
21035                SaveOptions {
21036                    format: true,
21037                    autosave: false,
21038                },
21039                project,
21040                window,
21041                cx,
21042            )
21043            .detach_and_log_err(cx);
21044        }
21045    }
21046
21047    pub(crate) fn apply_selected_diff_hunks(
21048        &mut self,
21049        _: &ApplyDiffHunk,
21050        window: &mut Window,
21051        cx: &mut Context<Self>,
21052    ) {
21053        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21054        let snapshot = self.snapshot(window, cx);
21055        let hunks = snapshot.hunks_for_ranges(
21056            self.selections
21057                .all(&snapshot.display_snapshot)
21058                .into_iter()
21059                .map(|selection| selection.range()),
21060        );
21061        let mut ranges_by_buffer = HashMap::default();
21062        self.transact(window, cx, |editor, _window, cx| {
21063            for hunk in hunks {
21064                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21065                    ranges_by_buffer
21066                        .entry(buffer.clone())
21067                        .or_insert_with(Vec::new)
21068                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21069                }
21070            }
21071
21072            for (buffer, ranges) in ranges_by_buffer {
21073                buffer.update(cx, |buffer, cx| {
21074                    buffer.merge_into_base(ranges, cx);
21075                });
21076            }
21077        });
21078
21079        if let Some(project) = self.project.clone() {
21080            self.save(
21081                SaveOptions {
21082                    format: true,
21083                    autosave: false,
21084                },
21085                project,
21086                window,
21087                cx,
21088            )
21089            .detach_and_log_err(cx);
21090        }
21091    }
21092
21093    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21094        if hovered != self.gutter_hovered {
21095            self.gutter_hovered = hovered;
21096            cx.notify();
21097        }
21098    }
21099
21100    pub fn insert_blocks(
21101        &mut self,
21102        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21103        autoscroll: Option<Autoscroll>,
21104        cx: &mut Context<Self>,
21105    ) -> Vec<CustomBlockId> {
21106        let blocks = self
21107            .display_map
21108            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21109        if let Some(autoscroll) = autoscroll {
21110            self.request_autoscroll(autoscroll, cx);
21111        }
21112        cx.notify();
21113        blocks
21114    }
21115
21116    pub fn resize_blocks(
21117        &mut self,
21118        heights: HashMap<CustomBlockId, u32>,
21119        autoscroll: Option<Autoscroll>,
21120        cx: &mut Context<Self>,
21121    ) {
21122        self.display_map
21123            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21124        if let Some(autoscroll) = autoscroll {
21125            self.request_autoscroll(autoscroll, cx);
21126        }
21127        cx.notify();
21128    }
21129
21130    pub fn replace_blocks(
21131        &mut self,
21132        renderers: HashMap<CustomBlockId, RenderBlock>,
21133        autoscroll: Option<Autoscroll>,
21134        cx: &mut Context<Self>,
21135    ) {
21136        self.display_map
21137            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21138        if let Some(autoscroll) = autoscroll {
21139            self.request_autoscroll(autoscroll, cx);
21140        }
21141        cx.notify();
21142    }
21143
21144    pub fn remove_blocks(
21145        &mut self,
21146        block_ids: HashSet<CustomBlockId>,
21147        autoscroll: Option<Autoscroll>,
21148        cx: &mut Context<Self>,
21149    ) {
21150        self.display_map.update(cx, |display_map, cx| {
21151            display_map.remove_blocks(block_ids, cx)
21152        });
21153        if let Some(autoscroll) = autoscroll {
21154            self.request_autoscroll(autoscroll, cx);
21155        }
21156        cx.notify();
21157    }
21158
21159    pub fn row_for_block(
21160        &self,
21161        block_id: CustomBlockId,
21162        cx: &mut Context<Self>,
21163    ) -> Option<DisplayRow> {
21164        self.display_map
21165            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21166    }
21167
21168    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21169        self.focused_block = Some(focused_block);
21170    }
21171
21172    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21173        self.focused_block.take()
21174    }
21175
21176    pub fn insert_creases(
21177        &mut self,
21178        creases: impl IntoIterator<Item = Crease<Anchor>>,
21179        cx: &mut Context<Self>,
21180    ) -> Vec<CreaseId> {
21181        self.display_map
21182            .update(cx, |map, cx| map.insert_creases(creases, cx))
21183    }
21184
21185    pub fn remove_creases(
21186        &mut self,
21187        ids: impl IntoIterator<Item = CreaseId>,
21188        cx: &mut Context<Self>,
21189    ) -> Vec<(CreaseId, Range<Anchor>)> {
21190        self.display_map
21191            .update(cx, |map, cx| map.remove_creases(ids, cx))
21192    }
21193
21194    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21195        self.display_map
21196            .update(cx, |map, cx| map.snapshot(cx))
21197            .longest_row()
21198    }
21199
21200    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21201        self.display_map
21202            .update(cx, |map, cx| map.snapshot(cx))
21203            .max_point()
21204    }
21205
21206    pub fn text(&self, cx: &App) -> String {
21207        self.buffer.read(cx).read(cx).text()
21208    }
21209
21210    pub fn is_empty(&self, cx: &App) -> bool {
21211        self.buffer.read(cx).read(cx).is_empty()
21212    }
21213
21214    pub fn text_option(&self, cx: &App) -> Option<String> {
21215        let text = self.text(cx);
21216        let text = text.trim();
21217
21218        if text.is_empty() {
21219            return None;
21220        }
21221
21222        Some(text.to_string())
21223    }
21224
21225    pub fn set_text(
21226        &mut self,
21227        text: impl Into<Arc<str>>,
21228        window: &mut Window,
21229        cx: &mut Context<Self>,
21230    ) {
21231        self.transact(window, cx, |this, _, cx| {
21232            this.buffer
21233                .read(cx)
21234                .as_singleton()
21235                .expect("you can only call set_text on editors for singleton buffers")
21236                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21237        });
21238    }
21239
21240    pub fn display_text(&self, cx: &mut App) -> String {
21241        self.display_map
21242            .update(cx, |map, cx| map.snapshot(cx))
21243            .text()
21244    }
21245
21246    fn create_minimap(
21247        &self,
21248        minimap_settings: MinimapSettings,
21249        window: &mut Window,
21250        cx: &mut Context<Self>,
21251    ) -> Option<Entity<Self>> {
21252        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21253            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21254    }
21255
21256    fn initialize_new_minimap(
21257        &self,
21258        minimap_settings: MinimapSettings,
21259        window: &mut Window,
21260        cx: &mut Context<Self>,
21261    ) -> Entity<Self> {
21262        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21263        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21264
21265        let mut minimap = Editor::new_internal(
21266            EditorMode::Minimap {
21267                parent: cx.weak_entity(),
21268            },
21269            self.buffer.clone(),
21270            None,
21271            Some(self.display_map.clone()),
21272            window,
21273            cx,
21274        );
21275        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21276        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21277        minimap.scroll_manager.clone_state(
21278            &self.scroll_manager,
21279            &my_snapshot,
21280            &minimap_snapshot,
21281            cx,
21282        );
21283        minimap.set_text_style_refinement(TextStyleRefinement {
21284            font_size: Some(MINIMAP_FONT_SIZE),
21285            font_weight: Some(MINIMAP_FONT_WEIGHT),
21286            font_family: Some(MINIMAP_FONT_FAMILY),
21287            ..Default::default()
21288        });
21289        minimap.update_minimap_configuration(minimap_settings, cx);
21290        cx.new(|_| minimap)
21291    }
21292
21293    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21294        let current_line_highlight = minimap_settings
21295            .current_line_highlight
21296            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21297        self.set_current_line_highlight(Some(current_line_highlight));
21298    }
21299
21300    pub fn minimap(&self) -> Option<&Entity<Self>> {
21301        self.minimap
21302            .as_ref()
21303            .filter(|_| self.minimap_visibility.visible())
21304    }
21305
21306    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21307        let mut wrap_guides = smallvec![];
21308
21309        if self.show_wrap_guides == Some(false) {
21310            return wrap_guides;
21311        }
21312
21313        let settings = self.buffer.read(cx).language_settings(cx);
21314        if settings.show_wrap_guides {
21315            match self.soft_wrap_mode(cx) {
21316                SoftWrap::Column(soft_wrap) => {
21317                    wrap_guides.push((soft_wrap as usize, true));
21318                }
21319                SoftWrap::Bounded(soft_wrap) => {
21320                    wrap_guides.push((soft_wrap as usize, true));
21321                }
21322                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21323            }
21324            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21325        }
21326
21327        wrap_guides
21328    }
21329
21330    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21331        let settings = self.buffer.read(cx).language_settings(cx);
21332        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21333        match mode {
21334            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21335                SoftWrap::None
21336            }
21337            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21338            language_settings::SoftWrap::PreferredLineLength => {
21339                SoftWrap::Column(settings.preferred_line_length)
21340            }
21341            language_settings::SoftWrap::Bounded => {
21342                SoftWrap::Bounded(settings.preferred_line_length)
21343            }
21344        }
21345    }
21346
21347    pub fn set_soft_wrap_mode(
21348        &mut self,
21349        mode: language_settings::SoftWrap,
21350        cx: &mut Context<Self>,
21351    ) {
21352        self.soft_wrap_mode_override = Some(mode);
21353        cx.notify();
21354    }
21355
21356    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21357        self.hard_wrap = hard_wrap;
21358        cx.notify();
21359    }
21360
21361    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21362        self.text_style_refinement = Some(style);
21363    }
21364
21365    /// called by the Element so we know what style we were most recently rendered with.
21366    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21367        // We intentionally do not inform the display map about the minimap style
21368        // so that wrapping is not recalculated and stays consistent for the editor
21369        // and its linked minimap.
21370        if !self.mode.is_minimap() {
21371            let font = style.text.font();
21372            let font_size = style.text.font_size.to_pixels(window.rem_size());
21373            let display_map = self
21374                .placeholder_display_map
21375                .as_ref()
21376                .filter(|_| self.is_empty(cx))
21377                .unwrap_or(&self.display_map);
21378
21379            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21380        }
21381        self.style = Some(style);
21382    }
21383
21384    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21385        if self.style.is_none() {
21386            self.style = Some(self.create_style(cx));
21387        }
21388        self.style.as_ref().unwrap()
21389    }
21390
21391    // Called by the element. This method is not designed to be called outside of the editor
21392    // element's layout code because it does not notify when rewrapping is computed synchronously.
21393    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21394        if self.is_empty(cx) {
21395            self.placeholder_display_map
21396                .as_ref()
21397                .map_or(false, |display_map| {
21398                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21399                })
21400        } else {
21401            self.display_map
21402                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21403        }
21404    }
21405
21406    pub fn set_soft_wrap(&mut self) {
21407        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21408    }
21409
21410    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21411        if self.soft_wrap_mode_override.is_some() {
21412            self.soft_wrap_mode_override.take();
21413        } else {
21414            let soft_wrap = match self.soft_wrap_mode(cx) {
21415                SoftWrap::GitDiff => return,
21416                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21417                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21418                    language_settings::SoftWrap::None
21419                }
21420            };
21421            self.soft_wrap_mode_override = Some(soft_wrap);
21422        }
21423        cx.notify();
21424    }
21425
21426    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21427        let Some(workspace) = self.workspace() else {
21428            return;
21429        };
21430        let fs = workspace.read(cx).app_state().fs.clone();
21431        let current_show = TabBarSettings::get_global(cx).show;
21432        update_settings_file(fs, cx, move |setting, _| {
21433            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21434        });
21435    }
21436
21437    pub fn toggle_indent_guides(
21438        &mut self,
21439        _: &ToggleIndentGuides,
21440        _: &mut Window,
21441        cx: &mut Context<Self>,
21442    ) {
21443        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21444            self.buffer
21445                .read(cx)
21446                .language_settings(cx)
21447                .indent_guides
21448                .enabled
21449        });
21450        self.show_indent_guides = Some(!currently_enabled);
21451        cx.notify();
21452    }
21453
21454    fn should_show_indent_guides(&self) -> Option<bool> {
21455        self.show_indent_guides
21456    }
21457
21458    pub fn disable_indent_guides_for_buffer(
21459        &mut self,
21460        buffer_id: BufferId,
21461        cx: &mut Context<Self>,
21462    ) {
21463        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21464        cx.notify();
21465    }
21466
21467    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21468        self.buffers_with_disabled_indent_guides
21469            .contains(&buffer_id)
21470    }
21471
21472    pub fn toggle_line_numbers(
21473        &mut self,
21474        _: &ToggleLineNumbers,
21475        _: &mut Window,
21476        cx: &mut Context<Self>,
21477    ) {
21478        let mut editor_settings = EditorSettings::get_global(cx).clone();
21479        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21480        EditorSettings::override_global(editor_settings, cx);
21481    }
21482
21483    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21484        if let Some(show_line_numbers) = self.show_line_numbers {
21485            return show_line_numbers;
21486        }
21487        EditorSettings::get_global(cx).gutter.line_numbers
21488    }
21489
21490    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21491        match (
21492            self.use_relative_line_numbers,
21493            EditorSettings::get_global(cx).relative_line_numbers,
21494        ) {
21495            (None, setting) => setting,
21496            (Some(false), _) => RelativeLineNumbers::Disabled,
21497            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21498            (Some(true), _) => RelativeLineNumbers::Enabled,
21499        }
21500    }
21501
21502    pub fn toggle_relative_line_numbers(
21503        &mut self,
21504        _: &ToggleRelativeLineNumbers,
21505        _: &mut Window,
21506        cx: &mut Context<Self>,
21507    ) {
21508        let is_relative = self.relative_line_numbers(cx);
21509        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21510    }
21511
21512    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21513        self.use_relative_line_numbers = is_relative;
21514        cx.notify();
21515    }
21516
21517    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21518        self.show_gutter = show_gutter;
21519        cx.notify();
21520    }
21521
21522    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21523        self.show_scrollbars = ScrollbarAxes {
21524            horizontal: show,
21525            vertical: show,
21526        };
21527        cx.notify();
21528    }
21529
21530    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21531        self.show_scrollbars.vertical = show;
21532        cx.notify();
21533    }
21534
21535    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21536        self.show_scrollbars.horizontal = show;
21537        cx.notify();
21538    }
21539
21540    pub fn set_minimap_visibility(
21541        &mut self,
21542        minimap_visibility: MinimapVisibility,
21543        window: &mut Window,
21544        cx: &mut Context<Self>,
21545    ) {
21546        if self.minimap_visibility != minimap_visibility {
21547            if minimap_visibility.visible() && self.minimap.is_none() {
21548                let minimap_settings = EditorSettings::get_global(cx).minimap;
21549                self.minimap =
21550                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21551            }
21552            self.minimap_visibility = minimap_visibility;
21553            cx.notify();
21554        }
21555    }
21556
21557    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21558        self.set_show_scrollbars(false, cx);
21559        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21560    }
21561
21562    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21563        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21564    }
21565
21566    /// Normally the text in full mode and auto height editors is padded on the
21567    /// left side by roughly half a character width for improved hit testing.
21568    ///
21569    /// Use this method to disable this for cases where this is not wanted (e.g.
21570    /// if you want to align the editor text with some other text above or below)
21571    /// or if you want to add this padding to single-line editors.
21572    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21573        self.offset_content = offset_content;
21574        cx.notify();
21575    }
21576
21577    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21578        self.show_line_numbers = Some(show_line_numbers);
21579        cx.notify();
21580    }
21581
21582    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21583        self.disable_expand_excerpt_buttons = true;
21584        cx.notify();
21585    }
21586
21587    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21588        self.number_deleted_lines = number;
21589        cx.notify();
21590    }
21591
21592    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21593        self.delegate_expand_excerpts = delegate;
21594    }
21595
21596    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21597        self.delegate_stage_and_restore = delegate;
21598    }
21599
21600    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21601        self.delegate_open_excerpts = delegate;
21602    }
21603
21604    pub fn set_on_local_selections_changed(
21605        &mut self,
21606        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21607    ) {
21608        self.on_local_selections_changed = callback;
21609    }
21610
21611    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21612        self.suppress_selection_callback = suppress;
21613    }
21614
21615    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21616        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21617        cx.notify();
21618    }
21619
21620    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21621        self.show_code_actions = Some(show_code_actions);
21622        cx.notify();
21623    }
21624
21625    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21626        self.show_runnables = Some(show_runnables);
21627        cx.notify();
21628    }
21629
21630    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21631        self.show_breakpoints = Some(show_breakpoints);
21632        cx.notify();
21633    }
21634
21635    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21636        self.show_diff_review_button = show;
21637        cx.notify();
21638    }
21639
21640    pub fn show_diff_review_button(&self) -> bool {
21641        self.show_diff_review_button
21642    }
21643
21644    pub fn render_diff_review_button(
21645        &self,
21646        display_row: DisplayRow,
21647        width: Pixels,
21648        cx: &mut Context<Self>,
21649    ) -> impl IntoElement {
21650        let text_color = cx.theme().colors().text;
21651        let icon_color = cx.theme().colors().icon_accent;
21652
21653        h_flex()
21654            .id("diff_review_button")
21655            .cursor_pointer()
21656            .w(width - px(1.))
21657            .h(relative(0.9))
21658            .justify_center()
21659            .rounded_sm()
21660            .border_1()
21661            .border_color(text_color.opacity(0.1))
21662            .bg(text_color.opacity(0.15))
21663            .hover(|s| {
21664                s.bg(icon_color.opacity(0.4))
21665                    .border_color(icon_color.opacity(0.5))
21666            })
21667            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21668            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21669            .on_mouse_down(
21670                gpui::MouseButton::Left,
21671                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21672                    editor.start_diff_review_drag(display_row, window, cx);
21673                }),
21674            )
21675    }
21676
21677    pub fn start_diff_review_drag(
21678        &mut self,
21679        display_row: DisplayRow,
21680        window: &mut Window,
21681        cx: &mut Context<Self>,
21682    ) {
21683        let snapshot = self.snapshot(window, cx);
21684        let point = snapshot
21685            .display_snapshot
21686            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21687        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21688        self.diff_review_drag_state = Some(DiffReviewDragState {
21689            start_anchor: anchor,
21690            current_anchor: anchor,
21691        });
21692        cx.notify();
21693    }
21694
21695    pub fn update_diff_review_drag(
21696        &mut self,
21697        display_row: DisplayRow,
21698        window: &mut Window,
21699        cx: &mut Context<Self>,
21700    ) {
21701        if self.diff_review_drag_state.is_none() {
21702            return;
21703        }
21704        let snapshot = self.snapshot(window, cx);
21705        let point = snapshot
21706            .display_snapshot
21707            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21708        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21709        if let Some(drag_state) = &mut self.diff_review_drag_state {
21710            drag_state.current_anchor = anchor;
21711            cx.notify();
21712        }
21713    }
21714
21715    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21716        if let Some(drag_state) = self.diff_review_drag_state.take() {
21717            let snapshot = self.snapshot(window, cx);
21718            let range = drag_state.row_range(&snapshot.display_snapshot);
21719            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21720        }
21721        cx.notify();
21722    }
21723
21724    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21725        self.diff_review_drag_state = None;
21726        cx.notify();
21727    }
21728
21729    /// Calculates the appropriate block height for the diff review overlay.
21730    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21731    /// and 2 lines per comment when expanded.
21732    fn calculate_overlay_height(
21733        &self,
21734        hunk_key: &DiffHunkKey,
21735        comments_expanded: bool,
21736        snapshot: &MultiBufferSnapshot,
21737    ) -> u32 {
21738        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21739        let base_height: u32 = 2; // Input row with avatar and buttons
21740
21741        if comment_count == 0 {
21742            base_height
21743        } else if comments_expanded {
21744            // Header (1 line) + 2 lines per comment
21745            base_height + 1 + (comment_count as u32 * 2)
21746        } else {
21747            // Just header when collapsed
21748            base_height + 1
21749        }
21750    }
21751
21752    pub fn show_diff_review_overlay(
21753        &mut self,
21754        display_range: Range<DisplayRow>,
21755        window: &mut Window,
21756        cx: &mut Context<Self>,
21757    ) {
21758        let Range { start, end } = display_range.sorted();
21759
21760        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21761        let editor_snapshot = self.snapshot(window, cx);
21762
21763        // Convert display rows to multibuffer points
21764        let start_point = editor_snapshot
21765            .display_snapshot
21766            .display_point_to_point(start.as_display_point(), Bias::Left);
21767        let end_point = editor_snapshot
21768            .display_snapshot
21769            .display_point_to_point(end.as_display_point(), Bias::Left);
21770        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21771
21772        // Create anchor range for the selected lines (start of first line to end of last line)
21773        let line_end = Point::new(
21774            end_point.row,
21775            buffer_snapshot.line_len(end_multi_buffer_row),
21776        );
21777        let anchor_range =
21778            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21779
21780        // Compute the hunk key for this display row
21781        let file_path = buffer_snapshot
21782            .file_at(start_point)
21783            .map(|file: &Arc<dyn language::File>| file.path().clone())
21784            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21785        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21786        let new_hunk_key = DiffHunkKey {
21787            file_path,
21788            hunk_start_anchor,
21789        };
21790
21791        // Check if we already have an overlay for this hunk
21792        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21793            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21794        }) {
21795            // Just focus the existing overlay's prompt editor
21796            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21797            window.focus(&focus_handle, cx);
21798            return;
21799        }
21800
21801        // Dismiss overlays that have no comments for their hunks
21802        self.dismiss_overlays_without_comments(cx);
21803
21804        // Get the current user's avatar URI from the project's user_store
21805        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21806            let user_store = project.read(cx).user_store();
21807            user_store
21808                .read(cx)
21809                .current_user()
21810                .map(|user| user.avatar_uri.clone())
21811        });
21812
21813        // Create anchor at the end of the last row so the block appears immediately below it
21814        // Use multibuffer coordinates for anchor creation
21815        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21816        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21817
21818        // Use the hunk key we already computed
21819        let hunk_key = new_hunk_key;
21820
21821        // Create the prompt editor for the review input
21822        let prompt_editor = cx.new(|cx| {
21823            let mut editor = Editor::single_line(window, cx);
21824            editor.set_placeholder_text("Add a review comment...", window, cx);
21825            editor
21826        });
21827
21828        // Register the Newline action on the prompt editor to submit the review
21829        let parent_editor = cx.entity().downgrade();
21830        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21831            prompt_editor.register_action({
21832                let parent_editor = parent_editor.clone();
21833                move |_: &crate::actions::Newline, window, cx| {
21834                    if let Some(editor) = parent_editor.upgrade() {
21835                        editor.update(cx, |editor, cx| {
21836                            editor.submit_diff_review_comment(window, cx);
21837                        });
21838                    }
21839                }
21840            })
21841        });
21842
21843        // Calculate initial height based on existing comments for this hunk
21844        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21845
21846        // Create the overlay block
21847        let prompt_editor_for_render = prompt_editor.clone();
21848        let hunk_key_for_render = hunk_key.clone();
21849        let editor_handle = cx.entity().downgrade();
21850        let block = BlockProperties {
21851            style: BlockStyle::Sticky,
21852            placement: BlockPlacement::Below(anchor),
21853            height: Some(initial_height),
21854            render: Arc::new(move |cx| {
21855                Self::render_diff_review_overlay(
21856                    &prompt_editor_for_render,
21857                    &hunk_key_for_render,
21858                    &editor_handle,
21859                    cx,
21860                )
21861            }),
21862            priority: 0,
21863        };
21864
21865        let block_ids = self.insert_blocks([block], None, cx);
21866        let Some(block_id) = block_ids.into_iter().next() else {
21867            log::error!("Failed to insert diff review overlay block");
21868            return;
21869        };
21870
21871        self.diff_review_overlays.push(DiffReviewOverlay {
21872            anchor_range,
21873            block_id,
21874            prompt_editor: prompt_editor.clone(),
21875            hunk_key,
21876            comments_expanded: true,
21877            inline_edit_editors: HashMap::default(),
21878            inline_edit_subscriptions: HashMap::default(),
21879            user_avatar_uri,
21880            _subscription: subscription,
21881        });
21882
21883        // Focus the prompt editor
21884        let focus_handle = prompt_editor.focus_handle(cx);
21885        window.focus(&focus_handle, cx);
21886
21887        cx.notify();
21888    }
21889
21890    /// Dismisses all diff review overlays.
21891    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21892        if self.diff_review_overlays.is_empty() {
21893            return;
21894        }
21895        let block_ids: HashSet<_> = self
21896            .diff_review_overlays
21897            .drain(..)
21898            .map(|overlay| overlay.block_id)
21899            .collect();
21900        self.remove_blocks(block_ids, None, cx);
21901        cx.notify();
21902    }
21903
21904    /// Dismisses overlays that have no comments stored for their hunks.
21905    /// Keeps overlays that have at least one comment.
21906    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21907        let snapshot = self.buffer.read(cx).snapshot(cx);
21908
21909        // First, compute which overlays have comments (to avoid borrow issues with retain)
21910        let overlays_with_comments: Vec<bool> = self
21911            .diff_review_overlays
21912            .iter()
21913            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21914            .collect();
21915
21916        // Now collect block IDs to remove and retain overlays
21917        let mut block_ids_to_remove = HashSet::default();
21918        let mut index = 0;
21919        self.diff_review_overlays.retain(|overlay| {
21920            let has_comments = overlays_with_comments[index];
21921            index += 1;
21922            if !has_comments {
21923                block_ids_to_remove.insert(overlay.block_id);
21924            }
21925            has_comments
21926        });
21927
21928        if !block_ids_to_remove.is_empty() {
21929            self.remove_blocks(block_ids_to_remove, None, cx);
21930            cx.notify();
21931        }
21932    }
21933
21934    /// Refreshes the diff review overlay block to update its height and render function.
21935    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21936    fn refresh_diff_review_overlay_height(
21937        &mut self,
21938        hunk_key: &DiffHunkKey,
21939        _window: &mut Window,
21940        cx: &mut Context<Self>,
21941    ) {
21942        // Extract all needed data from overlay first to avoid borrow conflicts
21943        let snapshot = self.buffer.read(cx).snapshot(cx);
21944        let (comments_expanded, block_id, prompt_editor) = {
21945            let Some(overlay) = self
21946                .diff_review_overlays
21947                .iter()
21948                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21949            else {
21950                return;
21951            };
21952
21953            (
21954                overlay.comments_expanded,
21955                overlay.block_id,
21956                overlay.prompt_editor.clone(),
21957            )
21958        };
21959
21960        // Calculate new height
21961        let snapshot = self.buffer.read(cx).snapshot(cx);
21962        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21963
21964        // Update the block height using resize_blocks (avoids flicker)
21965        let mut heights = HashMap::default();
21966        heights.insert(block_id, new_height);
21967        self.resize_blocks(heights, None, cx);
21968
21969        // Update the render function using replace_blocks (avoids flicker)
21970        let hunk_key_for_render = hunk_key.clone();
21971        let editor_handle = cx.entity().downgrade();
21972        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21973            Arc::new(move |cx| {
21974                Self::render_diff_review_overlay(
21975                    &prompt_editor,
21976                    &hunk_key_for_render,
21977                    &editor_handle,
21978                    cx,
21979                )
21980            });
21981
21982        let mut renderers = HashMap::default();
21983        renderers.insert(block_id, render);
21984        self.replace_blocks(renderers, None, cx);
21985    }
21986
21987    /// Action handler for SubmitDiffReviewComment.
21988    pub fn submit_diff_review_comment_action(
21989        &mut self,
21990        _: &SubmitDiffReviewComment,
21991        window: &mut Window,
21992        cx: &mut Context<Self>,
21993    ) {
21994        self.submit_diff_review_comment(window, cx);
21995    }
21996
21997    /// Stores the diff review comment locally.
21998    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21999    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22000        // Find the overlay that currently has focus
22001        let overlay_index = self
22002            .diff_review_overlays
22003            .iter()
22004            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22005        let Some(overlay_index) = overlay_index else {
22006            return;
22007        };
22008        let overlay = &self.diff_review_overlays[overlay_index];
22009
22010        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22011        if comment_text.is_empty() {
22012            return;
22013        }
22014
22015        let anchor_range = overlay.anchor_range.clone();
22016        let hunk_key = overlay.hunk_key.clone();
22017
22018        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22019
22020        // Clear the prompt editor but keep the overlay open
22021        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22022            overlay.prompt_editor.update(cx, |editor, cx| {
22023                editor.clear(window, cx);
22024            });
22025        }
22026
22027        // Refresh the overlay to update the block height for the new comment
22028        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22029
22030        cx.notify();
22031    }
22032
22033    /// Returns the prompt editor for the diff review overlay, if one is active.
22034    /// This is primarily used for testing.
22035    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22036        self.diff_review_overlays
22037            .first()
22038            .map(|overlay| &overlay.prompt_editor)
22039    }
22040
22041    /// Returns the line range for the first diff review overlay, if one is active.
22042    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22043    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22044        let overlay = self.diff_review_overlays.first()?;
22045        let snapshot = self.buffer.read(cx).snapshot(cx);
22046        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22047        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22048        let start_row = snapshot
22049            .point_to_buffer_point(start_point)
22050            .map(|(_, p, _)| p.row)
22051            .unwrap_or(start_point.row);
22052        let end_row = snapshot
22053            .point_to_buffer_point(end_point)
22054            .map(|(_, p, _)| p.row)
22055            .unwrap_or(end_point.row);
22056        Some((start_row, end_row))
22057    }
22058
22059    /// Sets whether the comments section is expanded in the diff review overlay.
22060    /// This is primarily used for testing.
22061    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22062        for overlay in &mut self.diff_review_overlays {
22063            overlay.comments_expanded = expanded;
22064        }
22065        cx.notify();
22066    }
22067
22068    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22069    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22070        a.file_path == b.file_path
22071            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22072    }
22073
22074    /// Returns comments for a specific hunk, ordered by creation time.
22075    pub fn comments_for_hunk<'a>(
22076        &'a self,
22077        key: &DiffHunkKey,
22078        snapshot: &MultiBufferSnapshot,
22079    ) -> &'a [StoredReviewComment] {
22080        let key_point = key.hunk_start_anchor.to_point(snapshot);
22081        self.stored_review_comments
22082            .iter()
22083            .find(|(k, _)| {
22084                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22085            })
22086            .map(|(_, comments)| comments.as_slice())
22087            .unwrap_or(&[])
22088    }
22089
22090    /// Returns the total count of stored review comments across all hunks.
22091    pub fn total_review_comment_count(&self) -> usize {
22092        self.stored_review_comments
22093            .iter()
22094            .map(|(_, v)| v.len())
22095            .sum()
22096    }
22097
22098    /// Returns the count of comments for a specific hunk.
22099    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22100        let key_point = key.hunk_start_anchor.to_point(snapshot);
22101        self.stored_review_comments
22102            .iter()
22103            .find(|(k, _)| {
22104                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22105            })
22106            .map(|(_, v)| v.len())
22107            .unwrap_or(0)
22108    }
22109
22110    /// Adds a new review comment to a specific hunk.
22111    pub fn add_review_comment(
22112        &mut self,
22113        hunk_key: DiffHunkKey,
22114        comment: String,
22115        anchor_range: Range<Anchor>,
22116        cx: &mut Context<Self>,
22117    ) -> usize {
22118        let id = self.next_review_comment_id;
22119        self.next_review_comment_id += 1;
22120
22121        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22122
22123        let snapshot = self.buffer.read(cx).snapshot(cx);
22124        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22125
22126        // Find existing entry for this hunk or add a new one
22127        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22128            k.file_path == hunk_key.file_path
22129                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22130        }) {
22131            comments.push(stored_comment);
22132        } else {
22133            self.stored_review_comments
22134                .push((hunk_key, vec![stored_comment]));
22135        }
22136
22137        cx.emit(EditorEvent::ReviewCommentsChanged {
22138            total_count: self.total_review_comment_count(),
22139        });
22140        cx.notify();
22141        id
22142    }
22143
22144    /// Removes a review comment by ID from any hunk.
22145    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22146        for (_, comments) in self.stored_review_comments.iter_mut() {
22147            if let Some(index) = comments.iter().position(|c| c.id == id) {
22148                comments.remove(index);
22149                cx.emit(EditorEvent::ReviewCommentsChanged {
22150                    total_count: self.total_review_comment_count(),
22151                });
22152                cx.notify();
22153                return true;
22154            }
22155        }
22156        false
22157    }
22158
22159    /// Updates a review comment's text by ID.
22160    pub fn update_review_comment(
22161        &mut self,
22162        id: usize,
22163        new_comment: String,
22164        cx: &mut Context<Self>,
22165    ) -> bool {
22166        for (_, comments) in self.stored_review_comments.iter_mut() {
22167            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22168                comment.comment = new_comment;
22169                comment.is_editing = false;
22170                cx.emit(EditorEvent::ReviewCommentsChanged {
22171                    total_count: self.total_review_comment_count(),
22172                });
22173                cx.notify();
22174                return true;
22175            }
22176        }
22177        false
22178    }
22179
22180    /// Sets a comment's editing state.
22181    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22182        for (_, comments) in self.stored_review_comments.iter_mut() {
22183            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22184                comment.is_editing = is_editing;
22185                cx.notify();
22186                return;
22187            }
22188        }
22189    }
22190
22191    /// Takes all stored comments from all hunks, clearing the storage.
22192    /// Returns a Vec of (hunk_key, comments) pairs.
22193    pub fn take_all_review_comments(
22194        &mut self,
22195        cx: &mut Context<Self>,
22196    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22197        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22198        self.dismiss_all_diff_review_overlays(cx);
22199        let comments = std::mem::take(&mut self.stored_review_comments);
22200        // Reset the ID counter since all comments have been taken
22201        self.next_review_comment_id = 0;
22202        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22203        cx.notify();
22204        comments
22205    }
22206
22207    /// Removes review comments whose anchors are no longer valid or whose
22208    /// associated diff hunks no longer exist.
22209    ///
22210    /// This should be called when the buffer changes to prevent orphaned comments
22211    /// from accumulating.
22212    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22213        let snapshot = self.buffer.read(cx).snapshot(cx);
22214        let original_count = self.total_review_comment_count();
22215
22216        // Remove comments with invalid hunk anchors
22217        self.stored_review_comments
22218            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22219
22220        // Also clean up individual comments with invalid anchor ranges
22221        for (_, comments) in &mut self.stored_review_comments {
22222            comments.retain(|comment| {
22223                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22224            });
22225        }
22226
22227        // Remove empty hunk entries
22228        self.stored_review_comments
22229            .retain(|(_, comments)| !comments.is_empty());
22230
22231        let new_count = self.total_review_comment_count();
22232        if new_count != original_count {
22233            cx.emit(EditorEvent::ReviewCommentsChanged {
22234                total_count: new_count,
22235            });
22236            cx.notify();
22237        }
22238    }
22239
22240    /// Toggles the expanded state of the comments section in the overlay.
22241    pub fn toggle_review_comments_expanded(
22242        &mut self,
22243        _: &ToggleReviewCommentsExpanded,
22244        window: &mut Window,
22245        cx: &mut Context<Self>,
22246    ) {
22247        // Find the overlay that currently has focus, or use the first one
22248        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22249            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22250                overlay.comments_expanded = !overlay.comments_expanded;
22251                Some(overlay.hunk_key.clone())
22252            } else {
22253                None
22254            }
22255        });
22256
22257        // If no focused overlay found, toggle the first one
22258        let hunk_key = overlay_info.or_else(|| {
22259            self.diff_review_overlays.first_mut().map(|overlay| {
22260                overlay.comments_expanded = !overlay.comments_expanded;
22261                overlay.hunk_key.clone()
22262            })
22263        });
22264
22265        if let Some(hunk_key) = hunk_key {
22266            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22267            cx.notify();
22268        }
22269    }
22270
22271    /// Handles the EditReviewComment action - sets a comment into editing mode.
22272    pub fn edit_review_comment(
22273        &mut self,
22274        action: &EditReviewComment,
22275        window: &mut Window,
22276        cx: &mut Context<Self>,
22277    ) {
22278        let comment_id = action.id;
22279
22280        // Set the comment to editing mode
22281        self.set_comment_editing(comment_id, true, cx);
22282
22283        // Find the overlay that contains this comment and create an inline editor if needed
22284        // First, find which hunk this comment belongs to
22285        let hunk_key = self
22286            .stored_review_comments
22287            .iter()
22288            .find_map(|(key, comments)| {
22289                if comments.iter().any(|c| c.id == comment_id) {
22290                    Some(key.clone())
22291                } else {
22292                    None
22293                }
22294            });
22295
22296        let snapshot = self.buffer.read(cx).snapshot(cx);
22297        if let Some(hunk_key) = hunk_key {
22298            if let Some(overlay) = self
22299                .diff_review_overlays
22300                .iter_mut()
22301                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22302            {
22303                if let std::collections::hash_map::Entry::Vacant(entry) =
22304                    overlay.inline_edit_editors.entry(comment_id)
22305                {
22306                    // Find the comment text
22307                    let comment_text = self
22308                        .stored_review_comments
22309                        .iter()
22310                        .flat_map(|(_, comments)| comments)
22311                        .find(|c| c.id == comment_id)
22312                        .map(|c| c.comment.clone())
22313                        .unwrap_or_default();
22314
22315                    // Create inline editor
22316                    let parent_editor = cx.entity().downgrade();
22317                    let inline_editor = cx.new(|cx| {
22318                        let mut editor = Editor::single_line(window, cx);
22319                        editor.set_text(&*comment_text, window, cx);
22320                        // Select all text for easy replacement
22321                        editor.select_all(&crate::actions::SelectAll, window, cx);
22322                        editor
22323                    });
22324
22325                    // Register the Newline action to confirm the edit
22326                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22327                        inline_editor.register_action({
22328                            let parent_editor = parent_editor.clone();
22329                            move |_: &crate::actions::Newline, window, cx| {
22330                                if let Some(editor) = parent_editor.upgrade() {
22331                                    editor.update(cx, |editor, cx| {
22332                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22333                                    });
22334                                }
22335                            }
22336                        })
22337                    });
22338
22339                    // Store the subscription to keep the action handler alive
22340                    overlay
22341                        .inline_edit_subscriptions
22342                        .insert(comment_id, subscription);
22343
22344                    // Focus the inline editor
22345                    let focus_handle = inline_editor.focus_handle(cx);
22346                    window.focus(&focus_handle, cx);
22347
22348                    entry.insert(inline_editor);
22349                }
22350            }
22351        }
22352
22353        cx.notify();
22354    }
22355
22356    /// Confirms an inline edit of a review comment.
22357    pub fn confirm_edit_review_comment(
22358        &mut self,
22359        comment_id: usize,
22360        _window: &mut Window,
22361        cx: &mut Context<Self>,
22362    ) {
22363        // Get the new text from the inline editor
22364        // Find the overlay containing this comment's inline editor
22365        let snapshot = self.buffer.read(cx).snapshot(cx);
22366        let hunk_key = self
22367            .stored_review_comments
22368            .iter()
22369            .find_map(|(key, comments)| {
22370                if comments.iter().any(|c| c.id == comment_id) {
22371                    Some(key.clone())
22372                } else {
22373                    None
22374                }
22375            });
22376
22377        let new_text = hunk_key
22378            .as_ref()
22379            .and_then(|hunk_key| {
22380                self.diff_review_overlays
22381                    .iter()
22382                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22383            })
22384            .as_ref()
22385            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22386            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22387
22388        if let Some(new_text) = new_text {
22389            if !new_text.is_empty() {
22390                self.update_review_comment(comment_id, new_text, cx);
22391            }
22392        }
22393
22394        // Remove the inline editor and its subscription
22395        if let Some(hunk_key) = hunk_key {
22396            if let Some(overlay) = self
22397                .diff_review_overlays
22398                .iter_mut()
22399                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22400            {
22401                overlay.inline_edit_editors.remove(&comment_id);
22402                overlay.inline_edit_subscriptions.remove(&comment_id);
22403            }
22404        }
22405
22406        // Clear editing state
22407        self.set_comment_editing(comment_id, false, cx);
22408    }
22409
22410    /// Cancels an inline edit of a review comment.
22411    pub fn cancel_edit_review_comment(
22412        &mut self,
22413        comment_id: usize,
22414        _window: &mut Window,
22415        cx: &mut Context<Self>,
22416    ) {
22417        // Find which hunk this comment belongs to
22418        let hunk_key = self
22419            .stored_review_comments
22420            .iter()
22421            .find_map(|(key, comments)| {
22422                if comments.iter().any(|c| c.id == comment_id) {
22423                    Some(key.clone())
22424                } else {
22425                    None
22426                }
22427            });
22428
22429        // Remove the inline editor and its subscription
22430        if let Some(hunk_key) = hunk_key {
22431            let snapshot = self.buffer.read(cx).snapshot(cx);
22432            if let Some(overlay) = self
22433                .diff_review_overlays
22434                .iter_mut()
22435                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22436            {
22437                overlay.inline_edit_editors.remove(&comment_id);
22438                overlay.inline_edit_subscriptions.remove(&comment_id);
22439            }
22440        }
22441
22442        // Clear editing state
22443        self.set_comment_editing(comment_id, false, cx);
22444    }
22445
22446    /// Action handler for ConfirmEditReviewComment.
22447    pub fn confirm_edit_review_comment_action(
22448        &mut self,
22449        action: &ConfirmEditReviewComment,
22450        window: &mut Window,
22451        cx: &mut Context<Self>,
22452    ) {
22453        self.confirm_edit_review_comment(action.id, window, cx);
22454    }
22455
22456    /// Action handler for CancelEditReviewComment.
22457    pub fn cancel_edit_review_comment_action(
22458        &mut self,
22459        action: &CancelEditReviewComment,
22460        window: &mut Window,
22461        cx: &mut Context<Self>,
22462    ) {
22463        self.cancel_edit_review_comment(action.id, window, cx);
22464    }
22465
22466    /// Handles the DeleteReviewComment action - removes a comment.
22467    pub fn delete_review_comment(
22468        &mut self,
22469        action: &DeleteReviewComment,
22470        window: &mut Window,
22471        cx: &mut Context<Self>,
22472    ) {
22473        // Get the hunk key before removing the comment
22474        // Find the hunk key from the comment itself
22475        let comment_id = action.id;
22476        let hunk_key = self
22477            .stored_review_comments
22478            .iter()
22479            .find_map(|(key, comments)| {
22480                if comments.iter().any(|c| c.id == comment_id) {
22481                    Some(key.clone())
22482                } else {
22483                    None
22484                }
22485            });
22486
22487        // Also get it from the overlay for refresh purposes
22488        let overlay_hunk_key = self
22489            .diff_review_overlays
22490            .first()
22491            .map(|o| o.hunk_key.clone());
22492
22493        self.remove_review_comment(action.id, cx);
22494
22495        // Refresh the overlay height after removing a comment
22496        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22497            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22498        }
22499    }
22500
22501    fn render_diff_review_overlay(
22502        prompt_editor: &Entity<Editor>,
22503        hunk_key: &DiffHunkKey,
22504        editor_handle: &WeakEntity<Editor>,
22505        cx: &mut BlockContext,
22506    ) -> AnyElement {
22507        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22508            if ranges.is_empty() {
22509                return None;
22510            }
22511            let formatted: Vec<String> = ranges
22512                .iter()
22513                .map(|(start, end)| {
22514                    let start_line = start + 1;
22515                    let end_line = end + 1;
22516                    if start_line == end_line {
22517                        format!("Line {start_line}")
22518                    } else {
22519                        format!("Lines {start_line}-{end_line}")
22520                    }
22521                })
22522                .collect();
22523            // Don't show label for single line in single excerpt
22524            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22525                return None;
22526            }
22527            Some(formatted.join(""))
22528        }
22529
22530        let theme = cx.theme();
22531        let colors = theme.colors();
22532
22533        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22534            editor_handle
22535                .upgrade()
22536                .map(|editor| {
22537                    let editor = editor.read(cx);
22538                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22539                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22540                    let (expanded, editors, avatar_uri, line_ranges) = editor
22541                        .diff_review_overlays
22542                        .iter()
22543                        .find(|overlay| {
22544                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22545                        })
22546                        .map(|o| {
22547                            let start_point = o.anchor_range.start.to_point(&snapshot);
22548                            let end_point = o.anchor_range.end.to_point(&snapshot);
22549                            // Get line ranges per excerpt to detect discontinuities
22550                            let buffer_ranges =
22551                                snapshot.range_to_buffer_ranges(start_point..end_point);
22552                            let ranges: Vec<(u32, u32)> = buffer_ranges
22553                                .iter()
22554                                .map(|(buffer, range, _)| {
22555                                    let start = buffer.offset_to_point(range.start.0).row;
22556                                    let end = buffer.offset_to_point(range.end.0).row;
22557                                    (start, end)
22558                                })
22559                                .collect();
22560                            (
22561                                o.comments_expanded,
22562                                o.inline_edit_editors.clone(),
22563                                o.user_avatar_uri.clone(),
22564                                if ranges.is_empty() {
22565                                    None
22566                                } else {
22567                                    Some(ranges)
22568                                },
22569                            )
22570                        })
22571                        .unwrap_or((true, HashMap::default(), None, None));
22572                    (comments, expanded, editors, avatar_uri, line_ranges)
22573                })
22574                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22575
22576        let comment_count = comments.len();
22577        let avatar_size = px(20.);
22578        let action_icon_size = IconSize::XSmall;
22579
22580        v_flex()
22581            .w_full()
22582            .bg(colors.editor_background)
22583            .border_b_1()
22584            .border_color(colors.border)
22585            .px_2()
22586            .pb_2()
22587            .gap_2()
22588            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22589            .when_some(line_ranges, |el, ranges| {
22590                let label = format_line_ranges(&ranges);
22591                if let Some(label) = label {
22592                    el.child(
22593                        h_flex()
22594                            .w_full()
22595                            .px_2()
22596                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22597                    )
22598                } else {
22599                    el
22600                }
22601            })
22602            // Top row: editable input with user's avatar
22603            .child(
22604                h_flex()
22605                    .w_full()
22606                    .items_center()
22607                    .gap_2()
22608                    .px_2()
22609                    .py_1p5()
22610                    .rounded_md()
22611                    .bg(colors.surface_background)
22612                    .child(
22613                        div()
22614                            .size(avatar_size)
22615                            .flex_shrink_0()
22616                            .rounded_full()
22617                            .overflow_hidden()
22618                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22619                                Avatar::new(avatar_uri.clone())
22620                                    .size(avatar_size)
22621                                    .into_any_element()
22622                            } else {
22623                                Icon::new(IconName::Person)
22624                                    .size(IconSize::Small)
22625                                    .color(ui::Color::Muted)
22626                                    .into_any_element()
22627                            }),
22628                    )
22629                    .child(
22630                        div()
22631                            .flex_1()
22632                            .border_1()
22633                            .border_color(colors.border)
22634                            .rounded_md()
22635                            .bg(colors.editor_background)
22636                            .px_2()
22637                            .py_1()
22638                            .child(prompt_editor.clone()),
22639                    )
22640                    .child(
22641                        h_flex()
22642                            .flex_shrink_0()
22643                            .gap_1()
22644                            .child(
22645                                IconButton::new("diff-review-close", IconName::Close)
22646                                    .icon_color(ui::Color::Muted)
22647                                    .icon_size(action_icon_size)
22648                                    .tooltip(Tooltip::text("Close"))
22649                                    .on_click(|_, window, cx| {
22650                                        window
22651                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22652                                    }),
22653                            )
22654                            .child(
22655                                IconButton::new("diff-review-add", IconName::Return)
22656                                    .icon_color(ui::Color::Muted)
22657                                    .icon_size(action_icon_size)
22658                                    .tooltip(Tooltip::text("Add comment"))
22659                                    .on_click(|_, window, cx| {
22660                                        window.dispatch_action(
22661                                            Box::new(crate::actions::SubmitDiffReviewComment),
22662                                            cx,
22663                                        );
22664                                    }),
22665                            ),
22666                    ),
22667            )
22668            // Expandable comments section (only shown when there are comments)
22669            .when(comment_count > 0, |el| {
22670                el.child(Self::render_comments_section(
22671                    comments,
22672                    comments_expanded,
22673                    inline_editors,
22674                    user_avatar_uri,
22675                    avatar_size,
22676                    action_icon_size,
22677                    colors,
22678                ))
22679            })
22680            .into_any_element()
22681    }
22682
22683    fn render_comments_section(
22684        comments: Vec<StoredReviewComment>,
22685        expanded: bool,
22686        inline_editors: HashMap<usize, Entity<Editor>>,
22687        user_avatar_uri: Option<SharedUri>,
22688        avatar_size: Pixels,
22689        action_icon_size: IconSize,
22690        colors: &theme::ThemeColors,
22691    ) -> impl IntoElement {
22692        let comment_count = comments.len();
22693
22694        v_flex()
22695            .w_full()
22696            .gap_1()
22697            // Header with expand/collapse toggle
22698            .child(
22699                h_flex()
22700                    .id("review-comments-header")
22701                    .w_full()
22702                    .items_center()
22703                    .gap_1()
22704                    .px_2()
22705                    .py_1()
22706                    .cursor_pointer()
22707                    .rounded_md()
22708                    .hover(|style| style.bg(colors.ghost_element_hover))
22709                    .on_click(|_, window: &mut Window, cx| {
22710                        window.dispatch_action(
22711                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22712                            cx,
22713                        );
22714                    })
22715                    .child(
22716                        Icon::new(if expanded {
22717                            IconName::ChevronDown
22718                        } else {
22719                            IconName::ChevronRight
22720                        })
22721                        .size(IconSize::Small)
22722                        .color(ui::Color::Muted),
22723                    )
22724                    .child(
22725                        Label::new(format!(
22726                            "{} Comment{}",
22727                            comment_count,
22728                            if comment_count == 1 { "" } else { "s" }
22729                        ))
22730                        .size(LabelSize::Small)
22731                        .color(Color::Muted),
22732                    ),
22733            )
22734            // Comments list (when expanded)
22735            .when(expanded, |el| {
22736                el.children(comments.into_iter().map(|comment| {
22737                    let inline_editor = inline_editors.get(&comment.id).cloned();
22738                    Self::render_comment_row(
22739                        comment,
22740                        inline_editor,
22741                        user_avatar_uri.clone(),
22742                        avatar_size,
22743                        action_icon_size,
22744                        colors,
22745                    )
22746                }))
22747            })
22748    }
22749
22750    fn render_comment_row(
22751        comment: StoredReviewComment,
22752        inline_editor: Option<Entity<Editor>>,
22753        user_avatar_uri: Option<SharedUri>,
22754        avatar_size: Pixels,
22755        action_icon_size: IconSize,
22756        colors: &theme::ThemeColors,
22757    ) -> impl IntoElement {
22758        let comment_id = comment.id;
22759        let is_editing = inline_editor.is_some();
22760
22761        h_flex()
22762            .w_full()
22763            .items_center()
22764            .gap_2()
22765            .px_2()
22766            .py_1p5()
22767            .rounded_md()
22768            .bg(colors.surface_background)
22769            .child(
22770                div()
22771                    .size(avatar_size)
22772                    .flex_shrink_0()
22773                    .rounded_full()
22774                    .overflow_hidden()
22775                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22776                        Avatar::new(avatar_uri.clone())
22777                            .size(avatar_size)
22778                            .into_any_element()
22779                    } else {
22780                        Icon::new(IconName::Person)
22781                            .size(IconSize::Small)
22782                            .color(ui::Color::Muted)
22783                            .into_any_element()
22784                    }),
22785            )
22786            .child(if let Some(editor) = inline_editor {
22787                // Inline edit mode: show an editable text field
22788                div()
22789                    .flex_1()
22790                    .border_1()
22791                    .border_color(colors.border)
22792                    .rounded_md()
22793                    .bg(colors.editor_background)
22794                    .px_2()
22795                    .py_1()
22796                    .child(editor)
22797                    .into_any_element()
22798            } else {
22799                // Display mode: show the comment text
22800                div()
22801                    .flex_1()
22802                    .text_sm()
22803                    .text_color(colors.text)
22804                    .child(comment.comment)
22805                    .into_any_element()
22806            })
22807            .child(if is_editing {
22808                // Editing mode: show close and confirm buttons
22809                h_flex()
22810                    .gap_1()
22811                    .child(
22812                        IconButton::new(
22813                            format!("diff-review-cancel-edit-{comment_id}"),
22814                            IconName::Close,
22815                        )
22816                        .icon_color(ui::Color::Muted)
22817                        .icon_size(action_icon_size)
22818                        .tooltip(Tooltip::text("Cancel"))
22819                        .on_click(move |_, window, cx| {
22820                            window.dispatch_action(
22821                                Box::new(crate::actions::CancelEditReviewComment {
22822                                    id: comment_id,
22823                                }),
22824                                cx,
22825                            );
22826                        }),
22827                    )
22828                    .child(
22829                        IconButton::new(
22830                            format!("diff-review-confirm-edit-{comment_id}"),
22831                            IconName::Return,
22832                        )
22833                        .icon_color(ui::Color::Muted)
22834                        .icon_size(action_icon_size)
22835                        .tooltip(Tooltip::text("Confirm"))
22836                        .on_click(move |_, window, cx| {
22837                            window.dispatch_action(
22838                                Box::new(crate::actions::ConfirmEditReviewComment {
22839                                    id: comment_id,
22840                                }),
22841                                cx,
22842                            );
22843                        }),
22844                    )
22845                    .into_any_element()
22846            } else {
22847                // Display mode: no action buttons for now (edit/delete not yet implemented)
22848                gpui::Empty.into_any_element()
22849            })
22850    }
22851
22852    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22853        if self.display_map.read(cx).masked != masked {
22854            self.display_map.update(cx, |map, _| map.masked = masked);
22855        }
22856        cx.notify()
22857    }
22858
22859    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22860        self.show_wrap_guides = Some(show_wrap_guides);
22861        cx.notify();
22862    }
22863
22864    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22865        self.show_indent_guides = Some(show_indent_guides);
22866        cx.notify();
22867    }
22868
22869    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22870        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22871            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22872                && let Some(dir) = file.abs_path(cx).parent()
22873            {
22874                return Some(dir.to_owned());
22875            }
22876        }
22877
22878        None
22879    }
22880
22881    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22882        self.active_excerpt(cx)?
22883            .1
22884            .read(cx)
22885            .file()
22886            .and_then(|f| f.as_local())
22887    }
22888
22889    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22890        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22891            let buffer = buffer.read(cx);
22892            if let Some(project_path) = buffer.project_path(cx) {
22893                let project = self.project()?.read(cx);
22894                project.absolute_path(&project_path, cx)
22895            } else {
22896                buffer
22897                    .file()
22898                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22899            }
22900        })
22901    }
22902
22903    pub fn reveal_in_finder(
22904        &mut self,
22905        _: &RevealInFileManager,
22906        _window: &mut Window,
22907        cx: &mut Context<Self>,
22908    ) {
22909        if let Some(path) = self.target_file_abs_path(cx) {
22910            if let Some(project) = self.project() {
22911                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22912            } else {
22913                cx.reveal_path(&path);
22914            }
22915        }
22916    }
22917
22918    pub fn copy_path(
22919        &mut self,
22920        _: &zed_actions::workspace::CopyPath,
22921        _window: &mut Window,
22922        cx: &mut Context<Self>,
22923    ) {
22924        if let Some(path) = self.target_file_abs_path(cx)
22925            && let Some(path) = path.to_str()
22926        {
22927            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22928        } else {
22929            cx.propagate();
22930        }
22931    }
22932
22933    pub fn copy_relative_path(
22934        &mut self,
22935        _: &zed_actions::workspace::CopyRelativePath,
22936        _window: &mut Window,
22937        cx: &mut Context<Self>,
22938    ) {
22939        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22940            let project = self.project()?.read(cx);
22941            let path = buffer.read(cx).file()?.path();
22942            let path = path.display(project.path_style(cx));
22943            Some(path)
22944        }) {
22945            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22946        } else {
22947            cx.propagate();
22948        }
22949    }
22950
22951    /// Returns the project path for the editor's buffer, if any buffer is
22952    /// opened in the editor.
22953    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22954        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22955            buffer.read(cx).project_path(cx)
22956        } else {
22957            None
22958        }
22959    }
22960
22961    // Returns true if the editor handled a go-to-line request
22962    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22963        maybe!({
22964            let breakpoint_store = self.breakpoint_store.as_ref()?;
22965
22966            let (active_stack_frame, debug_line_pane_id) = {
22967                let store = breakpoint_store.read(cx);
22968                let active_stack_frame = store.active_position().cloned();
22969                let debug_line_pane_id = store.active_debug_line_pane_id();
22970                (active_stack_frame, debug_line_pane_id)
22971            };
22972
22973            let Some(active_stack_frame) = active_stack_frame else {
22974                self.clear_row_highlights::<ActiveDebugLine>();
22975                return None;
22976            };
22977
22978            if let Some(debug_line_pane_id) = debug_line_pane_id {
22979                if let Some(workspace) = self
22980                    .workspace
22981                    .as_ref()
22982                    .and_then(|(workspace, _)| workspace.upgrade())
22983                {
22984                    let editor_pane_id = workspace
22985                        .read(cx)
22986                        .pane_for_item_id(cx.entity_id())
22987                        .map(|pane| pane.entity_id());
22988
22989                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
22990                        self.clear_row_highlights::<ActiveDebugLine>();
22991                        return None;
22992                    }
22993                }
22994            }
22995
22996            let position = active_stack_frame.position;
22997            let buffer_id = position.buffer_id?;
22998            let snapshot = self
22999                .project
23000                .as_ref()?
23001                .read(cx)
23002                .buffer_for_id(buffer_id, cx)?
23003                .read(cx)
23004                .snapshot();
23005
23006            let mut handled = false;
23007            for (id, _, ExcerptRange { context, .. }) in
23008                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
23009            {
23010                if context.start.cmp(&position, &snapshot).is_ge()
23011                    || context.end.cmp(&position, &snapshot).is_lt()
23012                {
23013                    continue;
23014                }
23015                let snapshot = self.buffer.read(cx).snapshot(cx);
23016                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
23017
23018                handled = true;
23019                self.clear_row_highlights::<ActiveDebugLine>();
23020
23021                self.go_to_line::<ActiveDebugLine>(
23022                    multibuffer_anchor,
23023                    Some(cx.theme().colors().editor_debugger_active_line_background),
23024                    window,
23025                    cx,
23026                );
23027
23028                cx.notify();
23029            }
23030
23031            handled.then_some(())
23032        })
23033        .is_some()
23034    }
23035
23036    pub fn copy_file_name_without_extension(
23037        &mut self,
23038        _: &CopyFileNameWithoutExtension,
23039        _: &mut Window,
23040        cx: &mut Context<Self>,
23041    ) {
23042        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23043            let file = buffer.read(cx).file()?;
23044            file.path().file_stem()
23045        }) {
23046            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23047        }
23048    }
23049
23050    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23051        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23052            let file = buffer.read(cx).file()?;
23053            Some(file.file_name(cx))
23054        }) {
23055            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23056        }
23057    }
23058
23059    pub fn toggle_git_blame(
23060        &mut self,
23061        _: &::git::Blame,
23062        window: &mut Window,
23063        cx: &mut Context<Self>,
23064    ) {
23065        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23066
23067        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23068            self.start_git_blame(true, window, cx);
23069        }
23070
23071        cx.notify();
23072    }
23073
23074    pub fn toggle_git_blame_inline(
23075        &mut self,
23076        _: &ToggleGitBlameInline,
23077        window: &mut Window,
23078        cx: &mut Context<Self>,
23079    ) {
23080        self.toggle_git_blame_inline_internal(true, window, cx);
23081        cx.notify();
23082    }
23083
23084    pub fn open_git_blame_commit(
23085        &mut self,
23086        _: &OpenGitBlameCommit,
23087        window: &mut Window,
23088        cx: &mut Context<Self>,
23089    ) {
23090        self.open_git_blame_commit_internal(window, cx);
23091    }
23092
23093    fn open_git_blame_commit_internal(
23094        &mut self,
23095        window: &mut Window,
23096        cx: &mut Context<Self>,
23097    ) -> Option<()> {
23098        let blame = self.blame.as_ref()?;
23099        let snapshot = self.snapshot(window, cx);
23100        let cursor = self
23101            .selections
23102            .newest::<Point>(&snapshot.display_snapshot)
23103            .head();
23104        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23105        let (_, blame_entry) = blame
23106            .update(cx, |blame, cx| {
23107                blame
23108                    .blame_for_rows(
23109                        &[RowInfo {
23110                            buffer_id: Some(buffer.remote_id()),
23111                            buffer_row: Some(point.row),
23112                            ..Default::default()
23113                        }],
23114                        cx,
23115                    )
23116                    .next()
23117            })
23118            .flatten()?;
23119        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23120        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23121        let workspace = self.workspace()?.downgrade();
23122        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23123        None
23124    }
23125
23126    pub fn git_blame_inline_enabled(&self) -> bool {
23127        self.git_blame_inline_enabled
23128    }
23129
23130    pub fn toggle_selection_menu(
23131        &mut self,
23132        _: &ToggleSelectionMenu,
23133        _: &mut Window,
23134        cx: &mut Context<Self>,
23135    ) {
23136        self.show_selection_menu = self
23137            .show_selection_menu
23138            .map(|show_selections_menu| !show_selections_menu)
23139            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23140
23141        cx.notify();
23142    }
23143
23144    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23145        self.show_selection_menu
23146            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23147    }
23148
23149    fn start_git_blame(
23150        &mut self,
23151        user_triggered: bool,
23152        window: &mut Window,
23153        cx: &mut Context<Self>,
23154    ) {
23155        if let Some(project) = self.project() {
23156            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23157                && buffer.read(cx).file().is_none()
23158            {
23159                return;
23160            }
23161
23162            let focused = self.focus_handle(cx).contains_focused(window, cx);
23163
23164            let project = project.clone();
23165            let blame = cx
23166                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23167            self.blame_subscription =
23168                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23169            self.blame = Some(blame);
23170        }
23171    }
23172
23173    fn toggle_git_blame_inline_internal(
23174        &mut self,
23175        user_triggered: bool,
23176        window: &mut Window,
23177        cx: &mut Context<Self>,
23178    ) {
23179        if self.git_blame_inline_enabled {
23180            self.git_blame_inline_enabled = false;
23181            self.show_git_blame_inline = false;
23182            self.show_git_blame_inline_delay_task.take();
23183        } else {
23184            self.git_blame_inline_enabled = true;
23185            self.start_git_blame_inline(user_triggered, window, cx);
23186        }
23187
23188        cx.notify();
23189    }
23190
23191    fn start_git_blame_inline(
23192        &mut self,
23193        user_triggered: bool,
23194        window: &mut Window,
23195        cx: &mut Context<Self>,
23196    ) {
23197        self.start_git_blame(user_triggered, window, cx);
23198
23199        if ProjectSettings::get_global(cx)
23200            .git
23201            .inline_blame_delay()
23202            .is_some()
23203        {
23204            self.start_inline_blame_timer(window, cx);
23205        } else {
23206            self.show_git_blame_inline = true
23207        }
23208    }
23209
23210    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23211        self.blame.as_ref()
23212    }
23213
23214    pub fn show_git_blame_gutter(&self) -> bool {
23215        self.show_git_blame_gutter
23216    }
23217
23218    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23219        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23220    }
23221
23222    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23223        self.show_git_blame_inline
23224            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23225            && !self.newest_selection_head_on_empty_line(cx)
23226            && self.has_blame_entries(cx)
23227    }
23228
23229    fn has_blame_entries(&self, cx: &App) -> bool {
23230        self.blame()
23231            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23232    }
23233
23234    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23235        let cursor_anchor = self.selections.newest_anchor().head();
23236
23237        let snapshot = self.buffer.read(cx).snapshot(cx);
23238        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23239
23240        snapshot.line_len(buffer_row) == 0
23241    }
23242
23243    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23244        let buffer_and_selection = maybe!({
23245            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23246            let selection_range = selection.range();
23247
23248            let multi_buffer = self.buffer().read(cx);
23249            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23250            let buffer_ranges = multi_buffer_snapshot
23251                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
23252
23253            let (buffer, range, _) = if selection.reversed {
23254                buffer_ranges.first()
23255            } else {
23256                buffer_ranges.last()
23257            }?;
23258
23259            let buffer_range = range.to_point(buffer);
23260
23261            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
23262                return Some((
23263                    multi_buffer.buffer(buffer.remote_id()).unwrap(),
23264                    buffer_range.start.row..buffer_range.end.row,
23265                ));
23266            };
23267
23268            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23269            let start =
23270                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.start, buffer);
23271            let end =
23272                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.end, buffer);
23273
23274            Some((
23275                multi_buffer.buffer(buffer.remote_id()).unwrap(),
23276                start.row..end.row,
23277            ))
23278        });
23279
23280        let Some((buffer, selection)) = buffer_and_selection else {
23281            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23282        };
23283
23284        let Some(project) = self.project() else {
23285            return Task::ready(Err(anyhow!("editor does not have project")));
23286        };
23287
23288        project.update(cx, |project, cx| {
23289            project.get_permalink_to_line(&buffer, selection, cx)
23290        })
23291    }
23292
23293    pub fn copy_permalink_to_line(
23294        &mut self,
23295        _: &CopyPermalinkToLine,
23296        window: &mut Window,
23297        cx: &mut Context<Self>,
23298    ) {
23299        let permalink_task = self.get_permalink_to_line(cx);
23300        let workspace = self.workspace();
23301
23302        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23303            Ok(permalink) => {
23304                cx.update(|_, cx| {
23305                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23306                })
23307                .ok();
23308            }
23309            Err(err) => {
23310                let message = format!("Failed to copy permalink: {err}");
23311
23312                anyhow::Result::<()>::Err(err).log_err();
23313
23314                if let Some(workspace) = workspace {
23315                    workspace
23316                        .update_in(cx, |workspace, _, cx| {
23317                            struct CopyPermalinkToLine;
23318
23319                            workspace.show_toast(
23320                                Toast::new(
23321                                    NotificationId::unique::<CopyPermalinkToLine>(),
23322                                    message,
23323                                ),
23324                                cx,
23325                            )
23326                        })
23327                        .ok();
23328                }
23329            }
23330        })
23331        .detach();
23332    }
23333
23334    pub fn copy_file_location(
23335        &mut self,
23336        _: &CopyFileLocation,
23337        _: &mut Window,
23338        cx: &mut Context<Self>,
23339    ) {
23340        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23341
23342        let start_line = selection.start.row + 1;
23343        let end_line = selection.end.row + 1;
23344
23345        let end_line = if selection.end.column == 0 && end_line > start_line {
23346            end_line - 1
23347        } else {
23348            end_line
23349        };
23350
23351        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23352            let project = self.project()?.read(cx);
23353            let file = buffer.read(cx).file()?;
23354            let path = file.path().display(project.path_style(cx));
23355
23356            let location = if start_line == end_line {
23357                format!("{path}:{start_line}")
23358            } else {
23359                format!("{path}:{start_line}-{end_line}")
23360            };
23361            Some(location)
23362        }) {
23363            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23364        }
23365    }
23366
23367    pub fn open_permalink_to_line(
23368        &mut self,
23369        _: &OpenPermalinkToLine,
23370        window: &mut Window,
23371        cx: &mut Context<Self>,
23372    ) {
23373        let permalink_task = self.get_permalink_to_line(cx);
23374        let workspace = self.workspace();
23375
23376        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23377            Ok(permalink) => {
23378                cx.update(|_, cx| {
23379                    cx.open_url(permalink.as_ref());
23380                })
23381                .ok();
23382            }
23383            Err(err) => {
23384                let message = format!("Failed to open permalink: {err}");
23385
23386                anyhow::Result::<()>::Err(err).log_err();
23387
23388                if let Some(workspace) = workspace {
23389                    workspace.update(cx, |workspace, cx| {
23390                        struct OpenPermalinkToLine;
23391
23392                        workspace.show_toast(
23393                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23394                            cx,
23395                        )
23396                    });
23397                }
23398            }
23399        })
23400        .detach();
23401    }
23402
23403    pub fn insert_uuid_v4(
23404        &mut self,
23405        _: &InsertUuidV4,
23406        window: &mut Window,
23407        cx: &mut Context<Self>,
23408    ) {
23409        self.insert_uuid(UuidVersion::V4, window, cx);
23410    }
23411
23412    pub fn insert_uuid_v7(
23413        &mut self,
23414        _: &InsertUuidV7,
23415        window: &mut Window,
23416        cx: &mut Context<Self>,
23417    ) {
23418        self.insert_uuid(UuidVersion::V7, window, cx);
23419    }
23420
23421    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23422        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23423        self.transact(window, cx, |this, window, cx| {
23424            let edits = this
23425                .selections
23426                .all::<Point>(&this.display_snapshot(cx))
23427                .into_iter()
23428                .map(|selection| {
23429                    let uuid = match version {
23430                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23431                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23432                    };
23433
23434                    (selection.range(), uuid.to_string())
23435                });
23436            this.edit(edits, cx);
23437            this.refresh_edit_prediction(true, false, window, cx);
23438        });
23439    }
23440
23441    pub fn open_selections_in_multibuffer(
23442        &mut self,
23443        _: &OpenSelectionsInMultibuffer,
23444        window: &mut Window,
23445        cx: &mut Context<Self>,
23446    ) {
23447        let multibuffer = self.buffer.read(cx);
23448
23449        let Some(buffer) = multibuffer.as_singleton() else {
23450            return;
23451        };
23452
23453        let Some(workspace) = self.workspace() else {
23454            return;
23455        };
23456
23457        let title = multibuffer.title(cx).to_string();
23458
23459        let locations = self
23460            .selections
23461            .all_anchors(&self.display_snapshot(cx))
23462            .iter()
23463            .map(|selection| {
23464                (
23465                    buffer.clone(),
23466                    (selection.start.text_anchor..selection.end.text_anchor)
23467                        .to_point(buffer.read(cx)),
23468                )
23469            })
23470            .into_group_map();
23471
23472        cx.spawn_in(window, async move |_, cx| {
23473            workspace.update_in(cx, |workspace, window, cx| {
23474                Self::open_locations_in_multibuffer(
23475                    workspace,
23476                    locations,
23477                    format!("Selections for '{title}'"),
23478                    false,
23479                    false,
23480                    MultibufferSelectionMode::All,
23481                    window,
23482                    cx,
23483                );
23484            })
23485        })
23486        .detach();
23487    }
23488
23489    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23490    /// last highlight added will be used.
23491    ///
23492    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23493    pub fn highlight_rows<T: 'static>(
23494        &mut self,
23495        range: Range<Anchor>,
23496        color: Hsla,
23497        options: RowHighlightOptions,
23498        cx: &mut Context<Self>,
23499    ) {
23500        let snapshot = self.buffer().read(cx).snapshot(cx);
23501        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23502        let ix = row_highlights.binary_search_by(|highlight| {
23503            Ordering::Equal
23504                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23505                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23506        });
23507
23508        if let Err(mut ix) = ix {
23509            let index = post_inc(&mut self.highlight_order);
23510
23511            // If this range intersects with the preceding highlight, then merge it with
23512            // the preceding highlight. Otherwise insert a new highlight.
23513            let mut merged = false;
23514            if ix > 0 {
23515                let prev_highlight = &mut row_highlights[ix - 1];
23516                if prev_highlight
23517                    .range
23518                    .end
23519                    .cmp(&range.start, &snapshot)
23520                    .is_ge()
23521                {
23522                    ix -= 1;
23523                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23524                        prev_highlight.range.end = range.end;
23525                    }
23526                    merged = true;
23527                    prev_highlight.index = index;
23528                    prev_highlight.color = color;
23529                    prev_highlight.options = options;
23530                }
23531            }
23532
23533            if !merged {
23534                row_highlights.insert(
23535                    ix,
23536                    RowHighlight {
23537                        range,
23538                        index,
23539                        color,
23540                        options,
23541                        type_id: TypeId::of::<T>(),
23542                    },
23543                );
23544            }
23545
23546            // If any of the following highlights intersect with this one, merge them.
23547            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23548                let highlight = &row_highlights[ix];
23549                if next_highlight
23550                    .range
23551                    .start
23552                    .cmp(&highlight.range.end, &snapshot)
23553                    .is_le()
23554                {
23555                    if next_highlight
23556                        .range
23557                        .end
23558                        .cmp(&highlight.range.end, &snapshot)
23559                        .is_gt()
23560                    {
23561                        row_highlights[ix].range.end = next_highlight.range.end;
23562                    }
23563                    row_highlights.remove(ix + 1);
23564                } else {
23565                    break;
23566                }
23567            }
23568        }
23569    }
23570
23571    /// Remove any highlighted row ranges of the given type that intersect the
23572    /// given ranges.
23573    pub fn remove_highlighted_rows<T: 'static>(
23574        &mut self,
23575        ranges_to_remove: Vec<Range<Anchor>>,
23576        cx: &mut Context<Self>,
23577    ) {
23578        let snapshot = self.buffer().read(cx).snapshot(cx);
23579        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23580        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23581        row_highlights.retain(|highlight| {
23582            while let Some(range_to_remove) = ranges_to_remove.peek() {
23583                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23584                    Ordering::Less | Ordering::Equal => {
23585                        ranges_to_remove.next();
23586                    }
23587                    Ordering::Greater => {
23588                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23589                            Ordering::Less | Ordering::Equal => {
23590                                return false;
23591                            }
23592                            Ordering::Greater => break,
23593                        }
23594                    }
23595                }
23596            }
23597
23598            true
23599        })
23600    }
23601
23602    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23603    pub fn clear_row_highlights<T: 'static>(&mut self) {
23604        self.highlighted_rows.remove(&TypeId::of::<T>());
23605    }
23606
23607    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23608    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23609        self.highlighted_rows
23610            .get(&TypeId::of::<T>())
23611            .map_or(&[] as &[_], |vec| vec.as_slice())
23612            .iter()
23613            .map(|highlight| (highlight.range.clone(), highlight.color))
23614    }
23615
23616    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23617    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23618    /// Allows to ignore certain kinds of highlights.
23619    pub fn highlighted_display_rows(
23620        &self,
23621        window: &mut Window,
23622        cx: &mut App,
23623    ) -> BTreeMap<DisplayRow, LineHighlight> {
23624        let snapshot = self.snapshot(window, cx);
23625        let mut used_highlight_orders = HashMap::default();
23626        self.highlighted_rows
23627            .iter()
23628            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23629            .fold(
23630                BTreeMap::<DisplayRow, LineHighlight>::new(),
23631                |mut unique_rows, highlight| {
23632                    let start = highlight.range.start.to_display_point(&snapshot);
23633                    let end = highlight.range.end.to_display_point(&snapshot);
23634                    let start_row = start.row().0;
23635                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
23636                    {
23637                        end.row().0.saturating_sub(1)
23638                    } else {
23639                        end.row().0
23640                    };
23641                    for row in start_row..=end_row {
23642                        let used_index =
23643                            used_highlight_orders.entry(row).or_insert(highlight.index);
23644                        if highlight.index >= *used_index {
23645                            *used_index = highlight.index;
23646                            unique_rows.insert(
23647                                DisplayRow(row),
23648                                LineHighlight {
23649                                    include_gutter: highlight.options.include_gutter,
23650                                    border: None,
23651                                    background: highlight.color.into(),
23652                                    type_id: Some(highlight.type_id),
23653                                },
23654                            );
23655                        }
23656                    }
23657                    unique_rows
23658                },
23659            )
23660    }
23661
23662    pub fn highlighted_display_row_for_autoscroll(
23663        &self,
23664        snapshot: &DisplaySnapshot,
23665    ) -> Option<DisplayRow> {
23666        self.highlighted_rows
23667            .values()
23668            .flat_map(|highlighted_rows| highlighted_rows.iter())
23669            .filter_map(|highlight| {
23670                if highlight.options.autoscroll {
23671                    Some(highlight.range.start.to_display_point(snapshot).row())
23672                } else {
23673                    None
23674                }
23675            })
23676            .min()
23677    }
23678
23679    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23680        self.highlight_background(
23681            HighlightKey::SearchWithinRange,
23682            ranges,
23683            |_, colors| colors.colors().editor_document_highlight_read_background,
23684            cx,
23685        )
23686    }
23687
23688    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23689        self.breadcrumb_header = Some(new_header);
23690    }
23691
23692    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23693        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23694    }
23695
23696    pub fn highlight_background(
23697        &mut self,
23698        key: HighlightKey,
23699        ranges: &[Range<Anchor>],
23700        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23701        cx: &mut Context<Self>,
23702    ) {
23703        self.background_highlights
23704            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23705        self.scrollbar_marker_state.dirty = true;
23706        cx.notify();
23707    }
23708
23709    pub fn clear_background_highlights(
23710        &mut self,
23711        key: HighlightKey,
23712        cx: &mut Context<Self>,
23713    ) -> Option<BackgroundHighlight> {
23714        let text_highlights = self.background_highlights.remove(&key)?;
23715        if !text_highlights.1.is_empty() {
23716            self.scrollbar_marker_state.dirty = true;
23717            cx.notify();
23718        }
23719        Some(text_highlights)
23720    }
23721
23722    pub fn highlight_gutter<T: 'static>(
23723        &mut self,
23724        ranges: impl Into<Vec<Range<Anchor>>>,
23725        color_fetcher: fn(&App) -> Hsla,
23726        cx: &mut Context<Self>,
23727    ) {
23728        self.gutter_highlights
23729            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23730        cx.notify();
23731    }
23732
23733    pub fn clear_gutter_highlights<T: 'static>(
23734        &mut self,
23735        cx: &mut Context<Self>,
23736    ) -> Option<GutterHighlight> {
23737        cx.notify();
23738        self.gutter_highlights.remove(&TypeId::of::<T>())
23739    }
23740
23741    pub fn insert_gutter_highlight<T: 'static>(
23742        &mut self,
23743        range: Range<Anchor>,
23744        color_fetcher: fn(&App) -> Hsla,
23745        cx: &mut Context<Self>,
23746    ) {
23747        let snapshot = self.buffer().read(cx).snapshot(cx);
23748        let mut highlights = self
23749            .gutter_highlights
23750            .remove(&TypeId::of::<T>())
23751            .map(|(_, highlights)| highlights)
23752            .unwrap_or_default();
23753        let ix = highlights.binary_search_by(|highlight| {
23754            Ordering::Equal
23755                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23756                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23757        });
23758        if let Err(ix) = ix {
23759            highlights.insert(ix, range);
23760        }
23761        self.gutter_highlights
23762            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23763    }
23764
23765    pub fn remove_gutter_highlights<T: 'static>(
23766        &mut self,
23767        ranges_to_remove: Vec<Range<Anchor>>,
23768        cx: &mut Context<Self>,
23769    ) {
23770        let snapshot = self.buffer().read(cx).snapshot(cx);
23771        let Some((color_fetcher, mut gutter_highlights)) =
23772            self.gutter_highlights.remove(&TypeId::of::<T>())
23773        else {
23774            return;
23775        };
23776        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23777        gutter_highlights.retain(|highlight| {
23778            while let Some(range_to_remove) = ranges_to_remove.peek() {
23779                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23780                    Ordering::Less | Ordering::Equal => {
23781                        ranges_to_remove.next();
23782                    }
23783                    Ordering::Greater => {
23784                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23785                            Ordering::Less | Ordering::Equal => {
23786                                return false;
23787                            }
23788                            Ordering::Greater => break,
23789                        }
23790                    }
23791                }
23792            }
23793
23794            true
23795        });
23796        self.gutter_highlights
23797            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23798    }
23799
23800    #[cfg(any(test, feature = "test-support"))]
23801    pub fn all_text_highlights(
23802        &self,
23803        window: &mut Window,
23804        cx: &mut Context<Self>,
23805    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23806        let snapshot = self.snapshot(window, cx);
23807        self.display_map.update(cx, |display_map, _| {
23808            display_map
23809                .all_text_highlights()
23810                .map(|(_, highlight)| {
23811                    let (style, ranges) = highlight.as_ref();
23812                    (
23813                        *style,
23814                        ranges
23815                            .iter()
23816                            .map(|range| range.clone().to_display_points(&snapshot))
23817                            .collect(),
23818                    )
23819                })
23820                .collect()
23821        })
23822    }
23823
23824    #[cfg(any(test, feature = "test-support"))]
23825    pub fn all_text_background_highlights(
23826        &self,
23827        window: &mut Window,
23828        cx: &mut Context<Self>,
23829    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23830        let snapshot = self.snapshot(window, cx);
23831        let buffer = &snapshot.buffer_snapshot();
23832        let start = buffer.anchor_before(MultiBufferOffset(0));
23833        let end = buffer.anchor_after(buffer.len());
23834        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23835    }
23836
23837    #[cfg(any(test, feature = "test-support"))]
23838    pub fn sorted_background_highlights_in_range(
23839        &self,
23840        search_range: Range<Anchor>,
23841        display_snapshot: &DisplaySnapshot,
23842        theme: &Theme,
23843    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23844        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23845        res.sort_by(|a, b| {
23846            a.0.start
23847                .cmp(&b.0.start)
23848                .then_with(|| a.0.end.cmp(&b.0.end))
23849                .then_with(|| a.1.cmp(&b.1))
23850        });
23851        res
23852    }
23853
23854    #[cfg(any(test, feature = "test-support"))]
23855    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23856        let snapshot = self.buffer().read(cx).snapshot(cx);
23857
23858        let highlights = self
23859            .background_highlights
23860            .get(&HighlightKey::BufferSearchHighlights);
23861
23862        if let Some((_color, ranges)) = highlights {
23863            ranges
23864                .iter()
23865                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23866                .collect_vec()
23867        } else {
23868            vec![]
23869        }
23870    }
23871
23872    fn document_highlights_for_position<'a>(
23873        &'a self,
23874        position: Anchor,
23875        buffer: &'a MultiBufferSnapshot,
23876    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23877        let read_highlights = self
23878            .background_highlights
23879            .get(&HighlightKey::DocumentHighlightRead)
23880            .map(|h| &h.1);
23881        let write_highlights = self
23882            .background_highlights
23883            .get(&HighlightKey::DocumentHighlightWrite)
23884            .map(|h| &h.1);
23885        let left_position = position.bias_left(buffer);
23886        let right_position = position.bias_right(buffer);
23887        read_highlights
23888            .into_iter()
23889            .chain(write_highlights)
23890            .flat_map(move |ranges| {
23891                let start_ix = match ranges.binary_search_by(|probe| {
23892                    let cmp = probe.end.cmp(&left_position, buffer);
23893                    if cmp.is_ge() {
23894                        Ordering::Greater
23895                    } else {
23896                        Ordering::Less
23897                    }
23898                }) {
23899                    Ok(i) | Err(i) => i,
23900                };
23901
23902                ranges[start_ix..]
23903                    .iter()
23904                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23905            })
23906    }
23907
23908    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23909        self.background_highlights
23910            .get(&key)
23911            .is_some_and(|(_, highlights)| !highlights.is_empty())
23912    }
23913
23914    /// Returns all background highlights for a given range.
23915    ///
23916    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23917    pub fn background_highlights_in_range(
23918        &self,
23919        search_range: Range<Anchor>,
23920        display_snapshot: &DisplaySnapshot,
23921        theme: &Theme,
23922    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23923        let mut results = Vec::new();
23924        for (color_fetcher, ranges) in self.background_highlights.values() {
23925            let start_ix = match ranges.binary_search_by(|probe| {
23926                let cmp = probe
23927                    .end
23928                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23929                if cmp.is_gt() {
23930                    Ordering::Greater
23931                } else {
23932                    Ordering::Less
23933                }
23934            }) {
23935                Ok(i) | Err(i) => i,
23936            };
23937            for (index, range) in ranges[start_ix..].iter().enumerate() {
23938                if range
23939                    .start
23940                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23941                    .is_ge()
23942                {
23943                    break;
23944                }
23945
23946                let color = color_fetcher(&(start_ix + index), theme);
23947                let start = range.start.to_display_point(display_snapshot);
23948                let end = range.end.to_display_point(display_snapshot);
23949                results.push((start..end, color))
23950            }
23951        }
23952        results
23953    }
23954
23955    pub fn gutter_highlights_in_range(
23956        &self,
23957        search_range: Range<Anchor>,
23958        display_snapshot: &DisplaySnapshot,
23959        cx: &App,
23960    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23961        let mut results = Vec::new();
23962        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23963            let color = color_fetcher(cx);
23964            let start_ix = match ranges.binary_search_by(|probe| {
23965                let cmp = probe
23966                    .end
23967                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23968                if cmp.is_gt() {
23969                    Ordering::Greater
23970                } else {
23971                    Ordering::Less
23972                }
23973            }) {
23974                Ok(i) | Err(i) => i,
23975            };
23976            for range in &ranges[start_ix..] {
23977                if range
23978                    .start
23979                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23980                    .is_ge()
23981                {
23982                    break;
23983                }
23984
23985                let start = range.start.to_display_point(display_snapshot);
23986                let end = range.end.to_display_point(display_snapshot);
23987                results.push((start..end, color))
23988            }
23989        }
23990        results
23991    }
23992
23993    /// Get the text ranges corresponding to the redaction query
23994    pub fn redacted_ranges(
23995        &self,
23996        search_range: Range<Anchor>,
23997        display_snapshot: &DisplaySnapshot,
23998        cx: &App,
23999    ) -> Vec<Range<DisplayPoint>> {
24000        display_snapshot
24001            .buffer_snapshot()
24002            .redacted_ranges(search_range, |file| {
24003                if let Some(file) = file {
24004                    file.is_private()
24005                        && EditorSettings::get(
24006                            Some(SettingsLocation {
24007                                worktree_id: file.worktree_id(cx),
24008                                path: file.path().as_ref(),
24009                            }),
24010                            cx,
24011                        )
24012                        .redact_private_values
24013                } else {
24014                    false
24015                }
24016            })
24017            .map(|range| {
24018                range.start.to_display_point(display_snapshot)
24019                    ..range.end.to_display_point(display_snapshot)
24020            })
24021            .collect()
24022    }
24023
24024    pub fn highlight_text_key(
24025        &mut self,
24026        key: HighlightKey,
24027        ranges: Vec<Range<Anchor>>,
24028        style: HighlightStyle,
24029        merge: bool,
24030        cx: &mut Context<Self>,
24031    ) {
24032        self.display_map.update(cx, |map, cx| {
24033            map.highlight_text(key, ranges, style, merge, cx);
24034        });
24035        cx.notify();
24036    }
24037
24038    pub fn highlight_text(
24039        &mut self,
24040        key: HighlightKey,
24041        ranges: Vec<Range<Anchor>>,
24042        style: HighlightStyle,
24043        cx: &mut Context<Self>,
24044    ) {
24045        self.display_map.update(cx, |map, cx| {
24046            map.highlight_text(key, ranges, style, false, cx)
24047        });
24048        cx.notify();
24049    }
24050
24051    pub fn text_highlights<'a>(
24052        &'a self,
24053        key: HighlightKey,
24054        cx: &'a App,
24055    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24056        self.display_map.read(cx).text_highlights(key)
24057    }
24058
24059    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24060        let cleared = self
24061            .display_map
24062            .update(cx, |map, _| map.clear_highlights(key));
24063        if cleared {
24064            cx.notify();
24065        }
24066    }
24067
24068    pub fn clear_highlights_with(
24069        &mut self,
24070        f: &mut dyn FnMut(&HighlightKey) -> bool,
24071        cx: &mut Context<Self>,
24072    ) {
24073        let cleared = self
24074            .display_map
24075            .update(cx, |map, _| map.clear_highlights_with(f));
24076        if cleared {
24077            cx.notify();
24078        }
24079    }
24080
24081    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24082        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24083            && self.focus_handle.is_focused(window)
24084    }
24085
24086    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24087        self.show_cursor_when_unfocused = is_enabled;
24088        cx.notify();
24089    }
24090
24091    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24092        cx.notify();
24093    }
24094
24095    fn on_debug_session_event(
24096        &mut self,
24097        _session: Entity<Session>,
24098        event: &SessionEvent,
24099        cx: &mut Context<Self>,
24100    ) {
24101        if let SessionEvent::InvalidateInlineValue = event {
24102            self.refresh_inline_values(cx);
24103        }
24104    }
24105
24106    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24107        let Some(semantics) = self.semantics_provider.clone() else {
24108            return;
24109        };
24110
24111        if !self.inline_value_cache.enabled {
24112            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24113            self.splice_inlays(&inlays, Vec::new(), cx);
24114            return;
24115        }
24116
24117        let current_execution_position = self
24118            .highlighted_rows
24119            .get(&TypeId::of::<ActiveDebugLine>())
24120            .and_then(|lines| lines.last().map(|line| line.range.end));
24121
24122        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24123            let inline_values = editor
24124                .update(cx, |editor, cx| {
24125                    let Some(current_execution_position) = current_execution_position else {
24126                        return Some(Task::ready(Ok(Vec::new())));
24127                    };
24128
24129                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
24130                        let snapshot = buffer.snapshot(cx);
24131
24132                        let excerpt = snapshot.excerpt_containing(
24133                            current_execution_position..current_execution_position,
24134                        )?;
24135
24136                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
24137                    })?;
24138
24139                    if current_execution_position
24140                        .text_anchor
24141                        .buffer_id
24142                        .is_some_and(|id| id != buffer.read(cx).remote_id())
24143                    {
24144                        return Some(Task::ready(Ok(Vec::new())));
24145                    }
24146
24147                    let range =
24148                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
24149
24150                    semantics.inline_values(buffer, range, cx)
24151                })
24152                .ok()
24153                .flatten()?
24154                .await
24155                .context("refreshing debugger inlays")
24156                .log_err()?;
24157
24158            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24159
24160            for (buffer_id, inline_value) in inline_values
24161                .into_iter()
24162                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
24163            {
24164                buffer_inline_values
24165                    .entry(buffer_id)
24166                    .or_default()
24167                    .push(inline_value);
24168            }
24169
24170            editor
24171                .update(cx, |editor, cx| {
24172                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24173                    let mut new_inlays = Vec::default();
24174
24175                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
24176                        let buffer_id = buffer_snapshot.remote_id();
24177                        buffer_inline_values
24178                            .get(&buffer_id)
24179                            .into_iter()
24180                            .flatten()
24181                            .for_each(|hint| {
24182                                let inlay = Inlay::debugger(
24183                                    post_inc(&mut editor.next_inlay_id),
24184                                    Anchor::in_buffer(excerpt_id, hint.position),
24185                                    hint.text(),
24186                                );
24187                                if !inlay.text().chars().contains(&'\n') {
24188                                    new_inlays.push(inlay);
24189                                }
24190                            });
24191                    }
24192
24193                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24194                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24195
24196                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24197                })
24198                .ok()?;
24199            Some(())
24200        });
24201    }
24202
24203    fn on_buffer_event(
24204        &mut self,
24205        multibuffer: &Entity<MultiBuffer>,
24206        event: &multi_buffer::Event,
24207        window: &mut Window,
24208        cx: &mut Context<Self>,
24209    ) {
24210        match event {
24211            multi_buffer::Event::Edited {
24212                edited_buffer,
24213                is_local,
24214            } => {
24215                self.scrollbar_marker_state.dirty = true;
24216                self.active_indent_guides_state.dirty = true;
24217                self.refresh_active_diagnostics(cx);
24218                self.refresh_code_actions(window, cx);
24219                self.refresh_single_line_folds(window, cx);
24220                let snapshot = self.snapshot(window, cx);
24221                self.refresh_matching_bracket_highlights(&snapshot, cx);
24222                self.refresh_outline_symbols_at_cursor(cx);
24223                self.refresh_sticky_headers(&snapshot, cx);
24224                if *is_local && self.has_active_edit_prediction() {
24225                    self.update_visible_edit_prediction(window, cx);
24226                }
24227
24228                // Clean up orphaned review comments after edits
24229                self.cleanup_orphaned_review_comments(cx);
24230
24231                if let Some(buffer) = edited_buffer {
24232                    if buffer.read(cx).file().is_none() {
24233                        cx.emit(EditorEvent::TitleChanged);
24234                    }
24235
24236                    if self.project.is_some() {
24237                        let buffer_id = buffer.read(cx).remote_id();
24238                        self.register_buffer(buffer_id, cx);
24239                        self.update_lsp_data(Some(buffer_id), window, cx);
24240                        self.refresh_inlay_hints(
24241                            InlayHintRefreshReason::BufferEdited(buffer_id),
24242                            cx,
24243                        );
24244                    }
24245                }
24246
24247                cx.emit(EditorEvent::BufferEdited);
24248                cx.emit(SearchEvent::MatchesInvalidated);
24249
24250                let Some(project) = &self.project else { return };
24251                let (telemetry, is_via_ssh) = {
24252                    let project = project.read(cx);
24253                    let telemetry = project.client().telemetry().clone();
24254                    let is_via_ssh = project.is_via_remote_server();
24255                    (telemetry, is_via_ssh)
24256                };
24257                telemetry.log_edit_event("editor", is_via_ssh);
24258            }
24259            multi_buffer::Event::ExcerptsAdded {
24260                buffer,
24261                predecessor,
24262                excerpts,
24263            } => {
24264                let buffer_id = buffer.read(cx).remote_id();
24265                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24266                    && let Some(project) = &self.project
24267                {
24268                    update_uncommitted_diff_for_buffer(
24269                        cx.entity(),
24270                        project,
24271                        [buffer.clone()],
24272                        self.buffer.clone(),
24273                        cx,
24274                    )
24275                    .detach();
24276                }
24277                self.semantic_token_state
24278                    .invalidate_buffer(&buffer.read(cx).remote_id());
24279                self.update_lsp_data(Some(buffer_id), window, cx);
24280                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24281                self.refresh_runnables(None, window, cx);
24282                self.colorize_brackets(false, cx);
24283                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24284                cx.emit(EditorEvent::ExcerptsAdded {
24285                    buffer: buffer.clone(),
24286                    predecessor: *predecessor,
24287                    excerpts: excerpts.clone(),
24288                });
24289            }
24290            multi_buffer::Event::ExcerptsRemoved {
24291                ids,
24292                removed_buffer_ids,
24293            } => {
24294                if let Some(inlay_hints) = &mut self.inlay_hints {
24295                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24296                }
24297                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
24298                for buffer_id in removed_buffer_ids {
24299                    self.registered_buffers.remove(buffer_id);
24300                    self.clear_runnables(Some(*buffer_id));
24301                    self.semantic_token_state.invalidate_buffer(buffer_id);
24302                    self.display_map.update(cx, |display_map, cx| {
24303                        display_map.invalidate_semantic_highlights(*buffer_id);
24304                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24305                    });
24306                }
24307
24308                self.display_map.update(cx, |display_map, cx| {
24309                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24310                });
24311
24312                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24313                cx.emit(EditorEvent::ExcerptsRemoved {
24314                    ids: ids.clone(),
24315                    removed_buffer_ids: removed_buffer_ids.clone(),
24316                });
24317            }
24318            multi_buffer::Event::ExcerptsEdited {
24319                excerpt_ids,
24320                buffer_ids,
24321            } => {
24322                self.display_map.update(cx, |map, cx| {
24323                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24324                });
24325                cx.emit(EditorEvent::ExcerptsEdited {
24326                    ids: excerpt_ids.clone(),
24327                });
24328            }
24329            multi_buffer::Event::ExcerptsExpanded { ids } => {
24330                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24331                self.refresh_document_highlights(cx);
24332                let snapshot = multibuffer.read(cx).snapshot(cx);
24333                for id in ids {
24334                    self.bracket_fetched_tree_sitter_chunks.remove(id);
24335                    if let Some(buffer) = snapshot.buffer_for_excerpt(*id) {
24336                        self.semantic_token_state
24337                            .invalidate_buffer(&buffer.remote_id());
24338                    }
24339                }
24340                self.colorize_brackets(false, cx);
24341                self.update_lsp_data(None, window, cx);
24342                self.refresh_runnables(None, window, cx);
24343                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
24344            }
24345            multi_buffer::Event::Reparsed(buffer_id) => {
24346                self.refresh_runnables(Some(*buffer_id), window, cx);
24347                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24348                self.colorize_brackets(true, cx);
24349                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24350
24351                cx.emit(EditorEvent::Reparsed(*buffer_id));
24352            }
24353            multi_buffer::Event::DiffHunksToggled => {
24354                self.refresh_runnables(None, window, cx);
24355            }
24356            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24357                if !is_fresh_language {
24358                    self.registered_buffers.remove(&buffer_id);
24359                }
24360                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24361                cx.emit(EditorEvent::Reparsed(*buffer_id));
24362                self.update_edit_prediction_settings(cx);
24363                cx.notify();
24364            }
24365            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24366            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24367            multi_buffer::Event::FileHandleChanged
24368            | multi_buffer::Event::Reloaded
24369            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24370            multi_buffer::Event::DiagnosticsUpdated => {
24371                self.update_diagnostics_state(window, cx);
24372            }
24373            _ => {}
24374        };
24375    }
24376
24377    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24378        if !self.diagnostics_enabled() {
24379            return;
24380        }
24381        self.refresh_active_diagnostics(cx);
24382        self.refresh_inline_diagnostics(true, window, cx);
24383        self.scrollbar_marker_state.dirty = true;
24384        cx.notify();
24385    }
24386
24387    pub fn start_temporary_diff_override(&mut self) {
24388        self.load_diff_task.take();
24389        self.temporary_diff_override = true;
24390    }
24391
24392    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24393        self.temporary_diff_override = false;
24394        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24395        self.buffer.update(cx, |buffer, cx| {
24396            buffer.set_all_diff_hunks_collapsed(cx);
24397        });
24398
24399        if let Some(project) = self.project.clone() {
24400            self.load_diff_task = Some(
24401                update_uncommitted_diff_for_buffer(
24402                    cx.entity(),
24403                    &project,
24404                    self.buffer.read(cx).all_buffers(),
24405                    self.buffer.clone(),
24406                    cx,
24407                )
24408                .shared(),
24409            );
24410        }
24411    }
24412
24413    fn on_display_map_changed(
24414        &mut self,
24415        _: Entity<DisplayMap>,
24416        _: &mut Window,
24417        cx: &mut Context<Self>,
24418    ) {
24419        cx.notify();
24420    }
24421
24422    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24423        if !self.mode.is_full() {
24424            return None;
24425        }
24426
24427        let theme_settings = theme::ThemeSettings::get_global(cx);
24428        let theme = cx.theme();
24429        let accent_colors = theme.accents().clone();
24430
24431        let accent_overrides = theme_settings
24432            .theme_overrides
24433            .get(theme.name.as_ref())
24434            .map(|theme_style| &theme_style.accents)
24435            .into_iter()
24436            .flatten()
24437            .chain(
24438                theme_settings
24439                    .experimental_theme_overrides
24440                    .as_ref()
24441                    .map(|overrides| &overrides.accents)
24442                    .into_iter()
24443                    .flatten(),
24444            )
24445            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24446            .collect();
24447
24448        Some(AccentData {
24449            colors: accent_colors,
24450            overrides: accent_overrides,
24451        })
24452    }
24453
24454    fn fetch_applicable_language_settings(
24455        &self,
24456        cx: &App,
24457    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24458        if !self.mode.is_full() {
24459            return HashMap::default();
24460        }
24461
24462        self.buffer().read(cx).all_buffers().into_iter().fold(
24463            HashMap::default(),
24464            |mut acc, buffer| {
24465                let buffer = buffer.read(cx);
24466                let language = buffer.language().map(|language| language.name());
24467                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
24468                    let file = buffer.file();
24469                    v.insert(language_settings(language, file, cx).into_owned());
24470                }
24471                acc
24472            },
24473        )
24474    }
24475
24476    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24477        let new_language_settings = self.fetch_applicable_language_settings(cx);
24478        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24479        self.applicable_language_settings = new_language_settings;
24480
24481        let new_accents = self.fetch_accent_data(cx);
24482        let accents_changed = new_accents != self.accent_data;
24483        self.accent_data = new_accents;
24484
24485        if self.diagnostics_enabled() {
24486            let new_severity = EditorSettings::get_global(cx)
24487                .diagnostics_max_severity
24488                .unwrap_or(DiagnosticSeverity::Hint);
24489            self.set_max_diagnostics_severity(new_severity, cx);
24490        }
24491        self.refresh_runnables(None, window, cx);
24492        self.update_edit_prediction_settings(cx);
24493        self.refresh_edit_prediction(true, false, window, cx);
24494        self.refresh_inline_values(cx);
24495
24496        let old_cursor_shape = self.cursor_shape;
24497        let old_show_breadcrumbs = self.show_breadcrumbs;
24498
24499        {
24500            let editor_settings = EditorSettings::get_global(cx);
24501            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24502            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24503            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24504            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24505        }
24506
24507        if old_cursor_shape != self.cursor_shape {
24508            cx.emit(EditorEvent::CursorShapeChanged);
24509        }
24510
24511        if old_show_breadcrumbs != self.show_breadcrumbs {
24512            cx.emit(EditorEvent::BreadcrumbsChanged);
24513        }
24514
24515        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24516            let project_settings = ProjectSettings::get_global(cx);
24517            (
24518                project_settings.session.restore_unsaved_buffers,
24519                project_settings.diagnostics.inline.enabled,
24520                project_settings.git.inline_blame.enabled,
24521            )
24522        };
24523        self.buffer_serialization = self
24524            .should_serialize_buffer()
24525            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24526
24527        if self.mode.is_full() {
24528            if self.show_inline_diagnostics != show_inline_diagnostics {
24529                self.show_inline_diagnostics = show_inline_diagnostics;
24530                self.refresh_inline_diagnostics(false, window, cx);
24531            }
24532
24533            if self.git_blame_inline_enabled != inline_blame_enabled {
24534                self.toggle_git_blame_inline_internal(false, window, cx);
24535            }
24536
24537            let minimap_settings = EditorSettings::get_global(cx).minimap;
24538            if self.minimap_visibility != MinimapVisibility::Disabled {
24539                if self.minimap_visibility.settings_visibility()
24540                    != minimap_settings.minimap_enabled()
24541                {
24542                    self.set_minimap_visibility(
24543                        MinimapVisibility::for_mode(self.mode(), cx),
24544                        window,
24545                        cx,
24546                    );
24547                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24548                    minimap_entity.update(cx, |minimap_editor, cx| {
24549                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24550                    })
24551                }
24552            }
24553
24554            if language_settings_changed || accents_changed {
24555                self.colorize_brackets(true, cx);
24556            }
24557
24558            if language_settings_changed {
24559                self.clear_disabled_lsp_folding_ranges(window, cx);
24560                self.refresh_document_symbols(None, cx);
24561            }
24562
24563            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24564                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24565            }) {
24566                if !inlay_splice.is_empty() {
24567                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24568                }
24569                self.refresh_document_colors(None, window, cx);
24570            }
24571
24572            self.refresh_inlay_hints(
24573                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24574                    self.selections.newest_anchor().head(),
24575                    &self.buffer.read(cx).snapshot(cx),
24576                    cx,
24577                )),
24578                cx,
24579            );
24580
24581            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24582                .global_lsp_settings
24583                .semantic_token_rules
24584                .clone();
24585            let semantic_token_rules_changed = self
24586                .semantic_token_state
24587                .update_rules(new_semantic_token_rules);
24588            if language_settings_changed || semantic_token_rules_changed {
24589                self.invalidate_semantic_tokens(None);
24590                self.refresh_semantic_tokens(None, None, cx);
24591            }
24592        }
24593
24594        cx.notify();
24595    }
24596
24597    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24598        if !self.mode.is_full() {
24599            return;
24600        }
24601
24602        let new_accents = self.fetch_accent_data(cx);
24603        if new_accents != self.accent_data {
24604            self.accent_data = new_accents;
24605            self.colorize_brackets(true, cx);
24606        }
24607
24608        self.invalidate_semantic_tokens(None);
24609        self.refresh_semantic_tokens(None, None, cx);
24610    }
24611
24612    pub fn set_searchable(&mut self, searchable: bool) {
24613        self.searchable = searchable;
24614    }
24615
24616    pub fn searchable(&self) -> bool {
24617        self.searchable
24618    }
24619
24620    pub fn open_excerpts_in_split(
24621        &mut self,
24622        _: &OpenExcerptsSplit,
24623        window: &mut Window,
24624        cx: &mut Context<Self>,
24625    ) {
24626        self.open_excerpts_common(None, true, window, cx)
24627    }
24628
24629    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24630        self.open_excerpts_common(None, false, window, cx)
24631    }
24632
24633    pub(crate) fn open_excerpts_common(
24634        &mut self,
24635        jump_data: Option<JumpData>,
24636        split: bool,
24637        window: &mut Window,
24638        cx: &mut Context<Self>,
24639    ) {
24640        if self.buffer.read(cx).is_singleton() {
24641            cx.propagate();
24642            return;
24643        }
24644
24645        let mut new_selections_by_buffer = HashMap::default();
24646        match &jump_data {
24647            Some(JumpData::MultiBufferPoint {
24648                excerpt_id,
24649                position,
24650                anchor,
24651                line_offset_from_top,
24652            }) => {
24653                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
24654                if let Some(buffer) = multi_buffer_snapshot
24655                    .buffer_id_for_excerpt(*excerpt_id)
24656                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
24657                {
24658                    let buffer_snapshot = buffer.read(cx).snapshot();
24659                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
24660                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24661                    } else {
24662                        buffer_snapshot.clip_point(*position, Bias::Left)
24663                    };
24664                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24665                    new_selections_by_buffer.insert(
24666                        buffer,
24667                        (
24668                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24669                            Some(*line_offset_from_top),
24670                        ),
24671                    );
24672                }
24673            }
24674            Some(JumpData::MultiBufferRow {
24675                row,
24676                line_offset_from_top,
24677            }) => {
24678                let point = MultiBufferPoint::new(row.0, 0);
24679                if let Some((buffer, buffer_point, _)) =
24680                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24681                {
24682                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24683                    new_selections_by_buffer
24684                        .entry(buffer)
24685                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24686                        .0
24687                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24688                }
24689            }
24690            None => {
24691                let selections = self
24692                    .selections
24693                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24694                let multi_buffer = self.buffer.read(cx);
24695                for selection in selections {
24696                    for (snapshot, range, _, anchor) in multi_buffer
24697                        .snapshot(cx)
24698                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24699                    {
24700                        if let Some(anchor) = anchor {
24701                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24702                            else {
24703                                continue;
24704                            };
24705                            let offset = text::ToOffset::to_offset(
24706                                &anchor.text_anchor,
24707                                &buffer_handle.read(cx).snapshot(),
24708                            );
24709                            let range = BufferOffset(offset)..BufferOffset(offset);
24710                            new_selections_by_buffer
24711                                .entry(buffer_handle)
24712                                .or_insert((Vec::new(), None))
24713                                .0
24714                                .push(range)
24715                        } else {
24716                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24717                            else {
24718                                continue;
24719                            };
24720                            new_selections_by_buffer
24721                                .entry(buffer_handle)
24722                                .or_insert((Vec::new(), None))
24723                                .0
24724                                .push(range)
24725                        }
24726                    }
24727                }
24728            }
24729        }
24730
24731        if self.delegate_open_excerpts {
24732            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24733                .into_iter()
24734                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24735                .collect();
24736            if !selections_by_buffer.is_empty() {
24737                cx.emit(EditorEvent::OpenExcerptsRequested {
24738                    selections_by_buffer,
24739                    split,
24740                });
24741            }
24742            return;
24743        }
24744
24745        let Some(workspace) = self.workspace() else {
24746            cx.propagate();
24747            return;
24748        };
24749
24750        new_selections_by_buffer
24751            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24752
24753        if new_selections_by_buffer.is_empty() {
24754            return;
24755        }
24756
24757        Self::open_buffers_in_workspace(
24758            workspace.downgrade(),
24759            new_selections_by_buffer,
24760            split,
24761            window,
24762            cx,
24763        );
24764    }
24765
24766    pub(crate) fn open_buffers_in_workspace(
24767        workspace: WeakEntity<Workspace>,
24768        new_selections_by_buffer: HashMap<
24769            Entity<language::Buffer>,
24770            (Vec<Range<BufferOffset>>, Option<u32>),
24771        >,
24772        split: bool,
24773        window: &mut Window,
24774        cx: &mut App,
24775    ) {
24776        // We defer the pane interaction because we ourselves are a workspace item
24777        // and activating a new item causes the pane to call a method on us reentrantly,
24778        // which panics if we're on the stack.
24779        window.defer(cx, move |window, cx| {
24780            workspace
24781                .update(cx, |workspace, cx| {
24782                    let pane = if split {
24783                        workspace.adjacent_pane(window, cx)
24784                    } else {
24785                        workspace.active_pane().clone()
24786                    };
24787
24788                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24789                        let buffer_read = buffer.read(cx);
24790                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24791                            (true, project::File::from_dyn(Some(file)).is_some())
24792                        } else {
24793                            (false, false)
24794                        };
24795
24796                        // If project file is none workspace.open_project_item will fail to open the excerpt
24797                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24798                        // so we check if there's a tab match in that case first
24799                        let editor = (!has_file || !is_project_file)
24800                            .then(|| {
24801                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24802                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24803                                // Instead, we try to activate the existing editor in the pane first.
24804                                let (editor, pane_item_index, pane_item_id) =
24805                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24806                                        let editor = item.downcast::<Editor>()?;
24807                                        let singleton_buffer =
24808                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24809                                        if singleton_buffer == buffer {
24810                                            Some((editor, i, item.item_id()))
24811                                        } else {
24812                                            None
24813                                        }
24814                                    })?;
24815                                pane.update(cx, |pane, cx| {
24816                                    pane.activate_item(pane_item_index, true, true, window, cx);
24817                                    if !PreviewTabsSettings::get_global(cx)
24818                                        .enable_preview_from_multibuffer
24819                                    {
24820                                        pane.unpreview_item_if_preview(pane_item_id);
24821                                    }
24822                                });
24823                                Some(editor)
24824                            })
24825                            .flatten()
24826                            .unwrap_or_else(|| {
24827                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24828                                    .enable_keep_preview_on_code_navigation;
24829                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24830                                    .enable_preview_from_multibuffer;
24831                                workspace.open_project_item::<Self>(
24832                                    pane.clone(),
24833                                    buffer,
24834                                    true,
24835                                    true,
24836                                    keep_old_preview,
24837                                    allow_new_preview,
24838                                    window,
24839                                    cx,
24840                                )
24841                            });
24842
24843                        editor.update(cx, |editor, cx| {
24844                            if has_file && !is_project_file {
24845                                editor.set_read_only(true);
24846                            }
24847                            let autoscroll = match scroll_offset {
24848                                Some(scroll_offset) => {
24849                                    Autoscroll::top_relative(scroll_offset as usize)
24850                                }
24851                                None => Autoscroll::newest(),
24852                            };
24853                            let nav_history = editor.nav_history.take();
24854                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24855                            let Some((excerpt_id, _, buffer_snapshot)) =
24856                                multibuffer_snapshot.as_singleton()
24857                            else {
24858                                return;
24859                            };
24860                            editor.change_selections(
24861                                SelectionEffects::scroll(autoscroll),
24862                                window,
24863                                cx,
24864                                |s| {
24865                                    s.select_ranges(ranges.into_iter().map(|range| {
24866                                        let range = buffer_snapshot.anchor_before(range.start)
24867                                            ..buffer_snapshot.anchor_after(range.end);
24868                                        multibuffer_snapshot
24869                                            .anchor_range_in_excerpt(excerpt_id, range)
24870                                            .unwrap()
24871                                    }));
24872                                },
24873                            );
24874                            editor.nav_history = nav_history;
24875                        });
24876                    }
24877                })
24878                .ok();
24879        });
24880    }
24881
24882    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24883        let snapshot = self.buffer.read(cx).read(cx);
24884        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24885        Some(
24886            ranges
24887                .iter()
24888                .map(move |range| {
24889                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24890                })
24891                .collect(),
24892        )
24893    }
24894
24895    fn selection_replacement_ranges(
24896        &self,
24897        range: Range<MultiBufferOffsetUtf16>,
24898        cx: &mut App,
24899    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24900        let selections = self
24901            .selections
24902            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24903        let newest_selection = selections
24904            .iter()
24905            .max_by_key(|selection| selection.id)
24906            .unwrap();
24907        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24908        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24909        let snapshot = self.buffer.read(cx).read(cx);
24910        selections
24911            .into_iter()
24912            .map(|mut selection| {
24913                selection.start.0.0 =
24914                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24915                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24916                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24917                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24918            })
24919            .collect()
24920    }
24921
24922    fn report_editor_event(
24923        &self,
24924        reported_event: ReportEditorEvent,
24925        file_extension: Option<String>,
24926        cx: &App,
24927    ) {
24928        if cfg!(any(test, feature = "test-support")) {
24929            return;
24930        }
24931
24932        let Some(project) = &self.project else { return };
24933
24934        // If None, we are in a file without an extension
24935        let file = self
24936            .buffer
24937            .read(cx)
24938            .as_singleton()
24939            .and_then(|b| b.read(cx).file());
24940        let file_extension = file_extension.or(file
24941            .as_ref()
24942            .and_then(|file| Path::new(file.file_name(cx)).extension())
24943            .and_then(|e| e.to_str())
24944            .map(|a| a.to_string()));
24945
24946        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24947            .map(|vim_mode| vim_mode.0)
24948            .unwrap_or(false);
24949
24950        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24951        let copilot_enabled = edit_predictions_provider
24952            == language::language_settings::EditPredictionProvider::Copilot;
24953        let copilot_enabled_for_language = self
24954            .buffer
24955            .read(cx)
24956            .language_settings(cx)
24957            .show_edit_predictions;
24958
24959        let project = project.read(cx);
24960        let event_type = reported_event.event_type();
24961
24962        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24963            telemetry::event!(
24964                event_type,
24965                type = if auto_saved {"autosave"} else {"manual"},
24966                file_extension,
24967                vim_mode,
24968                copilot_enabled,
24969                copilot_enabled_for_language,
24970                edit_predictions_provider,
24971                is_via_ssh = project.is_via_remote_server(),
24972            );
24973        } else {
24974            telemetry::event!(
24975                event_type,
24976                file_extension,
24977                vim_mode,
24978                copilot_enabled,
24979                copilot_enabled_for_language,
24980                edit_predictions_provider,
24981                is_via_ssh = project.is_via_remote_server(),
24982            );
24983        };
24984    }
24985
24986    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24987    /// with each line being an array of {text, highlight} objects.
24988    fn copy_highlight_json(
24989        &mut self,
24990        _: &CopyHighlightJson,
24991        window: &mut Window,
24992        cx: &mut Context<Self>,
24993    ) {
24994        #[derive(Serialize)]
24995        struct Chunk<'a> {
24996            text: String,
24997            highlight: Option<&'a str>,
24998        }
24999
25000        let snapshot = self.buffer.read(cx).snapshot(cx);
25001        let range = self
25002            .selected_text_range(false, window, cx)
25003            .and_then(|selection| {
25004                if selection.range.is_empty() {
25005                    None
25006                } else {
25007                    Some(
25008                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
25009                            selection.range.start,
25010                        )))
25011                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
25012                                selection.range.end,
25013                            ))),
25014                    )
25015                }
25016            })
25017            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
25018
25019        let chunks = snapshot.chunks(range, true);
25020        let mut lines = Vec::new();
25021        let mut line: VecDeque<Chunk> = VecDeque::new();
25022
25023        let Some(style) = self.style.as_ref() else {
25024            return;
25025        };
25026
25027        for chunk in chunks {
25028            let highlight = chunk
25029                .syntax_highlight_id
25030                .and_then(|id| id.name(&style.syntax));
25031            let mut chunk_lines = chunk.text.split('\n').peekable();
25032            while let Some(text) = chunk_lines.next() {
25033                let mut merged_with_last_token = false;
25034                if let Some(last_token) = line.back_mut()
25035                    && last_token.highlight == highlight
25036                {
25037                    last_token.text.push_str(text);
25038                    merged_with_last_token = true;
25039                }
25040
25041                if !merged_with_last_token {
25042                    line.push_back(Chunk {
25043                        text: text.into(),
25044                        highlight,
25045                    });
25046                }
25047
25048                if chunk_lines.peek().is_some() {
25049                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25050                        line.pop_front();
25051                    }
25052                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25053                        line.pop_back();
25054                    }
25055
25056                    lines.push(mem::take(&mut line));
25057                }
25058            }
25059        }
25060
25061        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25062            return;
25063        };
25064        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25065    }
25066
25067    pub fn open_context_menu(
25068        &mut self,
25069        _: &OpenContextMenu,
25070        window: &mut Window,
25071        cx: &mut Context<Self>,
25072    ) {
25073        self.request_autoscroll(Autoscroll::newest(), cx);
25074        let position = self
25075            .selections
25076            .newest_display(&self.display_snapshot(cx))
25077            .start;
25078        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25079    }
25080
25081    pub fn replay_insert_event(
25082        &mut self,
25083        text: &str,
25084        relative_utf16_range: Option<Range<isize>>,
25085        window: &mut Window,
25086        cx: &mut Context<Self>,
25087    ) {
25088        if !self.input_enabled {
25089            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25090            return;
25091        }
25092        if let Some(relative_utf16_range) = relative_utf16_range {
25093            let selections = self
25094                .selections
25095                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25096            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25097                let new_ranges = selections.into_iter().map(|range| {
25098                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25099                        range
25100                            .head()
25101                            .0
25102                            .0
25103                            .saturating_add_signed(relative_utf16_range.start),
25104                    ));
25105                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25106                        range
25107                            .head()
25108                            .0
25109                            .0
25110                            .saturating_add_signed(relative_utf16_range.end),
25111                    ));
25112                    start..end
25113                });
25114                s.select_ranges(new_ranges);
25115            });
25116        }
25117
25118        self.handle_input(text, window, cx);
25119    }
25120
25121    pub fn is_focused(&self, window: &Window) -> bool {
25122        self.focus_handle.is_focused(window)
25123    }
25124
25125    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25126        cx.emit(EditorEvent::Focused);
25127
25128        if let Some(descendant) = self
25129            .last_focused_descendant
25130            .take()
25131            .and_then(|descendant| descendant.upgrade())
25132        {
25133            window.focus(&descendant, cx);
25134        } else {
25135            if let Some(blame) = self.blame.as_ref() {
25136                blame.update(cx, GitBlame::focus)
25137            }
25138
25139            self.blink_manager.update(cx, BlinkManager::enable);
25140            self.show_cursor_names(window, cx);
25141            self.buffer.update(cx, |buffer, cx| {
25142                buffer.finalize_last_transaction(cx);
25143                if self.leader_id.is_none() {
25144                    buffer.set_active_selections(
25145                        &self.selections.disjoint_anchors_arc(),
25146                        self.selections.line_mode(),
25147                        self.cursor_shape,
25148                        cx,
25149                    );
25150                }
25151            });
25152
25153            if let Some(position_map) = self.last_position_map.clone()
25154                && !self.mouse_cursor_hidden
25155            {
25156                EditorElement::mouse_moved(
25157                    self,
25158                    &MouseMoveEvent {
25159                        position: window.mouse_position(),
25160                        pressed_button: None,
25161                        modifiers: window.modifiers(),
25162                    },
25163                    &position_map,
25164                    None,
25165                    window,
25166                    cx,
25167                );
25168            }
25169        }
25170    }
25171
25172    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25173        cx.emit(EditorEvent::FocusedIn)
25174    }
25175
25176    fn handle_focus_out(
25177        &mut self,
25178        event: FocusOutEvent,
25179        _window: &mut Window,
25180        cx: &mut Context<Self>,
25181    ) {
25182        if event.blurred != self.focus_handle {
25183            self.last_focused_descendant = Some(event.blurred);
25184        }
25185        self.selection_drag_state = SelectionDragState::None;
25186        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25187    }
25188
25189    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25190        self.blink_manager.update(cx, BlinkManager::disable);
25191        self.buffer
25192            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25193
25194        if let Some(blame) = self.blame.as_ref() {
25195            blame.update(cx, GitBlame::blur)
25196        }
25197        if !self.hover_state.focused(window, cx) {
25198            hide_hover(self, cx);
25199        }
25200        if !self
25201            .context_menu
25202            .borrow()
25203            .as_ref()
25204            .is_some_and(|context_menu| context_menu.focused(window, cx))
25205        {
25206            self.hide_context_menu(window, cx);
25207        }
25208        self.take_active_edit_prediction(cx);
25209        cx.emit(EditorEvent::Blurred);
25210        cx.notify();
25211    }
25212
25213    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25214        let mut pending: String = window
25215            .pending_input_keystrokes()
25216            .into_iter()
25217            .flatten()
25218            .filter_map(|keystroke| keystroke.key_char.clone())
25219            .collect();
25220
25221        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25222            pending = "".to_string();
25223        }
25224
25225        let existing_pending = self
25226            .text_highlights(HighlightKey::PendingInput, cx)
25227            .map(|(_, ranges)| ranges.to_vec());
25228        if existing_pending.is_none() && pending.is_empty() {
25229            return;
25230        }
25231        let transaction =
25232            self.transact(window, cx, |this, window, cx| {
25233                let selections = this
25234                    .selections
25235                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25236                let edits = selections
25237                    .iter()
25238                    .map(|selection| (selection.end..selection.end, pending.clone()));
25239                this.edit(edits, cx);
25240                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25241                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25242                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25243                    }));
25244                });
25245                if let Some(existing_ranges) = existing_pending {
25246                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25247                    this.edit(edits, cx);
25248                }
25249            });
25250
25251        let snapshot = self.snapshot(window, cx);
25252        let ranges = self
25253            .selections
25254            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25255            .into_iter()
25256            .map(|selection| {
25257                snapshot.buffer_snapshot().anchor_after(selection.end)
25258                    ..snapshot
25259                        .buffer_snapshot()
25260                        .anchor_before(selection.end + pending.len())
25261            })
25262            .collect();
25263
25264        if pending.is_empty() {
25265            self.clear_highlights(HighlightKey::PendingInput, cx);
25266        } else {
25267            self.highlight_text(
25268                HighlightKey::PendingInput,
25269                ranges,
25270                HighlightStyle {
25271                    underline: Some(UnderlineStyle {
25272                        thickness: px(1.),
25273                        color: None,
25274                        wavy: false,
25275                    }),
25276                    ..Default::default()
25277                },
25278                cx,
25279            );
25280        }
25281
25282        self.ime_transaction = self.ime_transaction.or(transaction);
25283        if let Some(transaction) = self.ime_transaction {
25284            self.buffer.update(cx, |buffer, cx| {
25285                buffer.group_until_transaction(transaction, cx);
25286            });
25287        }
25288
25289        if self
25290            .text_highlights(HighlightKey::PendingInput, cx)
25291            .is_none()
25292        {
25293            self.ime_transaction.take();
25294        }
25295    }
25296
25297    pub fn register_action_renderer(
25298        &mut self,
25299        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25300    ) -> Subscription {
25301        let id = self.next_editor_action_id.post_inc();
25302        self.editor_actions
25303            .borrow_mut()
25304            .insert(id, Box::new(listener));
25305
25306        let editor_actions = self.editor_actions.clone();
25307        Subscription::new(move || {
25308            editor_actions.borrow_mut().remove(&id);
25309        })
25310    }
25311
25312    pub fn register_action<A: Action>(
25313        &mut self,
25314        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25315    ) -> Subscription {
25316        let id = self.next_editor_action_id.post_inc();
25317        let listener = Arc::new(listener);
25318        self.editor_actions.borrow_mut().insert(
25319            id,
25320            Box::new(move |_, window, _| {
25321                let listener = listener.clone();
25322                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25323                    let action = action.downcast_ref().unwrap();
25324                    if phase == DispatchPhase::Bubble {
25325                        listener(action, window, cx)
25326                    }
25327                })
25328            }),
25329        );
25330
25331        let editor_actions = self.editor_actions.clone();
25332        Subscription::new(move || {
25333            editor_actions.borrow_mut().remove(&id);
25334        })
25335    }
25336
25337    pub fn file_header_size(&self) -> u32 {
25338        FILE_HEADER_HEIGHT
25339    }
25340
25341    pub fn restore(
25342        &mut self,
25343        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25344        window: &mut Window,
25345        cx: &mut Context<Self>,
25346    ) {
25347        self.buffer().update(cx, |multi_buffer, cx| {
25348            for (buffer_id, changes) in revert_changes {
25349                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25350                    buffer.update(cx, |buffer, cx| {
25351                        buffer.edit(
25352                            changes
25353                                .into_iter()
25354                                .map(|(range, text)| (range, text.to_string())),
25355                            None,
25356                            cx,
25357                        );
25358                    });
25359                }
25360            }
25361        });
25362        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25363            selections.refresh()
25364        });
25365    }
25366
25367    pub fn to_pixel_point(
25368        &mut self,
25369        source: Anchor,
25370        editor_snapshot: &EditorSnapshot,
25371        window: &mut Window,
25372        cx: &mut App,
25373    ) -> Option<gpui::Point<Pixels>> {
25374        let source_point = source.to_display_point(editor_snapshot);
25375        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25376    }
25377
25378    pub fn display_to_pixel_point(
25379        &mut self,
25380        source: DisplayPoint,
25381        editor_snapshot: &EditorSnapshot,
25382        window: &mut Window,
25383        cx: &mut App,
25384    ) -> Option<gpui::Point<Pixels>> {
25385        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25386        let text_layout_details = self.text_layout_details(window, cx);
25387        let scroll_top = text_layout_details
25388            .scroll_anchor
25389            .scroll_position(editor_snapshot)
25390            .y;
25391
25392        if source.row().as_f64() < scroll_top.floor() {
25393            return None;
25394        }
25395        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25396        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25397        Some(gpui::Point::new(source_x, source_y))
25398    }
25399
25400    pub fn has_visible_completions_menu(&self) -> bool {
25401        !self.edit_prediction_preview_is_active()
25402            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25403                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25404            })
25405    }
25406
25407    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25408        if self.mode.is_minimap() {
25409            return;
25410        }
25411        self.addons
25412            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25413    }
25414
25415    pub fn unregister_addon<T: Addon>(&mut self) {
25416        self.addons.remove(&std::any::TypeId::of::<T>());
25417    }
25418
25419    pub fn addon<T: Addon>(&self) -> Option<&T> {
25420        let type_id = std::any::TypeId::of::<T>();
25421        self.addons
25422            .get(&type_id)
25423            .and_then(|item| item.to_any().downcast_ref::<T>())
25424    }
25425
25426    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25427        let type_id = std::any::TypeId::of::<T>();
25428        self.addons
25429            .get_mut(&type_id)
25430            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25431    }
25432
25433    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25434        let text_layout_details = self.text_layout_details(window, cx);
25435        let style = &text_layout_details.editor_style;
25436        let font_id = window.text_system().resolve_font(&style.text.font());
25437        let font_size = style.text.font_size.to_pixels(window.rem_size());
25438        let line_height = style.text.line_height_in_pixels(window.rem_size());
25439        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25440        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25441
25442        CharacterDimensions {
25443            em_width,
25444            em_advance,
25445            line_height,
25446        }
25447    }
25448
25449    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25450        self.load_diff_task.clone()
25451    }
25452
25453    fn read_metadata_from_db(
25454        &mut self,
25455        item_id: u64,
25456        workspace_id: WorkspaceId,
25457        window: &mut Window,
25458        cx: &mut Context<Editor>,
25459    ) {
25460        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25461            && !self.mode.is_minimap()
25462            && WorkspaceSettings::get(None, cx).restore_on_startup
25463                != RestoreOnStartupBehavior::EmptyTab
25464        {
25465            let buffer_snapshot = OnceCell::new();
25466
25467            // Get file path for path-based fold lookup
25468            let file_path: Option<Arc<Path>> =
25469                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25470                    project::File::from_dyn(buffer.read(cx).file())
25471                        .map(|file| Arc::from(file.abs_path(cx)))
25472                });
25473
25474            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25475            let db = EditorDb::global(cx);
25476            let (folds, needs_migration) = if let Some(ref path) = file_path {
25477                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25478                    && !folds.is_empty()
25479                {
25480                    (Some(folds), false)
25481                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25482                    && !folds.is_empty()
25483                {
25484                    // Found old editor_folds data, will migrate to file_folds
25485                    (Some(folds), true)
25486                } else {
25487                    (None, false)
25488                }
25489            } else {
25490                // No file path, try editor_folds as fallback
25491                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25492                (folds.filter(|f| !f.is_empty()), false)
25493            };
25494
25495            if let Some(folds) = folds {
25496                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25497                let snapshot_len = snapshot.len().0;
25498
25499                // Helper: search for fingerprint in buffer, return offset if found
25500                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25501                    // Ensure we start at a character boundary (defensive)
25502                    let search_start = snapshot
25503                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25504                        .0;
25505                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25506
25507                    let mut byte_offset = search_start;
25508                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25509                        if byte_offset > search_end {
25510                            break;
25511                        }
25512                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25513                            return Some(byte_offset);
25514                        }
25515                        byte_offset += ch.len_utf8();
25516                    }
25517                    None
25518                };
25519
25520                // Track search position to handle duplicate fingerprints correctly.
25521                // Folds are stored in document order, so we advance after each match.
25522                let mut search_start = 0usize;
25523
25524                // Collect db_folds for migration (only folds with valid fingerprints)
25525                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25526
25527                let valid_folds: Vec<_> = folds
25528                    .into_iter()
25529                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25530                        // Skip folds without fingerprints (old data before migration)
25531                        let sfp = start_fp?;
25532                        let efp = end_fp?;
25533                        let efp_len = efp.len();
25534
25535                        // Fast path: check if fingerprints match at stored offsets
25536                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25537                        let start_matches = stored_start < snapshot_len
25538                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25539                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25540                        let end_matches = efp_check_pos >= stored_start
25541                            && stored_end <= snapshot_len
25542                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25543
25544                        let (new_start, new_end) = if start_matches && end_matches {
25545                            // Offsets unchanged, use stored values
25546                            (stored_start, stored_end)
25547                        } else if sfp == efp {
25548                            // Short fold: identical fingerprints can only match once per search
25549                            // Use stored fold length to compute new_end
25550                            let new_start = find_fingerprint(&sfp, search_start)?;
25551                            let fold_len = stored_end - stored_start;
25552                            let new_end = new_start + fold_len;
25553                            (new_start, new_end)
25554                        } else {
25555                            // Slow path: search for fingerprints in buffer
25556                            let new_start = find_fingerprint(&sfp, search_start)?;
25557                            // Search for end_fp after start, then add efp_len to get actual fold end
25558                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25559                            let new_end = efp_pos + efp_len;
25560                            (new_start, new_end)
25561                        };
25562
25563                        // Advance search position for next fold
25564                        search_start = new_end;
25565
25566                        // Validate fold makes sense (end must be after start)
25567                        if new_end <= new_start {
25568                            return None;
25569                        }
25570
25571                        // Collect for migration if needed
25572                        if needs_migration {
25573                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25574                        }
25575
25576                        Some(
25577                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25578                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25579                        )
25580                    })
25581                    .collect();
25582
25583                if !valid_folds.is_empty() {
25584                    self.fold_ranges(valid_folds, false, window, cx);
25585
25586                    // Migrate from editor_folds to file_folds if we loaded from old table
25587                    if needs_migration {
25588                        if let Some(ref path) = file_path {
25589                            let path = path.clone();
25590                            let db = EditorDb::global(cx);
25591                            cx.spawn(async move |_, _| {
25592                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25593                                    .await
25594                                    .log_err();
25595                            })
25596                            .detach();
25597                        }
25598                    }
25599                }
25600            }
25601
25602            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25603                && !selections.is_empty()
25604            {
25605                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25606                // skip adding the initial selection to selection history
25607                self.selection_history.mode = SelectionHistoryMode::Skipping;
25608                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25609                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25610                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25611                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25612                    }));
25613                });
25614                self.selection_history.mode = SelectionHistoryMode::Normal;
25615            };
25616        }
25617
25618        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25619    }
25620
25621    /// Load folds from the file_folds database table by file path.
25622    /// Used when manually opening a file that was previously closed.
25623    fn load_folds_from_db(
25624        &mut self,
25625        workspace_id: WorkspaceId,
25626        file_path: PathBuf,
25627        window: &mut Window,
25628        cx: &mut Context<Editor>,
25629    ) {
25630        if self.mode.is_minimap()
25631            || WorkspaceSettings::get(None, cx).restore_on_startup
25632                == RestoreOnStartupBehavior::EmptyTab
25633        {
25634            return;
25635        }
25636
25637        let Some(folds) = EditorDb::global(cx)
25638            .get_file_folds(workspace_id, &file_path)
25639            .log_err()
25640        else {
25641            return;
25642        };
25643        if folds.is_empty() {
25644            return;
25645        }
25646
25647        let snapshot = self.buffer.read(cx).snapshot(cx);
25648        let snapshot_len = snapshot.len().0;
25649
25650        // Helper: search for fingerprint in buffer, return offset if found
25651        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25652            let search_start = snapshot
25653                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25654                .0;
25655            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25656
25657            let mut byte_offset = search_start;
25658            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25659                if byte_offset > search_end {
25660                    break;
25661                }
25662                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25663                    return Some(byte_offset);
25664                }
25665                byte_offset += ch.len_utf8();
25666            }
25667            None
25668        };
25669
25670        let mut search_start = 0usize;
25671
25672        let valid_folds: Vec<_> = folds
25673            .into_iter()
25674            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25675                let sfp = start_fp?;
25676                let efp = end_fp?;
25677                let efp_len = efp.len();
25678
25679                let start_matches = stored_start < snapshot_len
25680                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25681                let efp_check_pos = stored_end.saturating_sub(efp_len);
25682                let end_matches = efp_check_pos >= stored_start
25683                    && stored_end <= snapshot_len
25684                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25685
25686                let (new_start, new_end) = if start_matches && end_matches {
25687                    (stored_start, stored_end)
25688                } else if sfp == efp {
25689                    let new_start = find_fingerprint(&sfp, search_start)?;
25690                    let fold_len = stored_end - stored_start;
25691                    let new_end = new_start + fold_len;
25692                    (new_start, new_end)
25693                } else {
25694                    let new_start = find_fingerprint(&sfp, search_start)?;
25695                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25696                    let new_end = efp_pos + efp_len;
25697                    (new_start, new_end)
25698                };
25699
25700                search_start = new_end;
25701
25702                if new_end <= new_start {
25703                    return None;
25704                }
25705
25706                Some(
25707                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25708                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25709                )
25710            })
25711            .collect();
25712
25713        if !valid_folds.is_empty() {
25714            self.fold_ranges(valid_folds, false, window, cx);
25715        }
25716    }
25717
25718    fn lsp_data_enabled(&self) -> bool {
25719        self.enable_lsp_data && self.mode().is_full()
25720    }
25721
25722    fn update_lsp_data(
25723        &mut self,
25724        for_buffer: Option<BufferId>,
25725        window: &mut Window,
25726        cx: &mut Context<'_, Self>,
25727    ) {
25728        if !self.lsp_data_enabled() {
25729            return;
25730        }
25731
25732        if let Some(buffer_id) = for_buffer {
25733            self.pull_diagnostics(buffer_id, window, cx);
25734        }
25735        self.refresh_semantic_tokens(for_buffer, None, cx);
25736        self.refresh_document_colors(for_buffer, window, cx);
25737        self.refresh_folding_ranges(for_buffer, window, cx);
25738        self.refresh_document_symbols(for_buffer, cx);
25739    }
25740
25741    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25742        if !self.lsp_data_enabled() {
25743            return;
25744        }
25745        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
25746            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25747        }
25748    }
25749
25750    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25751        if !self.lsp_data_enabled() {
25752            return;
25753        }
25754
25755        if !self.registered_buffers.contains_key(&buffer_id)
25756            && let Some(project) = self.project.as_ref()
25757        {
25758            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25759                project.update(cx, |project, cx| {
25760                    self.registered_buffers.insert(
25761                        buffer_id,
25762                        project.register_buffer_with_language_servers(&buffer, cx),
25763                    );
25764                });
25765            } else {
25766                self.registered_buffers.remove(&buffer_id);
25767            }
25768        }
25769    }
25770
25771    fn create_style(&self, cx: &App) -> EditorStyle {
25772        let settings = ThemeSettings::get_global(cx);
25773
25774        let mut text_style = match self.mode {
25775            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25776                color: cx.theme().colors().editor_foreground,
25777                font_family: settings.ui_font.family.clone(),
25778                font_features: settings.ui_font.features.clone(),
25779                font_fallbacks: settings.ui_font.fallbacks.clone(),
25780                font_size: rems(0.875).into(),
25781                font_weight: settings.ui_font.weight,
25782                line_height: relative(settings.buffer_line_height.value()),
25783                ..Default::default()
25784            },
25785            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25786                color: cx.theme().colors().editor_foreground,
25787                font_family: settings.buffer_font.family.clone(),
25788                font_features: settings.buffer_font.features.clone(),
25789                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25790                font_size: settings.buffer_font_size(cx).into(),
25791                font_weight: settings.buffer_font.weight,
25792                line_height: relative(settings.buffer_line_height.value()),
25793                ..Default::default()
25794            },
25795        };
25796        if let Some(text_style_refinement) = &self.text_style_refinement {
25797            text_style.refine(text_style_refinement)
25798        }
25799
25800        let background = match self.mode {
25801            EditorMode::SingleLine => cx.theme().system().transparent,
25802            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25803            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25804            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25805        };
25806
25807        EditorStyle {
25808            background,
25809            border: cx.theme().colors().border,
25810            local_player: cx.theme().players().local(),
25811            text: text_style,
25812            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25813            syntax: cx.theme().syntax().clone(),
25814            status: cx.theme().status().clone(),
25815            inlay_hints_style: make_inlay_hints_style(cx),
25816            edit_prediction_styles: make_suggestion_styles(cx),
25817            unnecessary_code_fade: settings.unnecessary_code_fade,
25818            show_underlines: self.diagnostics_enabled(),
25819        }
25820    }
25821
25822    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25823        let multibuffer = self.buffer().read(cx);
25824        let is_singleton = multibuffer.is_singleton();
25825        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25826        let buffer = multibuffer.buffer(*buffer_id)?;
25827
25828        let buffer = buffer.read(cx);
25829        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25830        let mut breadcrumbs = if is_singleton {
25831            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25832                buffer
25833                    .snapshot()
25834                    .resolve_file_path(
25835                        self.project
25836                            .as_ref()
25837                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25838                            .unwrap_or_default(),
25839                        cx,
25840                    )
25841                    .unwrap_or_else(|| {
25842                        if multibuffer.is_singleton() {
25843                            multibuffer.title(cx).to_string()
25844                        } else {
25845                            "untitled".to_string()
25846                        }
25847                    })
25848            });
25849            vec![HighlightedText {
25850                text: text.into(),
25851                highlights: vec![],
25852            }]
25853        } else {
25854            vec![]
25855        };
25856
25857        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25858            text: symbol.text.clone().into(),
25859            highlights: symbol.highlight_ranges.clone(),
25860        }));
25861        Some(breadcrumbs)
25862    }
25863
25864    fn disable_lsp_data(&mut self) {
25865        self.enable_lsp_data = false;
25866    }
25867
25868    fn disable_runnables(&mut self) {
25869        self.enable_runnables = false;
25870    }
25871
25872    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25873        self.register_visible_buffers(cx);
25874        self.colorize_brackets(false, cx);
25875        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25876        if !self.buffer().read(cx).is_singleton() {
25877            self.update_lsp_data(None, window, cx);
25878            self.refresh_runnables(None, window, cx);
25879        }
25880    }
25881}
25882
25883fn edit_for_markdown_paste<'a>(
25884    buffer: &MultiBufferSnapshot,
25885    range: Range<MultiBufferOffset>,
25886    to_insert: &'a str,
25887    url: Option<url::Url>,
25888) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25889    if url.is_none() {
25890        return (range, Cow::Borrowed(to_insert));
25891    };
25892
25893    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25894
25895    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25896        Cow::Borrowed(to_insert)
25897    } else {
25898        Cow::Owned(format!("[{old_text}]({to_insert})"))
25899    };
25900    (range, new_text)
25901}
25902
25903fn process_completion_for_edit(
25904    completion: &Completion,
25905    intent: CompletionIntent,
25906    buffer: &Entity<Buffer>,
25907    cursor_position: &text::Anchor,
25908    cx: &mut Context<Editor>,
25909) -> CompletionEdit {
25910    let buffer = buffer.read(cx);
25911    let buffer_snapshot = buffer.snapshot();
25912    let (snippet, new_text) = if completion.is_snippet() {
25913        let mut snippet_source = completion.new_text.clone();
25914        // Workaround for typescript language server issues so that methods don't expand within
25915        // strings and functions with type expressions. The previous point is used because the query
25916        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25917        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25918        let previous_point = if previous_point.column > 0 {
25919            cursor_position.to_previous_offset(&buffer_snapshot)
25920        } else {
25921            cursor_position.to_offset(&buffer_snapshot)
25922        };
25923        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25924            && scope.prefers_label_for_snippet_in_completion()
25925            && let Some(label) = completion.label()
25926            && matches!(
25927                completion.kind(),
25928                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25929            )
25930        {
25931            snippet_source = label;
25932        }
25933        match Snippet::parse(&snippet_source).log_err() {
25934            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25935            None => (None, completion.new_text.clone()),
25936        }
25937    } else {
25938        (None, completion.new_text.clone())
25939    };
25940
25941    let mut range_to_replace = {
25942        let replace_range = &completion.replace_range;
25943        if let CompletionSource::Lsp {
25944            insert_range: Some(insert_range),
25945            ..
25946        } = &completion.source
25947        {
25948            debug_assert_eq!(
25949                insert_range.start, replace_range.start,
25950                "insert_range and replace_range should start at the same position"
25951            );
25952            debug_assert!(
25953                insert_range
25954                    .start
25955                    .cmp(cursor_position, &buffer_snapshot)
25956                    .is_le(),
25957                "insert_range should start before or at cursor position"
25958            );
25959            debug_assert!(
25960                replace_range
25961                    .start
25962                    .cmp(cursor_position, &buffer_snapshot)
25963                    .is_le(),
25964                "replace_range should start before or at cursor position"
25965            );
25966
25967            let should_replace = match intent {
25968                CompletionIntent::CompleteWithInsert => false,
25969                CompletionIntent::CompleteWithReplace => true,
25970                CompletionIntent::Complete | CompletionIntent::Compose => {
25971                    let insert_mode =
25972                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
25973                            .completions
25974                            .lsp_insert_mode;
25975                    match insert_mode {
25976                        LspInsertMode::Insert => false,
25977                        LspInsertMode::Replace => true,
25978                        LspInsertMode::ReplaceSubsequence => {
25979                            let mut text_to_replace = buffer.chars_for_range(
25980                                buffer.anchor_before(replace_range.start)
25981                                    ..buffer.anchor_after(replace_range.end),
25982                            );
25983                            let mut current_needle = text_to_replace.next();
25984                            for haystack_ch in completion.label.text.chars() {
25985                                if let Some(needle_ch) = current_needle
25986                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25987                                {
25988                                    current_needle = text_to_replace.next();
25989                                }
25990                            }
25991                            current_needle.is_none()
25992                        }
25993                        LspInsertMode::ReplaceSuffix => {
25994                            if replace_range
25995                                .end
25996                                .cmp(cursor_position, &buffer_snapshot)
25997                                .is_gt()
25998                            {
25999                                let range_after_cursor = *cursor_position..replace_range.end;
26000                                let text_after_cursor = buffer
26001                                    .text_for_range(
26002                                        buffer.anchor_before(range_after_cursor.start)
26003                                            ..buffer.anchor_after(range_after_cursor.end),
26004                                    )
26005                                    .collect::<String>()
26006                                    .to_ascii_lowercase();
26007                                completion
26008                                    .label
26009                                    .text
26010                                    .to_ascii_lowercase()
26011                                    .ends_with(&text_after_cursor)
26012                            } else {
26013                                true
26014                            }
26015                        }
26016                    }
26017                }
26018            };
26019
26020            if should_replace {
26021                replace_range.clone()
26022            } else {
26023                insert_range.clone()
26024            }
26025        } else {
26026            replace_range.clone()
26027        }
26028    };
26029
26030    if range_to_replace
26031        .end
26032        .cmp(cursor_position, &buffer_snapshot)
26033        .is_lt()
26034    {
26035        range_to_replace.end = *cursor_position;
26036    }
26037
26038    let replace_range = range_to_replace.to_offset(buffer);
26039    CompletionEdit {
26040        new_text,
26041        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
26042        snippet,
26043    }
26044}
26045
26046struct CompletionEdit {
26047    new_text: String,
26048    replace_range: Range<BufferOffset>,
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, range, _)] => (*buffer, 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    ) -> Option<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        excerpt_id: ExcerptId,
27047        buffer: &Entity<Buffer>,
27048        buffer_position: text::Anchor,
27049        trigger: CompletionContext,
27050        window: &mut Window,
27051        cx: &mut Context<Editor>,
27052    ) -> Task<Result<Vec<CompletionResponse>>>;
27053
27054    fn resolve_completions(
27055        &self,
27056        _buffer: Entity<Buffer>,
27057        _completion_indices: Vec<usize>,
27058        _completions: Rc<RefCell<Box<[Completion]>>>,
27059        _cx: &mut Context<Editor>,
27060    ) -> Task<Result<bool>> {
27061        Task::ready(Ok(false))
27062    }
27063
27064    fn apply_additional_edits_for_completion(
27065        &self,
27066        _buffer: Entity<Buffer>,
27067        _completions: Rc<RefCell<Box<[Completion]>>>,
27068        _completion_index: usize,
27069        _push_to_history: bool,
27070        _all_commit_ranges: Vec<Range<language::Anchor>>,
27071        _cx: &mut Context<Editor>,
27072    ) -> Task<Result<Option<language::Transaction>>> {
27073        Task::ready(Ok(None))
27074    }
27075
27076    fn is_completion_trigger(
27077        &self,
27078        buffer: &Entity<Buffer>,
27079        position: language::Anchor,
27080        text: &str,
27081        trigger_in_words: bool,
27082        cx: &mut Context<Editor>,
27083    ) -> bool;
27084
27085    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27086
27087    fn sort_completions(&self) -> bool {
27088        true
27089    }
27090
27091    fn filter_completions(&self) -> bool {
27092        true
27093    }
27094
27095    fn show_snippets(&self) -> bool {
27096        false
27097    }
27098}
27099
27100pub trait CodeActionProvider {
27101    fn id(&self) -> Arc<str>;
27102
27103    fn code_actions(
27104        &self,
27105        buffer: &Entity<Buffer>,
27106        range: Range<text::Anchor>,
27107        window: &mut Window,
27108        cx: &mut App,
27109    ) -> Task<Result<Vec<CodeAction>>>;
27110
27111    fn apply_code_action(
27112        &self,
27113        buffer_handle: Entity<Buffer>,
27114        action: CodeAction,
27115        excerpt_id: ExcerptId,
27116        push_to_history: bool,
27117        window: &mut Window,
27118        cx: &mut App,
27119    ) -> Task<Result<ProjectTransaction>>;
27120}
27121
27122impl CodeActionProvider for Entity<Project> {
27123    fn id(&self) -> Arc<str> {
27124        "project".into()
27125    }
27126
27127    fn code_actions(
27128        &self,
27129        buffer: &Entity<Buffer>,
27130        range: Range<text::Anchor>,
27131        _window: &mut Window,
27132        cx: &mut App,
27133    ) -> Task<Result<Vec<CodeAction>>> {
27134        self.update(cx, |project, cx| {
27135            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27136            let code_actions = project.code_actions(buffer, range, None, cx);
27137            cx.background_spawn(async move {
27138                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27139                Ok(code_lens_actions
27140                    .context("code lens fetch")?
27141                    .into_iter()
27142                    .flatten()
27143                    .chain(
27144                        code_actions
27145                            .context("code action fetch")?
27146                            .into_iter()
27147                            .flatten(),
27148                    )
27149                    .collect())
27150            })
27151        })
27152    }
27153
27154    fn apply_code_action(
27155        &self,
27156        buffer_handle: Entity<Buffer>,
27157        action: CodeAction,
27158        _excerpt_id: ExcerptId,
27159        push_to_history: bool,
27160        _window: &mut Window,
27161        cx: &mut App,
27162    ) -> Task<Result<ProjectTransaction>> {
27163        self.update(cx, |project, cx| {
27164            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27165        })
27166    }
27167}
27168
27169fn snippet_completions(
27170    project: &Project,
27171    buffer: &Entity<Buffer>,
27172    buffer_anchor: text::Anchor,
27173    classifier: CharClassifier,
27174    cx: &mut App,
27175) -> Task<Result<CompletionResponse>> {
27176    let languages = buffer.read(cx).languages_at(buffer_anchor);
27177    let snippet_store = project.snippets().read(cx);
27178
27179    let scopes: Vec<_> = languages
27180        .iter()
27181        .filter_map(|language| {
27182            let language_name = language.lsp_id();
27183            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27184
27185            if snippets.is_empty() {
27186                None
27187            } else {
27188                Some((language.default_scope(), snippets))
27189            }
27190        })
27191        .collect();
27192
27193    if scopes.is_empty() {
27194        return Task::ready(Ok(CompletionResponse {
27195            completions: vec![],
27196            display_options: CompletionDisplayOptions::default(),
27197            is_incomplete: false,
27198        }));
27199    }
27200
27201    let snapshot = buffer.read(cx).text_snapshot();
27202    let executor = cx.background_executor().clone();
27203
27204    cx.background_spawn(async move {
27205        let is_word_char = |c| classifier.is_word(c);
27206
27207        let mut is_incomplete = false;
27208        let mut completions: Vec<Completion> = Vec::new();
27209
27210        const MAX_PREFIX_LEN: usize = 128;
27211        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27212        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27213        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27214
27215        let max_buffer_window: String = snapshot
27216            .text_for_range(window_start..buffer_offset)
27217            .collect();
27218
27219        if max_buffer_window.is_empty() {
27220            return Ok(CompletionResponse {
27221                completions: vec![],
27222                display_options: CompletionDisplayOptions::default(),
27223                is_incomplete: true,
27224            });
27225        }
27226
27227        for (_scope, snippets) in scopes.into_iter() {
27228            // Sort snippets by word count to match longer snippet prefixes first.
27229            let mut sorted_snippet_candidates = snippets
27230                .iter()
27231                .enumerate()
27232                .flat_map(|(snippet_ix, snippet)| {
27233                    snippet
27234                        .prefix
27235                        .iter()
27236                        .enumerate()
27237                        .map(move |(prefix_ix, prefix)| {
27238                            let word_count =
27239                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27240                            ((snippet_ix, prefix_ix), prefix, word_count)
27241                        })
27242                })
27243                .collect_vec();
27244            sorted_snippet_candidates
27245                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27246
27247            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27248
27249            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27250                .take(
27251                    sorted_snippet_candidates
27252                        .first()
27253                        .map(|(_, _, word_count)| *word_count)
27254                        .unwrap_or_default(),
27255                )
27256                .collect_vec();
27257
27258            const MAX_RESULTS: usize = 100;
27259            // Each match also remembers how many characters from the buffer it consumed
27260            let mut matches: Vec<(StringMatch, usize)> = vec![];
27261
27262            let mut snippet_list_cutoff_index = 0;
27263            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27264                let word_count = buffer_index + 1;
27265                // Increase `snippet_list_cutoff_index` until we have all of the
27266                // snippets with sufficiently many words.
27267                while sorted_snippet_candidates
27268                    .get(snippet_list_cutoff_index)
27269                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27270                        *snippet_word_count >= word_count
27271                    })
27272                {
27273                    snippet_list_cutoff_index += 1;
27274                }
27275
27276                // Take only the candidates with at least `word_count` many words
27277                let snippet_candidates_at_word_len =
27278                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27279
27280                let candidates = snippet_candidates_at_word_len
27281                    .iter()
27282                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27283                    .enumerate() // index in `sorted_snippet_candidates`
27284                    // First char must match
27285                    .filter(|(_ix, prefix)| {
27286                        itertools::equal(
27287                            prefix
27288                                .chars()
27289                                .next()
27290                                .into_iter()
27291                                .flat_map(|c| c.to_lowercase()),
27292                            buffer_window
27293                                .chars()
27294                                .next()
27295                                .into_iter()
27296                                .flat_map(|c| c.to_lowercase()),
27297                        )
27298                    })
27299                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27300                    .collect::<Vec<StringMatchCandidate>>();
27301
27302                matches.extend(
27303                    fuzzy::match_strings(
27304                        &candidates,
27305                        &buffer_window,
27306                        buffer_window.chars().any(|c| c.is_uppercase()),
27307                        true,
27308                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27309                        &Default::default(),
27310                        executor.clone(),
27311                    )
27312                    .await
27313                    .into_iter()
27314                    .map(|string_match| (string_match, buffer_window.len())),
27315                );
27316
27317                if matches.len() >= MAX_RESULTS {
27318                    break;
27319                }
27320            }
27321
27322            let to_lsp = |point: &text::Anchor| {
27323                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27324                point_to_lsp(end)
27325            };
27326            let lsp_end = to_lsp(&buffer_anchor);
27327
27328            if matches.len() >= MAX_RESULTS {
27329                is_incomplete = true;
27330            }
27331
27332            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27333                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27334                    sorted_snippet_candidates[string_match.candidate_id];
27335                let snippet = &snippets[snippet_index];
27336                let start = buffer_offset - buffer_window_len;
27337                let start = snapshot.anchor_before(start);
27338                let range = start..buffer_anchor;
27339                let lsp_start = to_lsp(&start);
27340                let lsp_range = lsp::Range {
27341                    start: lsp_start,
27342                    end: lsp_end,
27343                };
27344                Completion {
27345                    replace_range: range,
27346                    new_text: snippet.body.clone(),
27347                    source: CompletionSource::Lsp {
27348                        insert_range: None,
27349                        server_id: LanguageServerId(usize::MAX),
27350                        resolved: true,
27351                        lsp_completion: Box::new(lsp::CompletionItem {
27352                            label: snippet.prefix.first().unwrap().clone(),
27353                            kind: Some(CompletionItemKind::SNIPPET),
27354                            label_details: snippet.description.as_ref().map(|description| {
27355                                lsp::CompletionItemLabelDetails {
27356                                    detail: Some(description.clone()),
27357                                    description: None,
27358                                }
27359                            }),
27360                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27361                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27362                                lsp::InsertReplaceEdit {
27363                                    new_text: snippet.body.clone(),
27364                                    insert: lsp_range,
27365                                    replace: lsp_range,
27366                                },
27367                            )),
27368                            filter_text: Some(snippet.body.clone()),
27369                            sort_text: Some(char::MAX.to_string()),
27370                            ..lsp::CompletionItem::default()
27371                        }),
27372                        lsp_defaults: None,
27373                    },
27374                    label: CodeLabel {
27375                        text: matching_prefix.clone(),
27376                        runs: Vec::new(),
27377                        filter_range: 0..matching_prefix.len(),
27378                    },
27379                    icon_path: None,
27380                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27381                        single_line: snippet.name.clone().into(),
27382                        plain_text: snippet
27383                            .description
27384                            .clone()
27385                            .map(|description| description.into()),
27386                    }),
27387                    insert_text_mode: None,
27388                    confirm: None,
27389                    match_start: Some(start),
27390                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27391                }
27392            }));
27393        }
27394
27395        Ok(CompletionResponse {
27396            completions,
27397            display_options: CompletionDisplayOptions::default(),
27398            is_incomplete,
27399        })
27400    })
27401}
27402
27403impl CompletionProvider for Entity<Project> {
27404    fn completions(
27405        &self,
27406        _excerpt_id: ExcerptId,
27407        buffer: &Entity<Buffer>,
27408        buffer_position: text::Anchor,
27409        options: CompletionContext,
27410        _window: &mut Window,
27411        cx: &mut Context<Editor>,
27412    ) -> Task<Result<Vec<CompletionResponse>>> {
27413        self.update(cx, |project, cx| {
27414            let task = project.completions(buffer, buffer_position, options, cx);
27415            cx.background_spawn(task)
27416        })
27417    }
27418
27419    fn resolve_completions(
27420        &self,
27421        buffer: Entity<Buffer>,
27422        completion_indices: Vec<usize>,
27423        completions: Rc<RefCell<Box<[Completion]>>>,
27424        cx: &mut Context<Editor>,
27425    ) -> Task<Result<bool>> {
27426        self.update(cx, |project, cx| {
27427            project.lsp_store().update(cx, |lsp_store, cx| {
27428                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27429            })
27430        })
27431    }
27432
27433    fn apply_additional_edits_for_completion(
27434        &self,
27435        buffer: Entity<Buffer>,
27436        completions: Rc<RefCell<Box<[Completion]>>>,
27437        completion_index: usize,
27438        push_to_history: bool,
27439        all_commit_ranges: Vec<Range<language::Anchor>>,
27440        cx: &mut Context<Editor>,
27441    ) -> Task<Result<Option<language::Transaction>>> {
27442        self.update(cx, |project, cx| {
27443            project.lsp_store().update(cx, |lsp_store, cx| {
27444                lsp_store.apply_additional_edits_for_completion(
27445                    buffer,
27446                    completions,
27447                    completion_index,
27448                    push_to_history,
27449                    all_commit_ranges,
27450                    cx,
27451                )
27452            })
27453        })
27454    }
27455
27456    fn is_completion_trigger(
27457        &self,
27458        buffer: &Entity<Buffer>,
27459        position: language::Anchor,
27460        text: &str,
27461        trigger_in_words: bool,
27462        cx: &mut Context<Editor>,
27463    ) -> bool {
27464        let mut chars = text.chars();
27465        let char = if let Some(char) = chars.next() {
27466            char
27467        } else {
27468            return false;
27469        };
27470        if chars.next().is_some() {
27471            return false;
27472        }
27473
27474        let buffer = buffer.read(cx);
27475        let snapshot = buffer.snapshot();
27476        let classifier = snapshot
27477            .char_classifier_at(position)
27478            .scope_context(Some(CharScopeContext::Completion));
27479        if trigger_in_words && classifier.is_word(char) {
27480            return true;
27481        }
27482
27483        buffer.completion_triggers().contains(text)
27484    }
27485
27486    fn show_snippets(&self) -> bool {
27487        true
27488    }
27489}
27490
27491impl SemanticsProvider for WeakEntity<Project> {
27492    fn hover(
27493        &self,
27494        buffer: &Entity<Buffer>,
27495        position: text::Anchor,
27496        cx: &mut App,
27497    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27498        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27499            .ok()
27500    }
27501
27502    fn document_highlights(
27503        &self,
27504        buffer: &Entity<Buffer>,
27505        position: text::Anchor,
27506        cx: &mut App,
27507    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27508        self.update(cx, |project, cx| {
27509            project.document_highlights(buffer, position, cx)
27510        })
27511        .ok()
27512    }
27513
27514    fn definitions(
27515        &self,
27516        buffer: &Entity<Buffer>,
27517        position: text::Anchor,
27518        kind: GotoDefinitionKind,
27519        cx: &mut App,
27520    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27521        self.update(cx, |project, cx| match kind {
27522            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27523            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27524            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27525            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27526        })
27527        .ok()
27528    }
27529
27530    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27531        self.update(cx, |project, cx| {
27532            if project
27533                .active_debug_session(cx)
27534                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27535            {
27536                return true;
27537            }
27538
27539            buffer.update(cx, |buffer, cx| {
27540                project.any_language_server_supports_inlay_hints(buffer, cx)
27541            })
27542        })
27543        .unwrap_or(false)
27544    }
27545
27546    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27547        self.update(cx, |project, cx| {
27548            buffer.update(cx, |buffer, cx| {
27549                project.any_language_server_supports_semantic_tokens(buffer, cx)
27550            })
27551        })
27552        .unwrap_or(false)
27553    }
27554
27555    fn inline_values(
27556        &self,
27557        buffer_handle: Entity<Buffer>,
27558        range: Range<text::Anchor>,
27559        cx: &mut App,
27560    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27561        self.update(cx, |project, cx| {
27562            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27563
27564            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27565        })
27566        .ok()
27567        .flatten()
27568    }
27569
27570    fn applicable_inlay_chunks(
27571        &self,
27572        buffer: &Entity<Buffer>,
27573        ranges: &[Range<text::Anchor>],
27574        cx: &mut App,
27575    ) -> Vec<Range<BufferRow>> {
27576        self.update(cx, |project, cx| {
27577            project.lsp_store().update(cx, |lsp_store, cx| {
27578                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27579            })
27580        })
27581        .unwrap_or_default()
27582    }
27583
27584    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27585        self.update(cx, |project, cx| {
27586            project.lsp_store().update(cx, |lsp_store, _| {
27587                lsp_store.invalidate_inlay_hints(for_buffers)
27588            })
27589        })
27590        .ok();
27591    }
27592
27593    fn inlay_hints(
27594        &self,
27595        invalidate: InvalidationStrategy,
27596        buffer: Entity<Buffer>,
27597        ranges: Vec<Range<text::Anchor>>,
27598        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27599        cx: &mut App,
27600    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27601        self.update(cx, |project, cx| {
27602            project.lsp_store().update(cx, |lsp_store, cx| {
27603                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27604            })
27605        })
27606        .ok()
27607    }
27608
27609    fn semantic_tokens(
27610        &self,
27611        buffer: Entity<Buffer>,
27612        refresh: Option<RefreshForServer>,
27613        cx: &mut App,
27614    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27615        self.update(cx, |this, cx| {
27616            this.lsp_store().update(cx, |lsp_store, cx| {
27617                lsp_store.semantic_tokens(buffer, refresh, cx)
27618            })
27619        })
27620        .ok()
27621    }
27622
27623    fn range_for_rename(
27624        &self,
27625        buffer: &Entity<Buffer>,
27626        position: text::Anchor,
27627        cx: &mut App,
27628    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
27629        self.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        .ok()
27654    }
27655
27656    fn perform_rename(
27657        &self,
27658        buffer: &Entity<Buffer>,
27659        position: text::Anchor,
27660        new_name: String,
27661        cx: &mut App,
27662    ) -> Option<Task<Result<ProjectTransaction>>> {
27663        self.update(cx, |project, cx| {
27664            project.perform_rename(buffer.clone(), position, new_name, cx)
27665        })
27666        .ok()
27667    }
27668}
27669
27670fn consume_contiguous_rows(
27671    contiguous_row_selections: &mut Vec<Selection<Point>>,
27672    selection: &Selection<Point>,
27673    display_map: &DisplaySnapshot,
27674    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27675) -> (MultiBufferRow, MultiBufferRow) {
27676    contiguous_row_selections.push(selection.clone());
27677    let start_row = starting_row(selection, display_map);
27678    let mut end_row = ending_row(selection, display_map);
27679
27680    while let Some(next_selection) = selections.peek() {
27681        if next_selection.start.row <= end_row.0 {
27682            end_row = ending_row(next_selection, display_map);
27683            contiguous_row_selections.push(selections.next().unwrap().clone());
27684        } else {
27685            break;
27686        }
27687    }
27688    (start_row, end_row)
27689}
27690
27691fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27692    if selection.start.column > 0 {
27693        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27694    } else {
27695        MultiBufferRow(selection.start.row)
27696    }
27697}
27698
27699fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27700    if next_selection.end.column > 0 || next_selection.is_empty() {
27701        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27702    } else {
27703        MultiBufferRow(next_selection.end.row)
27704    }
27705}
27706
27707impl EditorSnapshot {
27708    pub fn remote_selections_in_range<'a>(
27709        &'a self,
27710        range: &'a Range<Anchor>,
27711        collaboration_hub: &dyn CollaborationHub,
27712        cx: &'a App,
27713    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27714        let participant_names = collaboration_hub.user_names(cx);
27715        let participant_indices = collaboration_hub.user_participant_indices(cx);
27716        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27717        let collaborators_by_replica_id = collaborators_by_peer_id
27718            .values()
27719            .map(|collaborator| (collaborator.replica_id, collaborator))
27720            .collect::<HashMap<_, _>>();
27721        self.buffer_snapshot()
27722            .selections_in_range(range, false)
27723            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27724                if replica_id == ReplicaId::AGENT {
27725                    Some(RemoteSelection {
27726                        replica_id,
27727                        selection,
27728                        cursor_shape,
27729                        line_mode,
27730                        collaborator_id: CollaboratorId::Agent,
27731                        user_name: Some("Agent".into()),
27732                        color: cx.theme().players().agent(),
27733                    })
27734                } else {
27735                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27736                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27737                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27738                    Some(RemoteSelection {
27739                        replica_id,
27740                        selection,
27741                        cursor_shape,
27742                        line_mode,
27743                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27744                        user_name,
27745                        color: if let Some(index) = participant_index {
27746                            cx.theme().players().color_for_participant(index.0)
27747                        } else {
27748                            cx.theme().players().absent()
27749                        },
27750                    })
27751                }
27752            })
27753    }
27754
27755    pub fn hunks_for_ranges(
27756        &self,
27757        ranges: impl IntoIterator<Item = Range<Point>>,
27758    ) -> Vec<MultiBufferDiffHunk> {
27759        let mut hunks = Vec::new();
27760        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27761            HashMap::default();
27762        for query_range in ranges {
27763            let query_rows =
27764                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27765            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27766                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27767            ) {
27768                // Include deleted hunks that are adjacent to the query range, because
27769                // otherwise they would be missed.
27770                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27771                if hunk.status().is_deleted() {
27772                    intersects_range |= hunk.row_range.start == query_rows.end;
27773                    intersects_range |= hunk.row_range.end == query_rows.start;
27774                }
27775                if intersects_range {
27776                    if !processed_buffer_rows
27777                        .entry(hunk.buffer_id)
27778                        .or_default()
27779                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27780                    {
27781                        continue;
27782                    }
27783                    hunks.push(hunk);
27784                }
27785            }
27786        }
27787
27788        hunks
27789    }
27790
27791    fn display_diff_hunks_for_rows<'a>(
27792        &'a self,
27793        display_rows: Range<DisplayRow>,
27794        folded_buffers: &'a HashSet<BufferId>,
27795    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27796        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27797        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27798
27799        self.buffer_snapshot()
27800            .diff_hunks_in_range(buffer_start..buffer_end)
27801            .filter_map(|hunk| {
27802                if folded_buffers.contains(&hunk.buffer_id)
27803                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27804                {
27805                    return None;
27806                }
27807
27808                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27809                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27810                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27811                    let line_len = self.buffer_snapshot().line_len(last_row);
27812                    Point::new(last_row.0, line_len)
27813                } else {
27814                    Point::new(hunk.row_range.end.0, 0)
27815                };
27816
27817                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27818                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27819
27820                let display_hunk = if hunk_display_start.column() != 0 {
27821                    DisplayDiffHunk::Folded {
27822                        display_row: hunk_display_start.row(),
27823                    }
27824                } else {
27825                    let mut end_row = hunk_display_end.row();
27826                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27827                        end_row.0 += 1;
27828                    }
27829                    let is_created_file = hunk.is_created_file();
27830
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: Anchor::range_in_buffer(
27838                            hunk.excerpt_id,
27839                            hunk.buffer_range,
27840                        ),
27841                        is_created_file,
27842                    }
27843                };
27844
27845                Some(display_hunk)
27846            })
27847    }
27848
27849    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27850        self.display_snapshot
27851            .buffer_snapshot()
27852            .language_at(position)
27853    }
27854
27855    pub fn is_focused(&self) -> bool {
27856        self.is_focused
27857    }
27858
27859    pub fn placeholder_text(&self) -> Option<String> {
27860        self.placeholder_display_snapshot
27861            .as_ref()
27862            .map(|display_map| display_map.text())
27863    }
27864
27865    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27866        self.scroll_anchor.scroll_position(&self.display_snapshot)
27867    }
27868
27869    pub fn gutter_dimensions(
27870        &self,
27871        font_id: FontId,
27872        font_size: Pixels,
27873        style: &EditorStyle,
27874        window: &mut Window,
27875        cx: &App,
27876    ) -> GutterDimensions {
27877        if self.show_gutter
27878            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27879            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27880        {
27881            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27882                matches!(
27883                    ProjectSettings::get_global(cx).git.git_gutter,
27884                    GitGutterSetting::TrackedFiles
27885                )
27886            });
27887            let gutter_settings = EditorSettings::get_global(cx).gutter;
27888            let show_line_numbers = self
27889                .show_line_numbers
27890                .unwrap_or(gutter_settings.line_numbers);
27891            let line_gutter_width = if show_line_numbers {
27892                // Avoid flicker-like gutter resizes when the line number gains another digit by
27893                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27894                let min_width_for_number_on_gutter =
27895                    ch_advance * gutter_settings.min_line_number_digits as f32;
27896                self.max_line_number_width(style, window)
27897                    .max(min_width_for_number_on_gutter)
27898            } else {
27899                0.0.into()
27900            };
27901
27902            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27903            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27904
27905            let git_blame_entries_width =
27906                self.git_blame_gutter_max_author_length
27907                    .map(|max_author_length| {
27908                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27909                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27910
27911                        /// The number of characters to dedicate to gaps and margins.
27912                        const SPACING_WIDTH: usize = 4;
27913
27914                        let max_char_count = max_author_length.min(renderer.max_author_length())
27915                            + ::git::SHORT_SHA_LENGTH
27916                            + MAX_RELATIVE_TIMESTAMP.len()
27917                            + SPACING_WIDTH;
27918
27919                        ch_advance * max_char_count
27920                    });
27921
27922            let is_singleton = self.buffer_snapshot().is_singleton();
27923
27924            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27925            left_padding += if !is_singleton {
27926                ch_width * 4.0
27927            } else if show_runnables || show_breakpoints {
27928                ch_width * 3.0
27929            } else if show_git_gutter && show_line_numbers {
27930                ch_width * 2.0
27931            } else if show_git_gutter || show_line_numbers {
27932                ch_width
27933            } else {
27934                px(0.)
27935            };
27936
27937            let shows_folds = is_singleton && gutter_settings.folds;
27938
27939            let right_padding = if shows_folds && show_line_numbers {
27940                ch_width * 4.0
27941            } else if shows_folds || (!is_singleton && show_line_numbers) {
27942                ch_width * 3.0
27943            } else if show_line_numbers {
27944                ch_width
27945            } else {
27946                px(0.)
27947            };
27948
27949            GutterDimensions {
27950                left_padding,
27951                right_padding,
27952                width: line_gutter_width + left_padding + right_padding,
27953                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27954                git_blame_entries_width,
27955            }
27956        } else if self.offset_content {
27957            GutterDimensions::default_with_margin(font_id, font_size, cx)
27958        } else {
27959            GutterDimensions::default()
27960        }
27961    }
27962
27963    pub fn render_crease_toggle(
27964        &self,
27965        buffer_row: MultiBufferRow,
27966        row_contains_cursor: bool,
27967        editor: Entity<Editor>,
27968        window: &mut Window,
27969        cx: &mut App,
27970    ) -> Option<AnyElement> {
27971        let folded = self.is_line_folded(buffer_row);
27972        let mut is_foldable = false;
27973
27974        if let Some(crease) = self
27975            .crease_snapshot
27976            .query_row(buffer_row, self.buffer_snapshot())
27977        {
27978            is_foldable = true;
27979            match crease {
27980                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27981                    if let Some(render_toggle) = render_toggle {
27982                        let toggle_callback =
27983                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27984                                if folded {
27985                                    editor.update(cx, |editor, cx| {
27986                                        editor.fold_at(buffer_row, window, cx)
27987                                    });
27988                                } else {
27989                                    editor.update(cx, |editor, cx| {
27990                                        editor.unfold_at(buffer_row, window, cx)
27991                                    });
27992                                }
27993                            });
27994                        return Some((render_toggle)(
27995                            buffer_row,
27996                            folded,
27997                            toggle_callback,
27998                            window,
27999                            cx,
28000                        ));
28001                    }
28002                }
28003            }
28004        }
28005
28006        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28007
28008        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28009            Some(
28010                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28011                    .toggle_state(folded)
28012                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28013                        if folded {
28014                            this.unfold_at(buffer_row, window, cx);
28015                        } else {
28016                            this.fold_at(buffer_row, window, cx);
28017                        }
28018                    }))
28019                    .into_any_element(),
28020            )
28021        } else {
28022            None
28023        }
28024    }
28025
28026    pub fn render_crease_trailer(
28027        &self,
28028        buffer_row: MultiBufferRow,
28029        window: &mut Window,
28030        cx: &mut App,
28031    ) -> Option<AnyElement> {
28032        let folded = self.is_line_folded(buffer_row);
28033        if let Crease::Inline { render_trailer, .. } = self
28034            .crease_snapshot
28035            .query_row(buffer_row, self.buffer_snapshot())?
28036        {
28037            let render_trailer = render_trailer.as_ref()?;
28038            Some(render_trailer(buffer_row, folded, window, cx))
28039        } else {
28040            None
28041        }
28042    }
28043
28044    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28045        let digit_count = self.widest_line_number().ilog10() + 1;
28046        column_pixels(style, digit_count as usize, window)
28047    }
28048
28049    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28050    ///
28051    /// This is positive if `base` is before `line`.
28052    fn relative_line_delta(
28053        &self,
28054        current_selection_head: DisplayRow,
28055        first_visible_row: DisplayRow,
28056        consider_wrapped_lines: bool,
28057    ) -> i64 {
28058        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28059        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28060
28061        if consider_wrapped_lines {
28062            let wrap_snapshot = self.wrap_snapshot();
28063            let base_wrap_row = wrap_snapshot
28064                .make_wrap_point(current_selection_head, Bias::Left)
28065                .row();
28066            let wrap_row = wrap_snapshot
28067                .make_wrap_point(first_visible_row, Bias::Left)
28068                .row();
28069
28070            wrap_row.0 as i64 - base_wrap_row.0 as i64
28071        } else {
28072            let fold_snapshot = self.fold_snapshot();
28073            let base_fold_row = fold_snapshot
28074                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28075                .row();
28076            let fold_row = fold_snapshot
28077                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28078                .row();
28079
28080            fold_row as i64 - base_fold_row as i64
28081        }
28082    }
28083
28084    /// Returns the unsigned relative line number to display for each row in `rows`.
28085    ///
28086    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28087    pub fn calculate_relative_line_numbers(
28088        &self,
28089        rows: &Range<DisplayRow>,
28090        current_selection_head: DisplayRow,
28091        count_wrapped_lines: bool,
28092    ) -> HashMap<DisplayRow, u32> {
28093        let initial_offset =
28094            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28095
28096        self.row_infos(rows.start)
28097            .take(rows.len())
28098            .enumerate()
28099            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28100            .filter(|(_row, row_info)| {
28101                row_info.buffer_row.is_some()
28102                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28103            })
28104            .enumerate()
28105            .filter_map(|(i, (row, row_info))| {
28106                // We want to ensure here that the current line has absolute
28107                // numbering, even if we are in a soft-wrapped line. With the
28108                // exception that if we are in a deleted line, we should number this
28109                // relative with 0, as otherwise it would have no line number at all
28110                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28111
28112                (relative_line_number != 0
28113                    || row_info
28114                        .diff_status
28115                        .is_some_and(|status| status.is_deleted()))
28116                .then_some((row, relative_line_number))
28117            })
28118            .collect()
28119    }
28120}
28121
28122pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28123    let font_size = style.text.font_size.to_pixels(window.rem_size());
28124    let layout = window.text_system().shape_line(
28125        SharedString::from(" ".repeat(column)),
28126        font_size,
28127        &[TextRun {
28128            len: column,
28129            font: style.text.font(),
28130            color: Hsla::default(),
28131            ..Default::default()
28132        }],
28133        None,
28134    );
28135
28136    layout.width
28137}
28138
28139impl Deref for EditorSnapshot {
28140    type Target = DisplaySnapshot;
28141
28142    fn deref(&self) -> &Self::Target {
28143        &self.display_snapshot
28144    }
28145}
28146
28147#[derive(Clone, Debug, PartialEq, Eq)]
28148pub enum EditorEvent {
28149    /// Emitted when the stored review comments change (added, removed, or updated).
28150    ReviewCommentsChanged {
28151        /// The new total count of review comments.
28152        total_count: usize,
28153    },
28154    InputIgnored {
28155        text: Arc<str>,
28156    },
28157    InputHandled {
28158        utf16_range_to_replace: Option<Range<isize>>,
28159        text: Arc<str>,
28160    },
28161    ExcerptsAdded {
28162        buffer: Entity<Buffer>,
28163        predecessor: ExcerptId,
28164        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
28165    },
28166    ExcerptsRemoved {
28167        ids: Vec<ExcerptId>,
28168        removed_buffer_ids: Vec<BufferId>,
28169    },
28170    BufferFoldToggled {
28171        ids: Vec<ExcerptId>,
28172        folded: bool,
28173    },
28174    ExcerptsEdited {
28175        ids: Vec<ExcerptId>,
28176    },
28177    ExcerptsExpanded {
28178        ids: Vec<ExcerptId>,
28179    },
28180    ExpandExcerptsRequested {
28181        excerpt_ids: Vec<ExcerptId>,
28182        lines: u32,
28183        direction: ExpandExcerptDirection,
28184    },
28185    StageOrUnstageRequested {
28186        stage: bool,
28187        hunks: Vec<MultiBufferDiffHunk>,
28188    },
28189    OpenExcerptsRequested {
28190        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28191        split: bool,
28192    },
28193    RestoreRequested {
28194        hunks: Vec<MultiBufferDiffHunk>,
28195    },
28196    BufferEdited,
28197    Edited {
28198        transaction_id: clock::Lamport,
28199    },
28200    Reparsed(BufferId),
28201    Focused,
28202    FocusedIn,
28203    Blurred,
28204    DirtyChanged,
28205    Saved,
28206    TitleChanged,
28207    SelectionsChanged {
28208        local: bool,
28209    },
28210    ScrollPositionChanged {
28211        local: bool,
28212        autoscroll: bool,
28213    },
28214    TransactionUndone {
28215        transaction_id: clock::Lamport,
28216    },
28217    TransactionBegun {
28218        transaction_id: clock::Lamport,
28219    },
28220    CursorShapeChanged,
28221    BreadcrumbsChanged,
28222    OutlineSymbolsChanged,
28223    PushedToNavHistory {
28224        anchor: Anchor,
28225        is_deactivate: bool,
28226    },
28227}
28228
28229impl EventEmitter<EditorEvent> for Editor {}
28230
28231impl Focusable for Editor {
28232    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28233        self.focus_handle.clone()
28234    }
28235}
28236
28237impl Render for Editor {
28238    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28239        EditorElement::new(&cx.entity(), self.create_style(cx))
28240    }
28241}
28242
28243impl EntityInputHandler for Editor {
28244    fn text_for_range(
28245        &mut self,
28246        range_utf16: Range<usize>,
28247        adjusted_range: &mut Option<Range<usize>>,
28248        _: &mut Window,
28249        cx: &mut Context<Self>,
28250    ) -> Option<String> {
28251        let snapshot = self.buffer.read(cx).read(cx);
28252        let start = snapshot.clip_offset_utf16(
28253            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28254            Bias::Left,
28255        );
28256        let end = snapshot.clip_offset_utf16(
28257            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28258            Bias::Right,
28259        );
28260        if (start.0.0..end.0.0) != range_utf16 {
28261            adjusted_range.replace(start.0.0..end.0.0);
28262        }
28263        Some(snapshot.text_for_range(start..end).collect())
28264    }
28265
28266    fn selected_text_range(
28267        &mut self,
28268        ignore_disabled_input: bool,
28269        _: &mut Window,
28270        cx: &mut Context<Self>,
28271    ) -> Option<UTF16Selection> {
28272        // Prevent the IME menu from appearing when holding down an alphabetic key
28273        // while input is disabled.
28274        if !ignore_disabled_input && !self.input_enabled {
28275            return None;
28276        }
28277
28278        let selection = self
28279            .selections
28280            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28281        let range = selection.range();
28282
28283        Some(UTF16Selection {
28284            range: range.start.0.0..range.end.0.0,
28285            reversed: selection.reversed,
28286        })
28287    }
28288
28289    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28290        let snapshot = self.buffer.read(cx).read(cx);
28291        let range = self
28292            .text_highlights(HighlightKey::InputComposition, cx)?
28293            .1
28294            .first()?;
28295        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28296    }
28297
28298    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28299        self.clear_highlights(HighlightKey::InputComposition, cx);
28300        self.ime_transaction.take();
28301    }
28302
28303    fn replace_text_in_range(
28304        &mut self,
28305        range_utf16: Option<Range<usize>>,
28306        text: &str,
28307        window: &mut Window,
28308        cx: &mut Context<Self>,
28309    ) {
28310        if !self.input_enabled {
28311            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28312            return;
28313        }
28314
28315        self.transact(window, cx, |this, window, cx| {
28316            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28317                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28318                    // During IME composition, macOS reports the replacement range
28319                    // relative to the first marked region (the only one visible via
28320                    // marked_text_range). The correct targets for replacement are the
28321                    // marked ranges themselves — one per cursor — so use them directly.
28322                    Some(marked_ranges)
28323                } else if range_utf16.start == range_utf16.end {
28324                    // An empty replacement range means "insert at cursor" with no text
28325                    // to replace. macOS reports the cursor position from its own
28326                    // (single-cursor) view of the buffer, which diverges from our actual
28327                    // cursor positions after multi-cursor edits have shifted offsets.
28328                    // Treating this as range_utf16=None lets each cursor insert in place.
28329                    None
28330                } else {
28331                    // Outside of IME composition (e.g. Accessibility Keyboard word
28332                    // completion), the range is an absolute document offset for the
28333                    // newest cursor. Fan it out to all cursors via
28334                    // selection_replacement_ranges, which applies the delta relative
28335                    // to the newest selection to every cursor.
28336                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28337                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28338                    Some(this.selection_replacement_ranges(range_utf16, cx))
28339                }
28340            } else {
28341                this.marked_text_ranges(cx)
28342            };
28343
28344            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28345                let newest_selection_id = this.selections.newest_anchor().id;
28346                this.selections
28347                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28348                    .iter()
28349                    .zip(ranges_to_replace.iter())
28350                    .find_map(|(selection, range)| {
28351                        if selection.id == newest_selection_id {
28352                            Some(
28353                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28354                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28355                            )
28356                        } else {
28357                            None
28358                        }
28359                    })
28360            });
28361
28362            cx.emit(EditorEvent::InputHandled {
28363                utf16_range_to_replace: range_to_replace,
28364                text: text.into(),
28365            });
28366
28367            if let Some(new_selected_ranges) = new_selected_ranges {
28368                // Only backspace if at least one range covers actual text. When all
28369                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28370                // Keyboard sends replacementRange=cursor..cursor), backspace would
28371                // incorrectly delete the character just before the cursor.
28372                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28373                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28374                    selections.select_ranges(new_selected_ranges)
28375                });
28376                if should_backspace {
28377                    this.backspace(&Default::default(), window, cx);
28378                }
28379            }
28380
28381            this.handle_input(text, window, cx);
28382        });
28383
28384        if let Some(transaction) = self.ime_transaction {
28385            self.buffer.update(cx, |buffer, cx| {
28386                buffer.group_until_transaction(transaction, cx);
28387            });
28388        }
28389
28390        self.unmark_text(window, cx);
28391    }
28392
28393    fn replace_and_mark_text_in_range(
28394        &mut self,
28395        range_utf16: Option<Range<usize>>,
28396        text: &str,
28397        new_selected_range_utf16: Option<Range<usize>>,
28398        window: &mut Window,
28399        cx: &mut Context<Self>,
28400    ) {
28401        if !self.input_enabled {
28402            return;
28403        }
28404
28405        let transaction = self.transact(window, cx, |this, window, cx| {
28406            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28407                let snapshot = this.buffer.read(cx).read(cx);
28408                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28409                    for marked_range in &mut marked_ranges {
28410                        marked_range.end = marked_range.start + relative_range_utf16.end;
28411                        marked_range.start += relative_range_utf16.start;
28412                        marked_range.start =
28413                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28414                        marked_range.end =
28415                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28416                    }
28417                }
28418                Some(marked_ranges)
28419            } else if let Some(range_utf16) = range_utf16 {
28420                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28421                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28422                Some(this.selection_replacement_ranges(range_utf16, cx))
28423            } else {
28424                None
28425            };
28426
28427            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28428                let newest_selection_id = this.selections.newest_anchor().id;
28429                this.selections
28430                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28431                    .iter()
28432                    .zip(ranges_to_replace.iter())
28433                    .find_map(|(selection, range)| {
28434                        if selection.id == newest_selection_id {
28435                            Some(
28436                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28437                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28438                            )
28439                        } else {
28440                            None
28441                        }
28442                    })
28443            });
28444
28445            cx.emit(EditorEvent::InputHandled {
28446                utf16_range_to_replace: range_to_replace,
28447                text: text.into(),
28448            });
28449
28450            if let Some(ranges) = ranges_to_replace {
28451                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28452                    s.select_ranges(ranges)
28453                });
28454            }
28455
28456            let marked_ranges = {
28457                let snapshot = this.buffer.read(cx).read(cx);
28458                this.selections
28459                    .disjoint_anchors_arc()
28460                    .iter()
28461                    .map(|selection| {
28462                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28463                    })
28464                    .collect::<Vec<_>>()
28465            };
28466
28467            if text.is_empty() {
28468                this.unmark_text(window, cx);
28469            } else {
28470                this.highlight_text(
28471                    HighlightKey::InputComposition,
28472                    marked_ranges.clone(),
28473                    HighlightStyle {
28474                        underline: Some(UnderlineStyle {
28475                            thickness: px(1.),
28476                            color: None,
28477                            wavy: false,
28478                        }),
28479                        ..Default::default()
28480                    },
28481                    cx,
28482                );
28483            }
28484
28485            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28486            let use_autoclose = this.use_autoclose;
28487            let use_auto_surround = this.use_auto_surround;
28488            this.set_use_autoclose(false);
28489            this.set_use_auto_surround(false);
28490            this.handle_input(text, window, cx);
28491            this.set_use_autoclose(use_autoclose);
28492            this.set_use_auto_surround(use_auto_surround);
28493
28494            if let Some(new_selected_range) = new_selected_range_utf16 {
28495                let snapshot = this.buffer.read(cx).read(cx);
28496                let new_selected_ranges = marked_ranges
28497                    .into_iter()
28498                    .map(|marked_range| {
28499                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28500                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28501                            insertion_start.0 + new_selected_range.start,
28502                        ));
28503                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28504                            insertion_start.0 + new_selected_range.end,
28505                        ));
28506                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28507                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28508                    })
28509                    .collect::<Vec<_>>();
28510
28511                drop(snapshot);
28512                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28513                    selections.select_ranges(new_selected_ranges)
28514                });
28515            }
28516        });
28517
28518        self.ime_transaction = self.ime_transaction.or(transaction);
28519        if let Some(transaction) = self.ime_transaction {
28520            self.buffer.update(cx, |buffer, cx| {
28521                buffer.group_until_transaction(transaction, cx);
28522            });
28523        }
28524
28525        if self
28526            .text_highlights(HighlightKey::InputComposition, cx)
28527            .is_none()
28528        {
28529            self.ime_transaction.take();
28530        }
28531    }
28532
28533    fn bounds_for_range(
28534        &mut self,
28535        range_utf16: Range<usize>,
28536        element_bounds: gpui::Bounds<Pixels>,
28537        window: &mut Window,
28538        cx: &mut Context<Self>,
28539    ) -> Option<gpui::Bounds<Pixels>> {
28540        let text_layout_details = self.text_layout_details(window, cx);
28541        let CharacterDimensions {
28542            em_width,
28543            em_advance,
28544            line_height,
28545        } = self.character_dimensions(window, cx);
28546
28547        let snapshot = self.snapshot(window, cx);
28548        let scroll_position = snapshot.scroll_position();
28549        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28550
28551        let start =
28552            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28553        let x = Pixels::from(
28554            ScrollOffset::from(
28555                snapshot.x_for_display_point(start, &text_layout_details)
28556                    + self.gutter_dimensions.full_width(),
28557            ) - scroll_left,
28558        );
28559        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28560
28561        Some(Bounds {
28562            origin: element_bounds.origin + point(x, y),
28563            size: size(em_width, line_height),
28564        })
28565    }
28566
28567    fn character_index_for_point(
28568        &mut self,
28569        point: gpui::Point<Pixels>,
28570        _window: &mut Window,
28571        _cx: &mut Context<Self>,
28572    ) -> Option<usize> {
28573        let position_map = self.last_position_map.as_ref()?;
28574        if !position_map.text_hitbox.contains(&point) {
28575            return None;
28576        }
28577        let display_point = position_map.point_for_position(point).previous_valid;
28578        let anchor = position_map
28579            .snapshot
28580            .display_point_to_anchor(display_point, Bias::Left);
28581        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28582        Some(utf16_offset.0.0)
28583    }
28584
28585    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28586        self.expects_character_input
28587    }
28588}
28589
28590trait SelectionExt {
28591    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28592    fn spanned_rows(
28593        &self,
28594        include_end_if_at_line_start: bool,
28595        map: &DisplaySnapshot,
28596    ) -> Range<MultiBufferRow>;
28597}
28598
28599impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28600    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28601        let start = self
28602            .start
28603            .to_point(map.buffer_snapshot())
28604            .to_display_point(map);
28605        let end = self
28606            .end
28607            .to_point(map.buffer_snapshot())
28608            .to_display_point(map);
28609        if self.reversed {
28610            end..start
28611        } else {
28612            start..end
28613        }
28614    }
28615
28616    fn spanned_rows(
28617        &self,
28618        include_end_if_at_line_start: bool,
28619        map: &DisplaySnapshot,
28620    ) -> Range<MultiBufferRow> {
28621        let start = self.start.to_point(map.buffer_snapshot());
28622        let mut end = self.end.to_point(map.buffer_snapshot());
28623        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28624            end.row -= 1;
28625        }
28626
28627        let buffer_start = map.prev_line_boundary(start).0;
28628        let buffer_end = map.next_line_boundary(end).0;
28629        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28630    }
28631}
28632
28633impl<T: InvalidationRegion> InvalidationStack<T> {
28634    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28635    where
28636        S: Clone + ToOffset,
28637    {
28638        while let Some(region) = self.last() {
28639            let all_selections_inside_invalidation_ranges =
28640                if selections.len() == region.ranges().len() {
28641                    selections
28642                        .iter()
28643                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28644                        .all(|(selection, invalidation_range)| {
28645                            let head = selection.head().to_offset(buffer);
28646                            invalidation_range.start <= head && invalidation_range.end >= head
28647                        })
28648                } else {
28649                    false
28650                };
28651
28652            if all_selections_inside_invalidation_ranges {
28653                break;
28654            } else {
28655                self.pop();
28656            }
28657        }
28658    }
28659}
28660
28661#[derive(Clone)]
28662struct ErasedEditorImpl(Entity<Editor>);
28663
28664impl ui_input::ErasedEditor for ErasedEditorImpl {
28665    fn text(&self, cx: &App) -> String {
28666        self.0.read(cx).text(cx)
28667    }
28668
28669    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28670        self.0.update(cx, |this, cx| {
28671            this.set_text(text, window, cx);
28672        })
28673    }
28674
28675    fn clear(&self, window: &mut Window, cx: &mut App) {
28676        self.0.update(cx, |this, cx| this.clear(window, cx));
28677    }
28678
28679    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28680        self.0.update(cx, |this, cx| {
28681            this.set_placeholder_text(text, window, cx);
28682        });
28683    }
28684
28685    fn focus_handle(&self, cx: &App) -> FocusHandle {
28686        self.0.read(cx).focus_handle(cx)
28687    }
28688
28689    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28690        let settings = ThemeSettings::get_global(cx);
28691        let theme_color = cx.theme().colors();
28692
28693        let text_style = TextStyle {
28694            font_family: settings.ui_font.family.clone(),
28695            font_features: settings.ui_font.features.clone(),
28696            font_size: rems(0.875).into(),
28697            font_weight: settings.ui_font.weight,
28698            font_style: FontStyle::Normal,
28699            line_height: relative(1.2),
28700            color: theme_color.text,
28701            ..Default::default()
28702        };
28703        let editor_style = EditorStyle {
28704            background: theme_color.ghost_element_background,
28705            local_player: cx.theme().players().local(),
28706            syntax: cx.theme().syntax().clone(),
28707            text: text_style,
28708            ..Default::default()
28709        };
28710        EditorElement::new(&self.0, editor_style).into_any()
28711    }
28712
28713    fn as_any(&self) -> &dyn Any {
28714        &self.0
28715    }
28716
28717    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28718        self.0.update(cx, |editor, cx| {
28719            let editor_offset = editor.buffer().read(cx).len(cx);
28720            editor.change_selections(
28721                SelectionEffects::scroll(Autoscroll::Next),
28722                window,
28723                cx,
28724                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28725            );
28726        });
28727    }
28728
28729    fn subscribe(
28730        &self,
28731        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28732        window: &mut Window,
28733        cx: &mut App,
28734    ) -> Subscription {
28735        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28736            let event = match event {
28737                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28738                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28739                _ => return,
28740            };
28741            (callback)(event, window, cx);
28742        })
28743    }
28744
28745    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28746        self.0.update(cx, |editor, cx| {
28747            editor.set_masked(masked, cx);
28748        });
28749    }
28750}
28751impl<T> Default for InvalidationStack<T> {
28752    fn default() -> Self {
28753        Self(Default::default())
28754    }
28755}
28756
28757impl<T> Deref for InvalidationStack<T> {
28758    type Target = Vec<T>;
28759
28760    fn deref(&self) -> &Self::Target {
28761        &self.0
28762    }
28763}
28764
28765impl<T> DerefMut for InvalidationStack<T> {
28766    fn deref_mut(&mut self) -> &mut Self::Target {
28767        &mut self.0
28768    }
28769}
28770
28771impl InvalidationRegion for SnippetState {
28772    fn ranges(&self) -> &[Range<Anchor>] {
28773        &self.ranges[self.active_index]
28774    }
28775}
28776
28777fn edit_prediction_edit_text(
28778    current_snapshot: &BufferSnapshot,
28779    edits: &[(Range<Anchor>, impl AsRef<str>)],
28780    edit_preview: &EditPreview,
28781    include_deletions: bool,
28782    cx: &App,
28783) -> HighlightedText {
28784    let edits = edits
28785        .iter()
28786        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
28787        .collect::<Vec<_>>();
28788
28789    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28790}
28791
28792fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28793    // Fallback for providers that don't provide edit_preview (like Copilot)
28794    // Just show the raw edit text with basic styling
28795    let mut text = String::new();
28796    let mut highlights = Vec::new();
28797
28798    let insertion_highlight_style = HighlightStyle {
28799        color: Some(cx.theme().colors().text),
28800        ..Default::default()
28801    };
28802
28803    for (_, edit_text) in edits {
28804        let start_offset = text.len();
28805        text.push_str(edit_text);
28806        let end_offset = text.len();
28807
28808        if start_offset < end_offset {
28809            highlights.push((start_offset..end_offset, insertion_highlight_style));
28810        }
28811    }
28812
28813    HighlightedText {
28814        text: text.into(),
28815        highlights,
28816    }
28817}
28818
28819pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28820    match severity {
28821        lsp::DiagnosticSeverity::ERROR => colors.error,
28822        lsp::DiagnosticSeverity::WARNING => colors.warning,
28823        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28824        lsp::DiagnosticSeverity::HINT => colors.info,
28825        _ => colors.ignored,
28826    }
28827}
28828
28829pub fn styled_runs_for_code_label<'a>(
28830    label: &'a CodeLabel,
28831    syntax_theme: &'a theme::SyntaxTheme,
28832    local_player: &'a theme::PlayerColor,
28833) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28834    let fade_out = HighlightStyle {
28835        fade_out: Some(0.35),
28836        ..Default::default()
28837    };
28838
28839    let mut prev_end = label.filter_range.end;
28840    label
28841        .runs
28842        .iter()
28843        .enumerate()
28844        .flat_map(move |(ix, (range, highlight_id))| {
28845            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28846                HighlightStyle {
28847                    color: Some(local_player.cursor),
28848                    ..Default::default()
28849                }
28850            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28851                HighlightStyle {
28852                    background_color: Some(local_player.selection),
28853                    ..Default::default()
28854                }
28855            } else if let Some(style) = highlight_id.style(syntax_theme) {
28856                style
28857            } else {
28858                return Default::default();
28859            };
28860            let muted_style = style.highlight(fade_out);
28861
28862            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28863            if range.start >= label.filter_range.end {
28864                if range.start > prev_end {
28865                    runs.push((prev_end..range.start, fade_out));
28866                }
28867                runs.push((range.clone(), muted_style));
28868            } else if range.end <= label.filter_range.end {
28869                runs.push((range.clone(), style));
28870            } else {
28871                runs.push((range.start..label.filter_range.end, style));
28872                runs.push((label.filter_range.end..range.end, muted_style));
28873            }
28874            prev_end = cmp::max(prev_end, range.end);
28875
28876            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28877                runs.push((prev_end..label.text.len(), fade_out));
28878            }
28879
28880            runs
28881        })
28882}
28883
28884pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28885    let mut prev_index = 0;
28886    let mut prev_codepoint: Option<char> = None;
28887    text.char_indices()
28888        .chain([(text.len(), '\0')])
28889        .filter_map(move |(index, codepoint)| {
28890            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28891            let is_boundary = index == text.len()
28892                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28893                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28894            if is_boundary {
28895                let chunk = &text[prev_index..index];
28896                prev_index = index;
28897                Some(chunk)
28898            } else {
28899                None
28900            }
28901        })
28902}
28903
28904/// Given a string of text immediately before the cursor, iterates over possible
28905/// strings a snippet could match to. More precisely: returns an iterator over
28906/// suffixes of `text` created by splitting at word boundaries (before & after
28907/// every non-word character).
28908///
28909/// Shorter suffixes are returned first.
28910pub(crate) fn snippet_candidate_suffixes<'a>(
28911    text: &'a str,
28912    is_word_char: &'a dyn Fn(char) -> bool,
28913) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28914    let mut prev_index = text.len();
28915    let mut prev_codepoint = None;
28916    text.char_indices()
28917        .rev()
28918        .chain([(0, '\0')])
28919        .filter_map(move |(index, codepoint)| {
28920            let prev_index = std::mem::replace(&mut prev_index, index);
28921            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28922            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28923                None
28924            } else {
28925                let chunk = &text[prev_index..]; // go to end of string
28926                Some(chunk)
28927            }
28928        })
28929}
28930
28931pub trait RangeToAnchorExt: Sized {
28932    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28933
28934    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28935        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28936        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28937    }
28938}
28939
28940impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28941    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28942        let start_offset = self.start.to_offset(snapshot);
28943        let end_offset = self.end.to_offset(snapshot);
28944        if start_offset == end_offset {
28945            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28946        } else {
28947            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28948        }
28949    }
28950}
28951
28952pub trait RowExt {
28953    fn as_f64(&self) -> f64;
28954
28955    fn next_row(&self) -> Self;
28956
28957    fn previous_row(&self) -> Self;
28958
28959    fn minus(&self, other: Self) -> u32;
28960}
28961
28962impl RowExt for DisplayRow {
28963    fn as_f64(&self) -> f64 {
28964        self.0 as _
28965    }
28966
28967    fn next_row(&self) -> Self {
28968        Self(self.0 + 1)
28969    }
28970
28971    fn previous_row(&self) -> Self {
28972        Self(self.0.saturating_sub(1))
28973    }
28974
28975    fn minus(&self, other: Self) -> u32 {
28976        self.0 - other.0
28977    }
28978}
28979
28980impl RowExt for MultiBufferRow {
28981    fn as_f64(&self) -> f64 {
28982        self.0 as _
28983    }
28984
28985    fn next_row(&self) -> Self {
28986        Self(self.0 + 1)
28987    }
28988
28989    fn previous_row(&self) -> Self {
28990        Self(self.0.saturating_sub(1))
28991    }
28992
28993    fn minus(&self, other: Self) -> u32 {
28994        self.0 - other.0
28995    }
28996}
28997
28998trait RowRangeExt {
28999    type Row;
29000
29001    fn len(&self) -> usize;
29002
29003    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29004}
29005
29006impl RowRangeExt for Range<MultiBufferRow> {
29007    type Row = MultiBufferRow;
29008
29009    fn len(&self) -> usize {
29010        (self.end.0 - self.start.0) as usize
29011    }
29012
29013    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29014        (self.start.0..self.end.0).map(MultiBufferRow)
29015    }
29016}
29017
29018impl RowRangeExt for Range<DisplayRow> {
29019    type Row = DisplayRow;
29020
29021    fn len(&self) -> usize {
29022        (self.end.0 - self.start.0) as usize
29023    }
29024
29025    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29026        (self.start.0..self.end.0).map(DisplayRow)
29027    }
29028}
29029
29030/// If select range has more than one line, we
29031/// just point the cursor to range.start.
29032fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29033    if range.start.row == range.end.row {
29034        range
29035    } else {
29036        range.start..range.start
29037    }
29038}
29039pub struct KillRing(ClipboardItem);
29040impl Global for KillRing {}
29041
29042const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29043
29044enum BreakpointPromptEditAction {
29045    Log,
29046    Condition,
29047    HitCondition,
29048}
29049
29050struct BreakpointPromptEditor {
29051    pub(crate) prompt: Entity<Editor>,
29052    editor: WeakEntity<Editor>,
29053    breakpoint_anchor: Anchor,
29054    breakpoint: Breakpoint,
29055    edit_action: BreakpointPromptEditAction,
29056    block_ids: HashSet<CustomBlockId>,
29057    editor_margins: Arc<Mutex<EditorMargins>>,
29058    _subscriptions: Vec<Subscription>,
29059}
29060
29061impl BreakpointPromptEditor {
29062    const MAX_LINES: u8 = 4;
29063
29064    fn new(
29065        editor: WeakEntity<Editor>,
29066        breakpoint_anchor: Anchor,
29067        breakpoint: Breakpoint,
29068        edit_action: BreakpointPromptEditAction,
29069        window: &mut Window,
29070        cx: &mut Context<Self>,
29071    ) -> Self {
29072        let base_text = match edit_action {
29073            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29074            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29075            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29076        }
29077        .map(|msg| msg.to_string())
29078        .unwrap_or_default();
29079
29080        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29081        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29082
29083        let prompt = cx.new(|cx| {
29084            let mut prompt = Editor::new(
29085                EditorMode::AutoHeight {
29086                    min_lines: 1,
29087                    max_lines: Some(Self::MAX_LINES as usize),
29088                },
29089                buffer,
29090                None,
29091                window,
29092                cx,
29093            );
29094            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29095            prompt.set_show_cursor_when_unfocused(false, cx);
29096            prompt.set_placeholder_text(
29097                match edit_action {
29098                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29099                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29100                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29101                },
29102                window,
29103                cx,
29104            );
29105
29106            prompt
29107        });
29108
29109        Self {
29110            prompt,
29111            editor,
29112            breakpoint_anchor,
29113            breakpoint,
29114            edit_action,
29115            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29116            block_ids: Default::default(),
29117            _subscriptions: vec![],
29118        }
29119    }
29120
29121    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29122        self.block_ids.extend(block_ids)
29123    }
29124
29125    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29126        if let Some(editor) = self.editor.upgrade() {
29127            let message = self
29128                .prompt
29129                .read(cx)
29130                .buffer
29131                .read(cx)
29132                .as_singleton()
29133                .expect("A multi buffer in breakpoint prompt isn't possible")
29134                .read(cx)
29135                .as_rope()
29136                .to_string();
29137
29138            editor.update(cx, |editor, cx| {
29139                editor.edit_breakpoint_at_anchor(
29140                    self.breakpoint_anchor,
29141                    self.breakpoint.clone(),
29142                    match self.edit_action {
29143                        BreakpointPromptEditAction::Log => {
29144                            BreakpointEditAction::EditLogMessage(message.into())
29145                        }
29146                        BreakpointPromptEditAction::Condition => {
29147                            BreakpointEditAction::EditCondition(message.into())
29148                        }
29149                        BreakpointPromptEditAction::HitCondition => {
29150                            BreakpointEditAction::EditHitCondition(message.into())
29151                        }
29152                    },
29153                    cx,
29154                );
29155
29156                editor.remove_blocks(self.block_ids.clone(), None, cx);
29157                cx.focus_self(window);
29158            });
29159        }
29160    }
29161
29162    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29163        self.editor
29164            .update(cx, |editor, cx| {
29165                editor.remove_blocks(self.block_ids.clone(), None, cx);
29166                window.focus(&editor.focus_handle, cx);
29167            })
29168            .log_err();
29169    }
29170
29171    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29172        let settings = ThemeSettings::get_global(cx);
29173        let text_style = TextStyle {
29174            color: if self.prompt.read(cx).read_only(cx) {
29175                cx.theme().colors().text_disabled
29176            } else {
29177                cx.theme().colors().text
29178            },
29179            font_family: settings.buffer_font.family.clone(),
29180            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29181            font_size: settings.buffer_font_size(cx).into(),
29182            font_weight: settings.buffer_font.weight,
29183            line_height: relative(settings.buffer_line_height.value()),
29184            ..Default::default()
29185        };
29186        EditorElement::new(
29187            &self.prompt,
29188            EditorStyle {
29189                background: cx.theme().colors().editor_background,
29190                local_player: cx.theme().players().local(),
29191                text: text_style,
29192                ..Default::default()
29193            },
29194        )
29195    }
29196
29197    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29198        let focus_handle = self.prompt.focus_handle(cx);
29199        IconButton::new("cancel", IconName::Close)
29200            .icon_color(Color::Muted)
29201            .shape(IconButtonShape::Square)
29202            .tooltip(move |_window, cx| {
29203                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29204            })
29205            .on_click(cx.listener(|this, _, window, cx| {
29206                this.cancel(&menu::Cancel, window, cx);
29207            }))
29208    }
29209
29210    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29211        let focus_handle = self.prompt.focus_handle(cx);
29212        IconButton::new("confirm", IconName::Return)
29213            .icon_color(Color::Muted)
29214            .shape(IconButtonShape::Square)
29215            .tooltip(move |_window, cx| {
29216                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29217            })
29218            .on_click(cx.listener(|this, _, window, cx| {
29219                this.confirm(&menu::Confirm, window, cx);
29220            }))
29221    }
29222}
29223
29224impl Render for BreakpointPromptEditor {
29225    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29226        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29227        let editor_margins = *self.editor_margins.lock();
29228        let gutter_dimensions = editor_margins.gutter;
29229        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29230        let right_padding = editor_margins.right + px(9.);
29231        h_flex()
29232            .key_context("Editor")
29233            .bg(cx.theme().colors().editor_background)
29234            .border_y_1()
29235            .border_color(cx.theme().status().info_border)
29236            .size_full()
29237            .py(window.line_height() / 2.5)
29238            .pr(right_padding)
29239            .on_action(cx.listener(Self::confirm))
29240            .on_action(cx.listener(Self::cancel))
29241            .child(
29242                WithRemSize::new(ui_font_size)
29243                    .h_full()
29244                    .w(left_gutter_width)
29245                    .flex()
29246                    .flex_row()
29247                    .flex_shrink_0()
29248                    .items_center()
29249                    .justify_center()
29250                    .gap_1()
29251                    .child(self.render_close_button(cx)),
29252            )
29253            .child(
29254                h_flex()
29255                    .w_full()
29256                    .justify_between()
29257                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29258                    .child(
29259                        WithRemSize::new(ui_font_size)
29260                            .flex()
29261                            .flex_row()
29262                            .items_center()
29263                            .child(self.render_confirm_button(cx)),
29264                    ),
29265            )
29266    }
29267}
29268
29269impl Focusable for BreakpointPromptEditor {
29270    fn focus_handle(&self, cx: &App) -> FocusHandle {
29271        self.prompt.focus_handle(cx)
29272    }
29273}
29274
29275fn all_edits_insertions_or_deletions(
29276    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29277    snapshot: &MultiBufferSnapshot,
29278) -> bool {
29279    let mut all_insertions = true;
29280    let mut all_deletions = true;
29281
29282    for (range, new_text) in edits.iter() {
29283        let range_is_empty = range.to_offset(snapshot).is_empty();
29284        let text_is_empty = new_text.is_empty();
29285
29286        if range_is_empty != text_is_empty {
29287            if range_is_empty {
29288                all_deletions = false;
29289            } else {
29290                all_insertions = false;
29291            }
29292        } else {
29293            return false;
29294        }
29295
29296        if !all_insertions && !all_deletions {
29297            return false;
29298        }
29299    }
29300    all_insertions || all_deletions
29301}
29302
29303struct MissingEditPredictionKeybindingTooltip;
29304
29305impl Render for MissingEditPredictionKeybindingTooltip {
29306    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29307        ui::tooltip_container(cx, |container, cx| {
29308            container
29309                .flex_shrink_0()
29310                .max_w_80()
29311                .min_h(rems_from_px(124.))
29312                .justify_between()
29313                .child(
29314                    v_flex()
29315                        .flex_1()
29316                        .text_ui_sm(cx)
29317                        .child(Label::new("Conflict with Accept Keybinding"))
29318                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29319                )
29320                .child(
29321                    h_flex()
29322                        .pb_1()
29323                        .gap_1()
29324                        .items_end()
29325                        .w_full()
29326                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29327                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29328                        }))
29329                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29330                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29331                        })),
29332                )
29333        })
29334    }
29335}
29336
29337#[derive(Debug, Clone, Copy, PartialEq)]
29338pub struct LineHighlight {
29339    pub background: Background,
29340    pub border: Option<gpui::Hsla>,
29341    pub include_gutter: bool,
29342    pub type_id: Option<TypeId>,
29343}
29344
29345struct LineManipulationResult {
29346    pub new_text: String,
29347    pub line_count_before: usize,
29348    pub line_count_after: usize,
29349}
29350
29351fn render_diff_hunk_controls(
29352    row: u32,
29353    status: &DiffHunkStatus,
29354    hunk_range: Range<Anchor>,
29355    is_created_file: bool,
29356    line_height: Pixels,
29357    editor: &Entity<Editor>,
29358    _window: &mut Window,
29359    cx: &mut App,
29360) -> AnyElement {
29361    h_flex()
29362        .h(line_height)
29363        .mr_1()
29364        .gap_1()
29365        .px_0p5()
29366        .pb_1()
29367        .border_x_1()
29368        .border_b_1()
29369        .border_color(cx.theme().colors().border_variant)
29370        .rounded_b_lg()
29371        .bg(cx.theme().colors().editor_background)
29372        .gap_1()
29373        .block_mouse_except_scroll()
29374        .shadow_md()
29375        .child(if status.has_secondary_hunk() {
29376            Button::new(("stage", row as u64), "Stage")
29377                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29378                .tooltip({
29379                    let focus_handle = editor.focus_handle(cx);
29380                    move |_window, cx| {
29381                        Tooltip::for_action_in(
29382                            "Stage Hunk",
29383                            &::git::ToggleStaged,
29384                            &focus_handle,
29385                            cx,
29386                        )
29387                    }
29388                })
29389                .on_click({
29390                    let editor = editor.clone();
29391                    move |_event, _window, cx| {
29392                        editor.update(cx, |editor, cx| {
29393                            editor.stage_or_unstage_diff_hunks(
29394                                true,
29395                                vec![hunk_range.start..hunk_range.start],
29396                                cx,
29397                            );
29398                        });
29399                    }
29400                })
29401        } else {
29402            Button::new(("unstage", row as u64), "Unstage")
29403                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29404                .tooltip({
29405                    let focus_handle = editor.focus_handle(cx);
29406                    move |_window, cx| {
29407                        Tooltip::for_action_in(
29408                            "Unstage Hunk",
29409                            &::git::ToggleStaged,
29410                            &focus_handle,
29411                            cx,
29412                        )
29413                    }
29414                })
29415                .on_click({
29416                    let editor = editor.clone();
29417                    move |_event, _window, cx| {
29418                        editor.update(cx, |editor, cx| {
29419                            editor.stage_or_unstage_diff_hunks(
29420                                false,
29421                                vec![hunk_range.start..hunk_range.start],
29422                                cx,
29423                            );
29424                        });
29425                    }
29426                })
29427        })
29428        .child(
29429            Button::new(("restore", row as u64), "Restore")
29430                .tooltip({
29431                    let focus_handle = editor.focus_handle(cx);
29432                    move |_window, cx| {
29433                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29434                    }
29435                })
29436                .on_click({
29437                    let editor = editor.clone();
29438                    move |_event, window, cx| {
29439                        editor.update(cx, |editor, cx| {
29440                            let snapshot = editor.snapshot(window, cx);
29441                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29442                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29443                        });
29444                    }
29445                })
29446                .disabled(is_created_file),
29447        )
29448        .when(
29449            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29450            |el| {
29451                el.child(
29452                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29453                        .shape(IconButtonShape::Square)
29454                        .icon_size(IconSize::Small)
29455                        // .disabled(!has_multiple_hunks)
29456                        .tooltip({
29457                            let focus_handle = editor.focus_handle(cx);
29458                            move |_window, cx| {
29459                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29460                            }
29461                        })
29462                        .on_click({
29463                            let editor = editor.clone();
29464                            move |_event, window, cx| {
29465                                editor.update(cx, |editor, cx| {
29466                                    let snapshot = editor.snapshot(window, cx);
29467                                    let position =
29468                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29469                                    editor.go_to_hunk_before_or_after_position(
29470                                        &snapshot,
29471                                        position,
29472                                        Direction::Next,
29473                                        true,
29474                                        window,
29475                                        cx,
29476                                    );
29477                                    editor.expand_selected_diff_hunks(cx);
29478                                });
29479                            }
29480                        }),
29481                )
29482                .child(
29483                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29484                        .shape(IconButtonShape::Square)
29485                        .icon_size(IconSize::Small)
29486                        // .disabled(!has_multiple_hunks)
29487                        .tooltip({
29488                            let focus_handle = editor.focus_handle(cx);
29489                            move |_window, cx| {
29490                                Tooltip::for_action_in(
29491                                    "Previous Hunk",
29492                                    &GoToPreviousHunk,
29493                                    &focus_handle,
29494                                    cx,
29495                                )
29496                            }
29497                        })
29498                        .on_click({
29499                            let editor = editor.clone();
29500                            move |_event, window, cx| {
29501                                editor.update(cx, |editor, cx| {
29502                                    let snapshot = editor.snapshot(window, cx);
29503                                    let point =
29504                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29505                                    editor.go_to_hunk_before_or_after_position(
29506                                        &snapshot,
29507                                        point,
29508                                        Direction::Prev,
29509                                        true,
29510                                        window,
29511                                        cx,
29512                                    );
29513                                    editor.expand_selected_diff_hunks(cx);
29514                                });
29515                            }
29516                        }),
29517                )
29518            },
29519        )
29520        .into_any_element()
29521}
29522
29523pub fn multibuffer_context_lines(cx: &App) -> u32 {
29524    EditorSettings::try_get(cx)
29525        .map(|settings| settings.excerpt_context_lines)
29526        .unwrap_or(2)
29527        .min(32)
29528}