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, AllLanguageSettings, LanguageSettings, LspInsertMode, RewrapBehavior,
  140        WordsCompletionMode, all_language_settings,
  141    },
  142    point_from_lsp, point_to_lsp, text_diff_with_options,
  143};
  144use linked_editing_ranges::refresh_linked_ranges;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId,
  148};
  149use markdown::Markdown;
  150use mouse_context_menu::MouseContextMenu;
  151use movement::TextLayoutDetails;
  152use multi_buffer::{
  153    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 = AllLanguageSettings::get_global(cx)
  600        .defaults
  601        .inlay_hints
  602        .show_background;
  603
  604    let mut style = cx.theme().syntax().get("hint");
  605
  606    if style.color.is_none() {
  607        style.color = Some(cx.theme().status().hint);
  608    }
  609
  610    if !show_background {
  611        style.background_color = None;
  612        return style;
  613    }
  614
  615    if style.background_color.is_none() {
  616        style.background_color = Some(cx.theme().status().hint_background);
  617    }
  618
  619    style
  620}
  621
  622pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  623    EditPredictionStyles {
  624        insertion: HighlightStyle {
  625            color: Some(cx.theme().status().predictive),
  626            ..HighlightStyle::default()
  627        },
  628        whitespace: HighlightStyle {
  629            background_color: Some(cx.theme().status().created_background),
  630            ..HighlightStyle::default()
  631        },
  632    }
  633}
  634
  635type CompletionId = usize;
  636
  637pub(crate) enum EditDisplayMode {
  638    TabAccept,
  639    DiffPopover,
  640    Inline,
  641}
  642
  643enum EditPrediction {
  644    Edit {
  645        edits: Vec<(Range<Anchor>, Arc<str>)>,
  646        /// Predicted cursor position as (anchor, offset_from_anchor).
  647        /// The anchor is in multibuffer coordinates; after applying edits,
  648        /// resolve the anchor and add the offset to get the final cursor position.
  649        cursor_position: Option<(Anchor, usize)>,
  650        edit_preview: Option<EditPreview>,
  651        display_mode: EditDisplayMode,
  652        snapshot: BufferSnapshot,
  653    },
  654    /// Move to a specific location in the active editor
  655    MoveWithin {
  656        target: Anchor,
  657        snapshot: BufferSnapshot,
  658    },
  659    /// Move to a specific location in a different editor (not the active one)
  660    MoveOutside {
  661        target: language::Anchor,
  662        snapshot: BufferSnapshot,
  663    },
  664}
  665
  666struct EditPredictionState {
  667    inlay_ids: Vec<InlayId>,
  668    completion: EditPrediction,
  669    completion_id: Option<SharedString>,
  670    invalidation_range: Option<Range<Anchor>>,
  671}
  672
  673enum EditPredictionSettings {
  674    Disabled,
  675    Enabled {
  676        show_in_menu: bool,
  677        preview_requires_modifier: bool,
  678    },
  679}
  680
  681#[derive(Debug, Clone)]
  682struct InlineDiagnostic {
  683    message: SharedString,
  684    group_id: usize,
  685    is_primary: bool,
  686    start: Point,
  687    severity: lsp::DiagnosticSeverity,
  688}
  689
  690pub enum MenuEditPredictionsPolicy {
  691    Never,
  692    ByProvider,
  693}
  694
  695pub enum EditPredictionPreview {
  696    /// Modifier is not pressed
  697    Inactive { released_too_fast: bool },
  698    /// Modifier pressed
  699    Active {
  700        since: Instant,
  701        previous_scroll_position: Option<SharedScrollAnchor>,
  702    },
  703}
  704
  705#[derive(Copy, Clone, Eq, PartialEq)]
  706enum EditPredictionKeybindSurface {
  707    Inline,
  708    CursorPopoverCompact,
  709    CursorPopoverExpanded,
  710}
  711
  712#[derive(Copy, Clone, Eq, PartialEq, Debug)]
  713enum EditPredictionKeybindAction {
  714    Accept,
  715    Preview,
  716}
  717
  718struct EditPredictionKeybindDisplay {
  719    #[cfg(test)]
  720    accept_keystroke: Option<gpui::KeybindingKeystroke>,
  721    #[cfg(test)]
  722    preview_keystroke: Option<gpui::KeybindingKeystroke>,
  723    displayed_keystroke: Option<gpui::KeybindingKeystroke>,
  724    action: EditPredictionKeybindAction,
  725    missing_accept_keystroke: bool,
  726    show_hold_label: bool,
  727}
  728
  729impl EditPredictionPreview {
  730    pub fn released_too_fast(&self) -> bool {
  731        match self {
  732            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  733            EditPredictionPreview::Active { .. } => false,
  734        }
  735    }
  736
  737    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  738        if let EditPredictionPreview::Active {
  739            previous_scroll_position,
  740            ..
  741        } = self
  742        {
  743            *previous_scroll_position = scroll_position;
  744        }
  745    }
  746}
  747
  748pub struct ContextMenuOptions {
  749    pub min_entries_visible: usize,
  750    pub max_entries_visible: usize,
  751    pub placement: Option<ContextMenuPlacement>,
  752}
  753
  754#[derive(Debug, Clone, PartialEq, Eq)]
  755pub enum ContextMenuPlacement {
  756    Above,
  757    Below,
  758}
  759
  760#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  761struct EditorActionId(usize);
  762
  763impl EditorActionId {
  764    pub fn post_inc(&mut self) -> Self {
  765        let answer = self.0;
  766
  767        *self = Self(answer + 1);
  768
  769        Self(answer)
  770    }
  771}
  772
  773// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  774// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  775
  776type BackgroundHighlight = (
  777    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  778    Arc<[Range<Anchor>]>,
  779);
  780type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  781
  782#[derive(Default)]
  783struct ScrollbarMarkerState {
  784    scrollbar_size: Size<Pixels>,
  785    dirty: bool,
  786    markers: Arc<[PaintQuad]>,
  787    pending_refresh: Option<Task<Result<()>>>,
  788}
  789
  790impl ScrollbarMarkerState {
  791    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  792        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  793    }
  794}
  795
  796#[derive(Clone, Copy, PartialEq, Eq)]
  797pub enum MinimapVisibility {
  798    Disabled,
  799    Enabled {
  800        /// The configuration currently present in the users settings.
  801        setting_configuration: bool,
  802        /// Whether to override the currently set visibility from the users setting.
  803        toggle_override: bool,
  804    },
  805}
  806
  807impl MinimapVisibility {
  808    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  809        if mode.is_full() {
  810            Self::Enabled {
  811                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  812                toggle_override: false,
  813            }
  814        } else {
  815            Self::Disabled
  816        }
  817    }
  818
  819    fn hidden(&self) -> Self {
  820        match *self {
  821            Self::Enabled {
  822                setting_configuration,
  823                ..
  824            } => Self::Enabled {
  825                setting_configuration,
  826                toggle_override: setting_configuration,
  827            },
  828            Self::Disabled => Self::Disabled,
  829        }
  830    }
  831
  832    fn disabled(&self) -> bool {
  833        matches!(*self, Self::Disabled)
  834    }
  835
  836    fn settings_visibility(&self) -> bool {
  837        match *self {
  838            Self::Enabled {
  839                setting_configuration,
  840                ..
  841            } => setting_configuration,
  842            _ => false,
  843        }
  844    }
  845
  846    fn visible(&self) -> bool {
  847        match *self {
  848            Self::Enabled {
  849                setting_configuration,
  850                toggle_override,
  851            } => setting_configuration ^ toggle_override,
  852            _ => false,
  853        }
  854    }
  855
  856    fn toggle_visibility(&self) -> Self {
  857        match *self {
  858            Self::Enabled {
  859                toggle_override,
  860                setting_configuration,
  861            } => Self::Enabled {
  862                setting_configuration,
  863                toggle_override: !toggle_override,
  864            },
  865            Self::Disabled => Self::Disabled,
  866        }
  867    }
  868}
  869
  870#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  871pub enum BufferSerialization {
  872    All,
  873    NonDirtyBuffers,
  874}
  875
  876impl BufferSerialization {
  877    fn new(restore_unsaved_buffers: bool) -> Self {
  878        if restore_unsaved_buffers {
  879            Self::All
  880        } else {
  881            Self::NonDirtyBuffers
  882        }
  883    }
  884}
  885
  886/// Addons allow storing per-editor state in other crates (e.g. Vim)
  887pub trait Addon: 'static {
  888    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  889
  890    fn render_buffer_header_controls(
  891        &self,
  892        _: &ExcerptInfo,
  893        _: &Window,
  894        _: &App,
  895    ) -> Option<AnyElement> {
  896        None
  897    }
  898
  899    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  900        None
  901    }
  902
  903    fn to_any(&self) -> &dyn std::any::Any;
  904
  905    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  906        None
  907    }
  908}
  909
  910struct ChangeLocation {
  911    current: Option<Vec<Anchor>>,
  912    original: Vec<Anchor>,
  913}
  914impl ChangeLocation {
  915    fn locations(&self) -> &[Anchor] {
  916        self.current.as_ref().unwrap_or(&self.original)
  917    }
  918}
  919
  920/// A set of caret positions, registered when the editor was edited.
  921pub struct ChangeList {
  922    changes: Vec<ChangeLocation>,
  923    /// Currently "selected" change.
  924    position: Option<usize>,
  925}
  926
  927impl ChangeList {
  928    pub fn new() -> Self {
  929        Self {
  930            changes: Vec::new(),
  931            position: None,
  932        }
  933    }
  934
  935    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  936    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  937    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  938        if self.changes.is_empty() {
  939            return None;
  940        }
  941
  942        let prev = self.position.unwrap_or(self.changes.len());
  943        let next = if direction == Direction::Prev {
  944            prev.saturating_sub(count)
  945        } else {
  946            (prev + count).min(self.changes.len() - 1)
  947        };
  948        self.position = Some(next);
  949        self.changes.get(next).map(|change| change.locations())
  950    }
  951
  952    /// Adds a new change to the list, resetting the change list position.
  953    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  954        self.position.take();
  955        if let Some(last) = self.changes.last_mut()
  956            && group
  957        {
  958            last.current = Some(new_positions)
  959        } else {
  960            self.changes.push(ChangeLocation {
  961                original: new_positions,
  962                current: None,
  963            });
  964        }
  965    }
  966
  967    pub fn last(&self) -> Option<&[Anchor]> {
  968        self.changes.last().map(|change| change.locations())
  969    }
  970
  971    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  972        self.changes.last().map(|change| change.original.as_slice())
  973    }
  974
  975    pub fn invert_last_group(&mut self) {
  976        if let Some(last) = self.changes.last_mut()
  977            && let Some(current) = last.current.as_mut()
  978        {
  979            mem::swap(&mut last.original, current);
  980        }
  981    }
  982}
  983
  984#[derive(Clone)]
  985struct InlineBlamePopoverState {
  986    scroll_handle: ScrollHandle,
  987    commit_message: Option<ParsedCommitMessage>,
  988    markdown: Entity<Markdown>,
  989}
  990
  991struct InlineBlamePopover {
  992    position: gpui::Point<Pixels>,
  993    hide_task: Option<Task<()>>,
  994    popover_bounds: Option<Bounds<Pixels>>,
  995    popover_state: InlineBlamePopoverState,
  996    keyboard_grace: bool,
  997}
  998
  999enum SelectionDragState {
 1000    /// State when no drag related activity is detected.
 1001    None,
 1002    /// State when the mouse is down on a selection that is about to be dragged.
 1003    ReadyToDrag {
 1004        selection: Selection<Anchor>,
 1005        click_position: gpui::Point<Pixels>,
 1006        mouse_down_time: Instant,
 1007    },
 1008    /// State when the mouse is dragging the selection in the editor.
 1009    Dragging {
 1010        selection: Selection<Anchor>,
 1011        drop_cursor: Selection<Anchor>,
 1012        hide_drop_cursor: bool,
 1013    },
 1014}
 1015
 1016enum ColumnarSelectionState {
 1017    FromMouse {
 1018        selection_tail: Anchor,
 1019        display_point: Option<DisplayPoint>,
 1020    },
 1021    FromSelection {
 1022        selection_tail: Anchor,
 1023    },
 1024}
 1025
 1026/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1027/// a breakpoint on them.
 1028#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1029struct PhantomBreakpointIndicator {
 1030    display_row: DisplayRow,
 1031    /// There's a small debounce between hovering over the line and showing the indicator.
 1032    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1033    is_active: bool,
 1034    collides_with_existing_breakpoint: bool,
 1035}
 1036
 1037/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1038/// in diff view mode.
 1039#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1040pub(crate) struct PhantomDiffReviewIndicator {
 1041    /// The starting anchor of the selection (or the only row if not dragging).
 1042    pub start: Anchor,
 1043    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1044    pub end: Anchor,
 1045    /// There's a small debounce between hovering over the line and showing the indicator.
 1046    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1047    pub is_active: bool,
 1048}
 1049
 1050#[derive(Clone, Debug)]
 1051pub(crate) struct DiffReviewDragState {
 1052    pub start_anchor: Anchor,
 1053    pub current_anchor: Anchor,
 1054}
 1055
 1056impl DiffReviewDragState {
 1057    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1058        let start = self.start_anchor.to_display_point(snapshot).row();
 1059        let current = self.current_anchor.to_display_point(snapshot).row();
 1060
 1061        (start..=current).sorted()
 1062    }
 1063}
 1064
 1065/// Identifies a specific hunk in the diff buffer.
 1066/// Used as a key to group comments by their location.
 1067#[derive(Clone, Debug)]
 1068pub struct DiffHunkKey {
 1069    /// The file path (relative to worktree) this hunk belongs to.
 1070    pub file_path: Arc<util::rel_path::RelPath>,
 1071    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1072    pub hunk_start_anchor: Anchor,
 1073}
 1074
 1075/// A review comment stored locally before being sent to the Agent panel.
 1076#[derive(Clone)]
 1077pub struct StoredReviewComment {
 1078    /// Unique identifier for this comment (for edit/delete operations).
 1079    pub id: usize,
 1080    /// The comment text entered by the user.
 1081    pub comment: String,
 1082    /// Anchors for the code range being reviewed.
 1083    pub range: Range<Anchor>,
 1084    /// Timestamp when the comment was created (for chronological ordering).
 1085    pub created_at: Instant,
 1086    /// Whether this comment is currently being edited inline.
 1087    pub is_editing: bool,
 1088}
 1089
 1090impl StoredReviewComment {
 1091    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1092        Self {
 1093            id,
 1094            comment,
 1095            range: anchor_range,
 1096            created_at: Instant::now(),
 1097            is_editing: false,
 1098        }
 1099    }
 1100}
 1101
 1102/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1103pub(crate) struct DiffReviewOverlay {
 1104    pub anchor_range: Range<Anchor>,
 1105    /// The block ID for the overlay.
 1106    pub block_id: CustomBlockId,
 1107    /// The editor entity for the review input.
 1108    pub prompt_editor: Entity<Editor>,
 1109    /// The hunk key this overlay belongs to.
 1110    pub hunk_key: DiffHunkKey,
 1111    /// Whether the comments section is expanded.
 1112    pub comments_expanded: bool,
 1113    /// Editors for comments currently being edited inline.
 1114    /// Key: comment ID, Value: Editor entity for inline editing.
 1115    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1116    /// Subscriptions for inline edit editors' action handlers.
 1117    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1118    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1119    /// The current user's avatar URI for display in comment rows.
 1120    pub user_avatar_uri: Option<SharedUri>,
 1121    /// Subscription to keep the action handler alive.
 1122    _subscription: Subscription,
 1123}
 1124
 1125/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1126///
 1127/// See the [module level documentation](self) for more information.
 1128pub struct Editor {
 1129    focus_handle: FocusHandle,
 1130    last_focused_descendant: Option<WeakFocusHandle>,
 1131    /// The text buffer being edited
 1132    buffer: Entity<MultiBuffer>,
 1133    /// Map of how text in the buffer should be displayed.
 1134    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1135    pub display_map: Entity<DisplayMap>,
 1136    placeholder_display_map: Option<Entity<DisplayMap>>,
 1137    pub selections: SelectionsCollection,
 1138    pub scroll_manager: ScrollManager,
 1139    /// When inline assist editors are linked, they all render cursors because
 1140    /// typing enters text into each of them, even the ones that aren't focused.
 1141    pub(crate) show_cursor_when_unfocused: bool,
 1142    columnar_selection_state: Option<ColumnarSelectionState>,
 1143    add_selections_state: Option<AddSelectionsState>,
 1144    select_next_state: Option<SelectNextState>,
 1145    select_prev_state: Option<SelectNextState>,
 1146    selection_history: SelectionHistory,
 1147    defer_selection_effects: bool,
 1148    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1149    autoclose_regions: Vec<AutocloseRegion>,
 1150    snippet_stack: InvalidationStack<SnippetState>,
 1151    select_syntax_node_history: SelectSyntaxNodeHistory,
 1152    ime_transaction: Option<TransactionId>,
 1153    pub diagnostics_max_severity: DiagnosticSeverity,
 1154    active_diagnostics: ActiveDiagnostic,
 1155    show_inline_diagnostics: bool,
 1156    inline_diagnostics_update: Task<()>,
 1157    inline_diagnostics_enabled: bool,
 1158    diagnostics_enabled: bool,
 1159    word_completions_enabled: bool,
 1160    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1161    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1162    hard_wrap: Option<usize>,
 1163    project: Option<Entity<Project>>,
 1164    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1165    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1166    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1167    blink_manager: Entity<BlinkManager>,
 1168    show_cursor_names: bool,
 1169    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1170    pub show_local_selections: bool,
 1171    mode: EditorMode,
 1172    show_breadcrumbs: bool,
 1173    show_gutter: bool,
 1174    show_scrollbars: ScrollbarAxes,
 1175    minimap_visibility: MinimapVisibility,
 1176    offset_content: bool,
 1177    disable_expand_excerpt_buttons: bool,
 1178    delegate_expand_excerpts: bool,
 1179    delegate_stage_and_restore: bool,
 1180    delegate_open_excerpts: bool,
 1181    enable_lsp_data: bool,
 1182    enable_runnables: bool,
 1183    show_line_numbers: Option<bool>,
 1184    use_relative_line_numbers: Option<bool>,
 1185    show_git_diff_gutter: Option<bool>,
 1186    show_code_actions: Option<bool>,
 1187    show_runnables: Option<bool>,
 1188    show_breakpoints: Option<bool>,
 1189    show_diff_review_button: bool,
 1190    show_wrap_guides: Option<bool>,
 1191    show_indent_guides: Option<bool>,
 1192    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1193    highlight_order: usize,
 1194    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1195    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1196    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1197    scrollbar_marker_state: ScrollbarMarkerState,
 1198    active_indent_guides_state: ActiveIndentGuidesState,
 1199    nav_history: Option<ItemNavHistory>,
 1200    context_menu: RefCell<Option<CodeContextMenu>>,
 1201    context_menu_options: Option<ContextMenuOptions>,
 1202    mouse_context_menu: Option<MouseContextMenu>,
 1203    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1204    inline_blame_popover: Option<InlineBlamePopover>,
 1205    inline_blame_popover_show_task: Option<Task<()>>,
 1206    signature_help_state: SignatureHelpState,
 1207    auto_signature_help: Option<bool>,
 1208    find_all_references_task_sources: Vec<Anchor>,
 1209    next_completion_id: CompletionId,
 1210    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1211    code_actions_task: Option<Task<Result<()>>>,
 1212    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1213    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1214    debounced_selection_highlight_complete: bool,
 1215    document_highlights_task: Option<Task<()>>,
 1216    linked_editing_range_task: Option<Task<Option<()>>>,
 1217    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1218    pending_rename: Option<RenameState>,
 1219    searchable: bool,
 1220    cursor_shape: CursorShape,
 1221    /// Whether the cursor is offset one character to the left when something is
 1222    /// selected (needed for vim visual mode)
 1223    cursor_offset_on_selection: bool,
 1224    current_line_highlight: Option<CurrentLineHighlight>,
 1225    /// Whether to collapse search match ranges to just their start position.
 1226    /// When true, navigating to a match positions the cursor at the match
 1227    /// without selecting the matched text.
 1228    collapse_matches: bool,
 1229    autoindent_mode: Option<AutoindentMode>,
 1230    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1231    input_enabled: bool,
 1232    expects_character_input: bool,
 1233    use_modal_editing: bool,
 1234    read_only: bool,
 1235    leader_id: Option<CollaboratorId>,
 1236    remote_id: Option<ViewId>,
 1237    pub hover_state: HoverState,
 1238    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1239    prev_pressure_stage: Option<PressureStage>,
 1240    gutter_hovered: bool,
 1241    hovered_link_state: Option<HoveredLinkState>,
 1242    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1243    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1244    active_edit_prediction: Option<EditPredictionState>,
 1245    /// Used to prevent flickering as the user types while the menu is open
 1246    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1247    edit_prediction_settings: EditPredictionSettings,
 1248    edit_predictions_hidden_for_vim_mode: bool,
 1249    show_edit_predictions_override: Option<bool>,
 1250    show_completions_on_input_override: Option<bool>,
 1251    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1252    edit_prediction_preview: EditPredictionPreview,
 1253    in_leading_whitespace: bool,
 1254    next_inlay_id: usize,
 1255    next_color_inlay_id: usize,
 1256    _subscriptions: Vec<Subscription>,
 1257    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1258    gutter_dimensions: GutterDimensions,
 1259    style: Option<EditorStyle>,
 1260    text_style_refinement: Option<TextStyleRefinement>,
 1261    next_editor_action_id: EditorActionId,
 1262    editor_actions: Rc<
 1263        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1264    >,
 1265    use_autoclose: bool,
 1266    use_auto_surround: bool,
 1267    auto_replace_emoji_shortcode: bool,
 1268    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1269    show_git_blame_gutter: bool,
 1270    show_git_blame_inline: bool,
 1271    show_git_blame_inline_delay_task: Option<Task<()>>,
 1272    git_blame_inline_enabled: bool,
 1273    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1274    buffer_serialization: Option<BufferSerialization>,
 1275    show_selection_menu: Option<bool>,
 1276    blame: Option<Entity<GitBlame>>,
 1277    blame_subscription: Option<Subscription>,
 1278    custom_context_menu: Option<
 1279        Box<
 1280            dyn 'static
 1281                + Fn(
 1282                    &mut Self,
 1283                    DisplayPoint,
 1284                    &mut Window,
 1285                    &mut Context<Self>,
 1286                ) -> Option<Entity<ui::ContextMenu>>,
 1287        >,
 1288    >,
 1289    last_bounds: Option<Bounds<Pixels>>,
 1290    last_position_map: Option<Rc<PositionMap>>,
 1291    expect_bounds_change: Option<Bounds<Pixels>>,
 1292    runnables: RunnableData,
 1293    breakpoint_store: Option<Entity<BreakpointStore>>,
 1294    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1295    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1296    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1297    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1298    /// when hunks have comments stored.
 1299    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1300    /// Stored review comments grouped by hunk.
 1301    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1302    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1303    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1304    /// Counter for generating unique comment IDs.
 1305    next_review_comment_id: usize,
 1306    hovered_diff_hunk_row: Option<DisplayRow>,
 1307    pull_diagnostics_task: Task<()>,
 1308    in_project_search: bool,
 1309    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1310    breadcrumb_header: Option<String>,
 1311    focused_block: Option<FocusedBlock>,
 1312    next_scroll_position: NextScrollCursorCenterTopBottom,
 1313    addons: HashMap<TypeId, Box<dyn Addon>>,
 1314    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1315    load_diff_task: Option<Shared<Task<()>>>,
 1316    /// Whether we are temporarily displaying a diff other than git's
 1317    temporary_diff_override: bool,
 1318    selection_mark_mode: bool,
 1319    toggle_fold_multiple_buffers: Task<()>,
 1320    _scroll_cursor_center_top_bottom_task: Task<()>,
 1321    serialize_selections: Task<()>,
 1322    serialize_folds: Task<()>,
 1323    mouse_cursor_hidden: bool,
 1324    minimap: Option<Entity<Self>>,
 1325    hide_mouse_mode: HideMouseMode,
 1326    pub change_list: ChangeList,
 1327    inline_value_cache: InlineValueCache,
 1328    number_deleted_lines: bool,
 1329
 1330    selection_drag_state: SelectionDragState,
 1331    colors: Option<LspColorData>,
 1332    post_scroll_update: Task<()>,
 1333    refresh_colors_task: Task<()>,
 1334    use_document_folding_ranges: bool,
 1335    refresh_folding_ranges_task: Task<()>,
 1336    inlay_hints: Option<LspInlayHintData>,
 1337    folding_newlines: Task<()>,
 1338    select_next_is_case_sensitive: Option<bool>,
 1339    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1340    on_local_selections_changed:
 1341        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1342    suppress_selection_callback: bool,
 1343    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1344    accent_data: Option<AccentData>,
 1345    bracket_fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1346    semantic_token_state: SemanticTokenState,
 1347    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1348    refresh_document_symbols_task: Shared<Task<()>>,
 1349    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1350    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1351    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1352    sticky_headers_task: Task<()>,
 1353    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1354    pub(crate) colorize_brackets_task: Task<()>,
 1355}
 1356
 1357#[derive(Debug, PartialEq)]
 1358struct AccentData {
 1359    colors: AccentColors,
 1360    overrides: Vec<SharedString>,
 1361}
 1362
 1363fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1364    if debounce_ms > 0 {
 1365        Some(Duration::from_millis(debounce_ms))
 1366    } else {
 1367        None
 1368    }
 1369}
 1370
 1371#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1372enum NextScrollCursorCenterTopBottom {
 1373    #[default]
 1374    Center,
 1375    Top,
 1376    Bottom,
 1377}
 1378
 1379impl NextScrollCursorCenterTopBottom {
 1380    fn next(&self) -> Self {
 1381        match self {
 1382            Self::Center => Self::Top,
 1383            Self::Top => Self::Bottom,
 1384            Self::Bottom => Self::Center,
 1385        }
 1386    }
 1387}
 1388
 1389#[derive(Clone)]
 1390pub struct EditorSnapshot {
 1391    pub mode: EditorMode,
 1392    show_gutter: bool,
 1393    offset_content: bool,
 1394    show_line_numbers: Option<bool>,
 1395    number_deleted_lines: bool,
 1396    show_git_diff_gutter: Option<bool>,
 1397    show_code_actions: Option<bool>,
 1398    show_runnables: Option<bool>,
 1399    show_breakpoints: Option<bool>,
 1400    git_blame_gutter_max_author_length: Option<usize>,
 1401    pub display_snapshot: DisplaySnapshot,
 1402    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1403    is_focused: bool,
 1404    scroll_anchor: SharedScrollAnchor,
 1405    ongoing_scroll: OngoingScroll,
 1406    current_line_highlight: CurrentLineHighlight,
 1407    gutter_hovered: bool,
 1408    semantic_tokens_enabled: bool,
 1409}
 1410
 1411#[derive(Default, Debug, Clone, Copy)]
 1412pub struct GutterDimensions {
 1413    pub left_padding: Pixels,
 1414    pub right_padding: Pixels,
 1415    pub width: Pixels,
 1416    pub margin: Pixels,
 1417    pub git_blame_entries_width: Option<Pixels>,
 1418}
 1419
 1420impl GutterDimensions {
 1421    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1422        Self {
 1423            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1424            ..Default::default()
 1425        }
 1426    }
 1427
 1428    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1429        -cx.text_system().descent(font_id, font_size)
 1430    }
 1431    /// The full width of the space taken up by the gutter.
 1432    pub fn full_width(&self) -> Pixels {
 1433        self.margin + self.width
 1434    }
 1435
 1436    /// The width of the space reserved for the fold indicators,
 1437    /// use alongside 'justify_end' and `gutter_width` to
 1438    /// right align content with the line numbers
 1439    pub fn fold_area_width(&self) -> Pixels {
 1440        self.margin + self.right_padding
 1441    }
 1442}
 1443
 1444struct CharacterDimensions {
 1445    em_width: Pixels,
 1446    em_advance: Pixels,
 1447    line_height: Pixels,
 1448}
 1449
 1450#[derive(Debug)]
 1451pub struct RemoteSelection {
 1452    pub replica_id: ReplicaId,
 1453    pub selection: Selection<Anchor>,
 1454    pub cursor_shape: CursorShape,
 1455    pub collaborator_id: CollaboratorId,
 1456    pub line_mode: bool,
 1457    pub user_name: Option<SharedString>,
 1458    pub color: PlayerColor,
 1459}
 1460
 1461#[derive(Clone, Debug)]
 1462struct SelectionHistoryEntry {
 1463    selections: Arc<[Selection<Anchor>]>,
 1464    select_next_state: Option<SelectNextState>,
 1465    select_prev_state: Option<SelectNextState>,
 1466    add_selections_state: Option<AddSelectionsState>,
 1467}
 1468
 1469#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1470enum SelectionHistoryMode {
 1471    #[default]
 1472    Normal,
 1473    Undoing,
 1474    Redoing,
 1475    Skipping,
 1476}
 1477
 1478#[derive(Clone, PartialEq, Eq, Hash)]
 1479struct HoveredCursor {
 1480    replica_id: ReplicaId,
 1481    selection_id: usize,
 1482}
 1483
 1484#[derive(Debug)]
 1485/// SelectionEffects controls the side-effects of updating the selection.
 1486///
 1487/// The default behaviour does "what you mostly want":
 1488/// - it pushes to the nav history if the cursor moved by >10 lines
 1489/// - it re-triggers completion requests
 1490/// - it scrolls to fit
 1491///
 1492/// You might want to modify these behaviours. For example when doing a "jump"
 1493/// like go to definition, we always want to add to nav history; but when scrolling
 1494/// in vim mode we never do.
 1495///
 1496/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1497/// move.
 1498#[derive(Clone)]
 1499pub struct SelectionEffects {
 1500    nav_history: Option<bool>,
 1501    completions: bool,
 1502    scroll: Option<Autoscroll>,
 1503}
 1504
 1505impl Default for SelectionEffects {
 1506    fn default() -> Self {
 1507        Self {
 1508            nav_history: None,
 1509            completions: true,
 1510            scroll: Some(Autoscroll::fit()),
 1511        }
 1512    }
 1513}
 1514impl SelectionEffects {
 1515    pub fn scroll(scroll: Autoscroll) -> Self {
 1516        Self {
 1517            scroll: Some(scroll),
 1518            ..Default::default()
 1519        }
 1520    }
 1521
 1522    pub fn no_scroll() -> Self {
 1523        Self {
 1524            scroll: None,
 1525            ..Default::default()
 1526        }
 1527    }
 1528
 1529    pub fn completions(self, completions: bool) -> Self {
 1530        Self {
 1531            completions,
 1532            ..self
 1533        }
 1534    }
 1535
 1536    pub fn nav_history(self, nav_history: bool) -> Self {
 1537        Self {
 1538            nav_history: Some(nav_history),
 1539            ..self
 1540        }
 1541    }
 1542}
 1543
 1544struct DeferredSelectionEffectsState {
 1545    changed: bool,
 1546    effects: SelectionEffects,
 1547    old_cursor_position: Anchor,
 1548    history_entry: SelectionHistoryEntry,
 1549}
 1550
 1551#[derive(Default)]
 1552struct SelectionHistory {
 1553    #[allow(clippy::type_complexity)]
 1554    selections_by_transaction:
 1555        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1556    mode: SelectionHistoryMode,
 1557    undo_stack: VecDeque<SelectionHistoryEntry>,
 1558    redo_stack: VecDeque<SelectionHistoryEntry>,
 1559}
 1560
 1561impl SelectionHistory {
 1562    #[track_caller]
 1563    fn insert_transaction(
 1564        &mut self,
 1565        transaction_id: TransactionId,
 1566        selections: Arc<[Selection<Anchor>]>,
 1567    ) {
 1568        if selections.is_empty() {
 1569            log::error!(
 1570                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1571                std::panic::Location::caller()
 1572            );
 1573            return;
 1574        }
 1575        self.selections_by_transaction
 1576            .insert(transaction_id, (selections, None));
 1577    }
 1578
 1579    #[allow(clippy::type_complexity)]
 1580    fn transaction(
 1581        &self,
 1582        transaction_id: TransactionId,
 1583    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1584        self.selections_by_transaction.get(&transaction_id)
 1585    }
 1586
 1587    #[allow(clippy::type_complexity)]
 1588    fn transaction_mut(
 1589        &mut self,
 1590        transaction_id: TransactionId,
 1591    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1592        self.selections_by_transaction.get_mut(&transaction_id)
 1593    }
 1594
 1595    fn push(&mut self, entry: SelectionHistoryEntry) {
 1596        if !entry.selections.is_empty() {
 1597            match self.mode {
 1598                SelectionHistoryMode::Normal => {
 1599                    self.push_undo(entry);
 1600                    self.redo_stack.clear();
 1601                }
 1602                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1603                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1604                SelectionHistoryMode::Skipping => {}
 1605            }
 1606        }
 1607    }
 1608
 1609    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1610        if self
 1611            .undo_stack
 1612            .back()
 1613            .is_none_or(|e| e.selections != entry.selections)
 1614        {
 1615            self.undo_stack.push_back(entry);
 1616            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1617                self.undo_stack.pop_front();
 1618            }
 1619        }
 1620    }
 1621
 1622    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1623        if self
 1624            .redo_stack
 1625            .back()
 1626            .is_none_or(|e| e.selections != entry.selections)
 1627        {
 1628            self.redo_stack.push_back(entry);
 1629            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1630                self.redo_stack.pop_front();
 1631            }
 1632        }
 1633    }
 1634}
 1635
 1636#[derive(Clone, Copy)]
 1637pub struct RowHighlightOptions {
 1638    pub autoscroll: bool,
 1639    pub include_gutter: bool,
 1640}
 1641
 1642impl Default for RowHighlightOptions {
 1643    fn default() -> Self {
 1644        Self {
 1645            autoscroll: Default::default(),
 1646            include_gutter: true,
 1647        }
 1648    }
 1649}
 1650
 1651struct RowHighlight {
 1652    index: usize,
 1653    range: Range<Anchor>,
 1654    color: Hsla,
 1655    options: RowHighlightOptions,
 1656    type_id: TypeId,
 1657}
 1658
 1659#[derive(Clone, Debug)]
 1660struct AddSelectionsState {
 1661    groups: Vec<AddSelectionsGroup>,
 1662}
 1663
 1664#[derive(Clone, Debug)]
 1665struct AddSelectionsGroup {
 1666    above: bool,
 1667    stack: Vec<usize>,
 1668}
 1669
 1670#[derive(Clone)]
 1671struct SelectNextState {
 1672    query: AhoCorasick,
 1673    wordwise: bool,
 1674    done: bool,
 1675}
 1676
 1677impl std::fmt::Debug for SelectNextState {
 1678    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1679        f.debug_struct(std::any::type_name::<Self>())
 1680            .field("wordwise", &self.wordwise)
 1681            .field("done", &self.done)
 1682            .finish()
 1683    }
 1684}
 1685
 1686#[derive(Debug)]
 1687struct AutocloseRegion {
 1688    selection_id: usize,
 1689    range: Range<Anchor>,
 1690    pair: BracketPair,
 1691}
 1692
 1693#[derive(Debug)]
 1694struct SnippetState {
 1695    ranges: Vec<Vec<Range<Anchor>>>,
 1696    active_index: usize,
 1697    choices: Vec<Option<Vec<String>>>,
 1698}
 1699
 1700#[doc(hidden)]
 1701pub struct RenameState {
 1702    pub range: Range<Anchor>,
 1703    pub old_name: Arc<str>,
 1704    pub editor: Entity<Editor>,
 1705    block_id: CustomBlockId,
 1706}
 1707
 1708struct InvalidationStack<T>(Vec<T>);
 1709
 1710struct RegisteredEditPredictionDelegate {
 1711    provider: Arc<dyn EditPredictionDelegateHandle>,
 1712    _subscription: Subscription,
 1713}
 1714
 1715#[derive(Debug, PartialEq, Eq)]
 1716pub struct ActiveDiagnosticGroup {
 1717    pub active_range: Range<Anchor>,
 1718    pub active_message: String,
 1719    pub group_id: usize,
 1720    pub blocks: HashSet<CustomBlockId>,
 1721}
 1722
 1723#[derive(Debug, PartialEq, Eq)]
 1724
 1725pub(crate) enum ActiveDiagnostic {
 1726    None,
 1727    All,
 1728    Group(ActiveDiagnosticGroup),
 1729}
 1730
 1731#[derive(Serialize, Deserialize, Clone, Debug)]
 1732pub struct ClipboardSelection {
 1733    /// The number of bytes in this selection.
 1734    pub len: usize,
 1735    /// Whether this was a full-line selection.
 1736    pub is_entire_line: bool,
 1737    /// The indentation of the first line when this content was originally copied.
 1738    pub first_line_indent: u32,
 1739    #[serde(default)]
 1740    pub file_path: Option<PathBuf>,
 1741    #[serde(default)]
 1742    pub line_range: Option<RangeInclusive<u32>>,
 1743}
 1744
 1745impl ClipboardSelection {
 1746    pub fn for_buffer(
 1747        len: usize,
 1748        is_entire_line: bool,
 1749        range: Range<Point>,
 1750        buffer: &MultiBufferSnapshot,
 1751        project: Option<&Entity<Project>>,
 1752        cx: &App,
 1753    ) -> Self {
 1754        let first_line_indent = buffer
 1755            .indent_size_for_line(MultiBufferRow(range.start.row))
 1756            .len;
 1757
 1758        let file_path = util::maybe!({
 1759            let project = project?.read(cx);
 1760            let file = buffer.file_at(range.start)?;
 1761            let project_path = ProjectPath {
 1762                worktree_id: file.worktree_id(cx),
 1763                path: file.path().clone(),
 1764            };
 1765            project.absolute_path(&project_path, cx)
 1766        });
 1767
 1768        let line_range = file_path.as_ref().and_then(|_| {
 1769            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1770            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1771            if start_excerpt_id == end_excerpt_id {
 1772                Some(start_point.row..=end_point.row)
 1773            } else {
 1774                None
 1775            }
 1776        });
 1777
 1778        Self {
 1779            len,
 1780            is_entire_line,
 1781            first_line_indent,
 1782            file_path,
 1783            line_range,
 1784        }
 1785    }
 1786}
 1787
 1788// selections, scroll behavior, was newest selection reversed
 1789type SelectSyntaxNodeHistoryState = (
 1790    Box<[Selection<Anchor>]>,
 1791    SelectSyntaxNodeScrollBehavior,
 1792    bool,
 1793);
 1794
 1795#[derive(Default)]
 1796struct SelectSyntaxNodeHistory {
 1797    stack: Vec<SelectSyntaxNodeHistoryState>,
 1798    // disable temporarily to allow changing selections without losing the stack
 1799    pub disable_clearing: bool,
 1800}
 1801
 1802impl SelectSyntaxNodeHistory {
 1803    pub fn try_clear(&mut self) {
 1804        if !self.disable_clearing {
 1805            self.stack.clear();
 1806        }
 1807    }
 1808
 1809    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1810        self.stack.push(selection);
 1811    }
 1812
 1813    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1814        self.stack.pop()
 1815    }
 1816}
 1817
 1818enum SelectSyntaxNodeScrollBehavior {
 1819    CursorTop,
 1820    FitSelection,
 1821    CursorBottom,
 1822}
 1823
 1824#[derive(Debug, Clone, Copy)]
 1825pub(crate) struct NavigationData {
 1826    cursor_anchor: Anchor,
 1827    cursor_position: Point,
 1828    scroll_anchor: ScrollAnchor,
 1829    scroll_top_row: u32,
 1830}
 1831
 1832#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1833pub enum GotoDefinitionKind {
 1834    Symbol,
 1835    Declaration,
 1836    Type,
 1837    Implementation,
 1838}
 1839
 1840pub enum FormatTarget {
 1841    Buffers(HashSet<Entity<Buffer>>),
 1842    Ranges(Vec<Range<MultiBufferPoint>>),
 1843}
 1844
 1845pub(crate) struct FocusedBlock {
 1846    id: BlockId,
 1847    focus_handle: WeakFocusHandle,
 1848}
 1849
 1850#[derive(Clone, Debug)]
 1851pub enum JumpData {
 1852    MultiBufferRow {
 1853        row: MultiBufferRow,
 1854        line_offset_from_top: u32,
 1855    },
 1856    MultiBufferPoint {
 1857        excerpt_id: ExcerptId,
 1858        position: Point,
 1859        anchor: text::Anchor,
 1860        line_offset_from_top: u32,
 1861    },
 1862}
 1863
 1864pub enum MultibufferSelectionMode {
 1865    First,
 1866    All,
 1867}
 1868
 1869#[derive(Clone, Copy, Debug, Default)]
 1870pub struct RewrapOptions {
 1871    pub override_language_settings: bool,
 1872    pub preserve_existing_whitespace: bool,
 1873    pub line_length: Option<usize>,
 1874}
 1875
 1876impl Editor {
 1877    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1878        let buffer = cx.new(|cx| Buffer::local("", cx));
 1879        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1880        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1881    }
 1882
 1883    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1884        let buffer = cx.new(|cx| Buffer::local("", cx));
 1885        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1886        Self::new(EditorMode::full(), buffer, None, window, cx)
 1887    }
 1888
 1889    pub fn auto_height(
 1890        min_lines: usize,
 1891        max_lines: usize,
 1892        window: &mut Window,
 1893        cx: &mut Context<Self>,
 1894    ) -> Self {
 1895        let buffer = cx.new(|cx| Buffer::local("", cx));
 1896        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1897        Self::new(
 1898            EditorMode::AutoHeight {
 1899                min_lines,
 1900                max_lines: Some(max_lines),
 1901            },
 1902            buffer,
 1903            None,
 1904            window,
 1905            cx,
 1906        )
 1907    }
 1908
 1909    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1910    /// The editor grows as tall as needed to fit its content.
 1911    pub fn auto_height_unbounded(
 1912        min_lines: usize,
 1913        window: &mut Window,
 1914        cx: &mut Context<Self>,
 1915    ) -> Self {
 1916        let buffer = cx.new(|cx| Buffer::local("", cx));
 1917        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1918        Self::new(
 1919            EditorMode::AutoHeight {
 1920                min_lines,
 1921                max_lines: None,
 1922            },
 1923            buffer,
 1924            None,
 1925            window,
 1926            cx,
 1927        )
 1928    }
 1929
 1930    pub fn for_buffer(
 1931        buffer: Entity<Buffer>,
 1932        project: Option<Entity<Project>>,
 1933        window: &mut Window,
 1934        cx: &mut Context<Self>,
 1935    ) -> Self {
 1936        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1937        Self::new(EditorMode::full(), buffer, project, window, cx)
 1938    }
 1939
 1940    pub fn for_multibuffer(
 1941        buffer: Entity<MultiBuffer>,
 1942        project: Option<Entity<Project>>,
 1943        window: &mut Window,
 1944        cx: &mut Context<Self>,
 1945    ) -> Self {
 1946        Self::new(EditorMode::full(), buffer, project, window, cx)
 1947    }
 1948
 1949    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1950        let mut clone = Self::new(
 1951            self.mode.clone(),
 1952            self.buffer.clone(),
 1953            self.project.clone(),
 1954            window,
 1955            cx,
 1956        );
 1957        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1958            let snapshot = display_map.snapshot(cx);
 1959            clone.display_map.update(cx, |display_map, cx| {
 1960                display_map.set_state(&snapshot, cx);
 1961            });
 1962            snapshot
 1963        });
 1964        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1965        clone.folds_did_change(cx);
 1966        clone.selections.clone_state(&self.selections);
 1967        clone
 1968            .scroll_manager
 1969            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1970        clone.searchable = self.searchable;
 1971        clone.read_only = self.read_only;
 1972        clone.buffers_with_disabled_indent_guides =
 1973            self.buffers_with_disabled_indent_guides.clone();
 1974        clone
 1975    }
 1976
 1977    pub fn new(
 1978        mode: EditorMode,
 1979        buffer: Entity<MultiBuffer>,
 1980        project: Option<Entity<Project>>,
 1981        window: &mut Window,
 1982        cx: &mut Context<Self>,
 1983    ) -> Self {
 1984        Editor::new_internal(mode, buffer, project, None, window, cx)
 1985    }
 1986
 1987    pub fn refresh_sticky_headers(
 1988        &mut self,
 1989        display_snapshot: &DisplaySnapshot,
 1990        cx: &mut Context<Editor>,
 1991    ) {
 1992        if !self.mode.is_full() {
 1993            return;
 1994        }
 1995        let multi_buffer = display_snapshot.buffer_snapshot();
 1996        let scroll_anchor = self
 1997            .scroll_manager
 1998            .native_anchor(display_snapshot, cx)
 1999            .anchor;
 2000        let Some((excerpt_id, _, buffer)) = multi_buffer.as_singleton() else {
 2001            return;
 2002        };
 2003        let buffer = buffer.clone();
 2004
 2005        let buffer_visible_start = scroll_anchor.text_anchor.to_point(&buffer);
 2006        let max_row = buffer.max_point().row;
 2007        let start_row = buffer_visible_start.row.min(max_row);
 2008        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2009
 2010        let syntax = self.style(cx).syntax.clone();
 2011        let background_task = cx.background_spawn(async move {
 2012            buffer
 2013                .outline_items_containing(
 2014                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2015                    true,
 2016                    Some(syntax.as_ref()),
 2017                )
 2018                .into_iter()
 2019                .map(|outline_item| OutlineItem {
 2020                    depth: outline_item.depth,
 2021                    range: Anchor::range_in_buffer(excerpt_id, outline_item.range),
 2022                    source_range_for_text: Anchor::range_in_buffer(
 2023                        excerpt_id,
 2024                        outline_item.source_range_for_text,
 2025                    ),
 2026                    text: outline_item.text,
 2027                    highlight_ranges: outline_item.highlight_ranges,
 2028                    name_ranges: outline_item.name_ranges,
 2029                    body_range: outline_item
 2030                        .body_range
 2031                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2032                    annotation_range: outline_item
 2033                        .annotation_range
 2034                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2035                })
 2036                .collect()
 2037        });
 2038        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2039            let sticky_headers = background_task.await;
 2040            this.update(cx, |this, cx| {
 2041                this.sticky_headers = Some(sticky_headers);
 2042                cx.notify();
 2043            })
 2044            .ok();
 2045        });
 2046    }
 2047
 2048    fn new_internal(
 2049        mode: EditorMode,
 2050        multi_buffer: Entity<MultiBuffer>,
 2051        project: Option<Entity<Project>>,
 2052        display_map: Option<Entity<DisplayMap>>,
 2053        window: &mut Window,
 2054        cx: &mut Context<Self>,
 2055    ) -> Self {
 2056        debug_assert!(
 2057            display_map.is_none() || mode.is_minimap(),
 2058            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2059        );
 2060
 2061        let full_mode = mode.is_full();
 2062        let is_minimap = mode.is_minimap();
 2063        let diagnostics_max_severity = if full_mode {
 2064            EditorSettings::get_global(cx)
 2065                .diagnostics_max_severity
 2066                .unwrap_or(DiagnosticSeverity::Hint)
 2067        } else {
 2068            DiagnosticSeverity::Off
 2069        };
 2070        let style = window.text_style();
 2071        let font_size = style.font_size.to_pixels(window.rem_size());
 2072        let editor = cx.entity().downgrade();
 2073        let fold_placeholder = FoldPlaceholder {
 2074            constrain_width: false,
 2075            render: Arc::new(move |fold_id, fold_range, cx| {
 2076                let editor = editor.clone();
 2077                FoldPlaceholder::fold_element(fold_id, cx)
 2078                    .cursor_pointer()
 2079                    .child("")
 2080                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2081                    .on_click(move |_, _window, cx| {
 2082                        editor
 2083                            .update(cx, |editor, cx| {
 2084                                editor.unfold_ranges(
 2085                                    &[fold_range.start..fold_range.end],
 2086                                    true,
 2087                                    false,
 2088                                    cx,
 2089                                );
 2090                                cx.stop_propagation();
 2091                            })
 2092                            .ok();
 2093                    })
 2094                    .into_any()
 2095            }),
 2096            merge_adjacent: true,
 2097            ..FoldPlaceholder::default()
 2098        };
 2099        let display_map = display_map.unwrap_or_else(|| {
 2100            cx.new(|cx| {
 2101                DisplayMap::new(
 2102                    multi_buffer.clone(),
 2103                    style.font(),
 2104                    font_size,
 2105                    None,
 2106                    FILE_HEADER_HEIGHT,
 2107                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2108                    fold_placeholder,
 2109                    diagnostics_max_severity,
 2110                    cx,
 2111                )
 2112            })
 2113        });
 2114
 2115        let selections = SelectionsCollection::new();
 2116
 2117        let blink_manager = cx.new(|cx| {
 2118            let mut blink_manager = BlinkManager::new(
 2119                CURSOR_BLINK_INTERVAL,
 2120                |cx| EditorSettings::get_global(cx).cursor_blink,
 2121                cx,
 2122            );
 2123            if is_minimap {
 2124                blink_manager.disable(cx);
 2125            }
 2126            blink_manager
 2127        });
 2128
 2129        let soft_wrap_mode_override =
 2130            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2131
 2132        let mut project_subscriptions = Vec::new();
 2133        if full_mode && let Some(project) = project.as_ref() {
 2134            project_subscriptions.push(cx.subscribe_in(
 2135                project,
 2136                window,
 2137                |editor, _, event, window, cx| match event {
 2138                    project::Event::RefreshCodeLens => {
 2139                        // we always query lens with actions, without storing them, always refreshing them
 2140                    }
 2141                    project::Event::RefreshInlayHints {
 2142                        server_id,
 2143                        request_id,
 2144                    } => {
 2145                        editor.refresh_inlay_hints(
 2146                            InlayHintRefreshReason::RefreshRequested {
 2147                                server_id: *server_id,
 2148                                request_id: *request_id,
 2149                            },
 2150                            cx,
 2151                        );
 2152                    }
 2153                    project::Event::RefreshSemanticTokens {
 2154                        server_id,
 2155                        request_id,
 2156                    } => {
 2157                        editor.refresh_semantic_tokens(
 2158                            None,
 2159                            Some(RefreshForServer {
 2160                                server_id: *server_id,
 2161                                request_id: *request_id,
 2162                            }),
 2163                            cx,
 2164                        );
 2165                    }
 2166                    project::Event::LanguageServerRemoved(_) => {
 2167                        editor.registered_buffers.clear();
 2168                        editor.register_visible_buffers(cx);
 2169                        editor.invalidate_semantic_tokens(None);
 2170                        editor.refresh_runnables(None, window, cx);
 2171                        editor.update_lsp_data(None, window, cx);
 2172                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2173                    }
 2174                    project::Event::SnippetEdit(id, snippet_edits) => {
 2175                        // todo(lw): Non singletons
 2176                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2177                            let snapshot = buffer.read(cx).snapshot();
 2178                            let focus_handle = editor.focus_handle(cx);
 2179                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2180                                for (range, snippet) in snippet_edits {
 2181                                    let buffer_range =
 2182                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2183                                    editor
 2184                                        .insert_snippet(
 2185                                            &[MultiBufferOffset(buffer_range.start)
 2186                                                ..MultiBufferOffset(buffer_range.end)],
 2187                                            snippet.clone(),
 2188                                            window,
 2189                                            cx,
 2190                                        )
 2191                                        .ok();
 2192                                }
 2193                            }
 2194                        }
 2195                    }
 2196                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2197                        let buffer_id = *buffer_id;
 2198                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2199                            editor.register_buffer(buffer_id, cx);
 2200                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2201                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2202                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2203                            refresh_linked_ranges(editor, window, cx);
 2204                            editor.refresh_code_actions(window, cx);
 2205                            editor.refresh_document_highlights(cx);
 2206                        }
 2207                    }
 2208
 2209                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2210                        let Some(workspace) = editor.workspace() else {
 2211                            return;
 2212                        };
 2213                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2214                        else {
 2215                            return;
 2216                        };
 2217
 2218                        if active_editor.entity_id() == cx.entity_id() {
 2219                            let entity_id = cx.entity_id();
 2220                            workspace.update(cx, |this, cx| {
 2221                                this.panes_mut()
 2222                                    .iter_mut()
 2223                                    .filter(|pane| pane.entity_id() != entity_id)
 2224                                    .for_each(|p| {
 2225                                        p.update(cx, |pane, _| {
 2226                                            pane.nav_history_mut().rename_item(
 2227                                                entity_id,
 2228                                                project_path.clone(),
 2229                                                abs_path.clone().into(),
 2230                                            );
 2231                                        })
 2232                                    });
 2233                            });
 2234
 2235                            Self::open_transaction_for_hidden_buffers(
 2236                                workspace,
 2237                                transaction.clone(),
 2238                                "Rename".to_string(),
 2239                                window,
 2240                                cx,
 2241                            );
 2242                        }
 2243                    }
 2244
 2245                    project::Event::WorkspaceEditApplied(transaction) => {
 2246                        let Some(workspace) = editor.workspace() else {
 2247                            return;
 2248                        };
 2249                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2250                        else {
 2251                            return;
 2252                        };
 2253
 2254                        if active_editor.entity_id() == cx.entity_id() {
 2255                            Self::open_transaction_for_hidden_buffers(
 2256                                workspace,
 2257                                transaction.clone(),
 2258                                "LSP Edit".to_string(),
 2259                                window,
 2260                                cx,
 2261                            );
 2262                        }
 2263                    }
 2264
 2265                    _ => {}
 2266                },
 2267            ));
 2268            if let Some(task_inventory) = project
 2269                .read(cx)
 2270                .task_store()
 2271                .read(cx)
 2272                .task_inventory()
 2273                .cloned()
 2274            {
 2275                project_subscriptions.push(cx.observe_in(
 2276                    &task_inventory,
 2277                    window,
 2278                    |editor, _, window, cx| {
 2279                        editor.refresh_runnables(None, window, cx);
 2280                    },
 2281                ));
 2282            };
 2283
 2284            project_subscriptions.push(cx.subscribe_in(
 2285                &project.read(cx).breakpoint_store(),
 2286                window,
 2287                |editor, _, event, window, cx| match event {
 2288                    BreakpointStoreEvent::ClearDebugLines => {
 2289                        editor.clear_row_highlights::<ActiveDebugLine>();
 2290                        editor.refresh_inline_values(cx);
 2291                    }
 2292                    BreakpointStoreEvent::SetDebugLine => {
 2293                        if editor.go_to_active_debug_line(window, cx) {
 2294                            cx.stop_propagation();
 2295                        }
 2296
 2297                        editor.refresh_inline_values(cx);
 2298                    }
 2299                    _ => {}
 2300                },
 2301            ));
 2302            let git_store = project.read(cx).git_store().clone();
 2303            let project = project.clone();
 2304            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2305                if let GitStoreEvent::RepositoryAdded = event {
 2306                    this.load_diff_task = Some(
 2307                        update_uncommitted_diff_for_buffer(
 2308                            cx.entity(),
 2309                            &project,
 2310                            this.buffer.read(cx).all_buffers(),
 2311                            this.buffer.clone(),
 2312                            cx,
 2313                        )
 2314                        .shared(),
 2315                    );
 2316                }
 2317            }));
 2318        }
 2319
 2320        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2321
 2322        let inlay_hint_settings =
 2323            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2324        let focus_handle = cx.focus_handle();
 2325        if !is_minimap {
 2326            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2327                .detach();
 2328            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2329                .detach();
 2330            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2331                .detach();
 2332            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2333                .detach();
 2334            cx.observe_pending_input(window, Self::observe_pending_input)
 2335                .detach();
 2336        }
 2337
 2338        let show_indent_guides =
 2339            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2340                Some(false)
 2341            } else {
 2342                None
 2343            };
 2344
 2345        let breakpoint_store = match (&mode, project.as_ref()) {
 2346            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2347            _ => None,
 2348        };
 2349
 2350        let mut code_action_providers = Vec::new();
 2351        let mut load_uncommitted_diff = None;
 2352        if let Some(project) = project.clone() {
 2353            load_uncommitted_diff = Some(
 2354                update_uncommitted_diff_for_buffer(
 2355                    cx.entity(),
 2356                    &project,
 2357                    multi_buffer.read(cx).all_buffers(),
 2358                    multi_buffer.clone(),
 2359                    cx,
 2360                )
 2361                .shared(),
 2362            );
 2363            code_action_providers.push(Rc::new(project) as Rc<_>);
 2364        }
 2365
 2366        let mut editor = Self {
 2367            focus_handle,
 2368            show_cursor_when_unfocused: false,
 2369            last_focused_descendant: None,
 2370            buffer: multi_buffer.clone(),
 2371            display_map: display_map.clone(),
 2372            placeholder_display_map: None,
 2373            selections,
 2374            scroll_manager: ScrollManager::new(cx),
 2375            columnar_selection_state: None,
 2376            add_selections_state: None,
 2377            select_next_state: None,
 2378            select_prev_state: None,
 2379            selection_history: SelectionHistory::default(),
 2380            defer_selection_effects: false,
 2381            deferred_selection_effects_state: None,
 2382            autoclose_regions: Vec::new(),
 2383            snippet_stack: InvalidationStack::default(),
 2384            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2385            ime_transaction: None,
 2386            active_diagnostics: ActiveDiagnostic::None,
 2387            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2388            inline_diagnostics_update: Task::ready(()),
 2389            inline_diagnostics: Vec::new(),
 2390            soft_wrap_mode_override,
 2391            diagnostics_max_severity,
 2392            hard_wrap: None,
 2393            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2394            semantics_provider: project
 2395                .as_ref()
 2396                .map(|project| Rc::new(project.downgrade()) as _),
 2397            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2398            project,
 2399            blink_manager: blink_manager.clone(),
 2400            show_local_selections: true,
 2401            show_scrollbars: ScrollbarAxes {
 2402                horizontal: full_mode,
 2403                vertical: full_mode,
 2404            },
 2405            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2406            offset_content: !matches!(mode, EditorMode::SingleLine),
 2407            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2408            show_gutter: full_mode,
 2409            show_line_numbers: (!full_mode).then_some(false),
 2410            use_relative_line_numbers: None,
 2411            disable_expand_excerpt_buttons: !full_mode,
 2412            delegate_expand_excerpts: false,
 2413            delegate_stage_and_restore: false,
 2414            delegate_open_excerpts: false,
 2415            enable_lsp_data: true,
 2416            enable_runnables: true,
 2417            show_git_diff_gutter: None,
 2418            show_code_actions: None,
 2419            show_runnables: None,
 2420            show_breakpoints: None,
 2421            show_diff_review_button: false,
 2422            show_wrap_guides: None,
 2423            show_indent_guides,
 2424            buffers_with_disabled_indent_guides: HashSet::default(),
 2425            highlight_order: 0,
 2426            highlighted_rows: HashMap::default(),
 2427            background_highlights: HashMap::default(),
 2428            gutter_highlights: HashMap::default(),
 2429            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2430            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2431            nav_history: None,
 2432            context_menu: RefCell::new(None),
 2433            context_menu_options: None,
 2434            mouse_context_menu: None,
 2435            completion_tasks: Vec::new(),
 2436            inline_blame_popover: None,
 2437            inline_blame_popover_show_task: None,
 2438            signature_help_state: SignatureHelpState::default(),
 2439            auto_signature_help: None,
 2440            find_all_references_task_sources: Vec::new(),
 2441            next_completion_id: 0,
 2442            next_inlay_id: 0,
 2443            code_action_providers,
 2444            available_code_actions: None,
 2445            code_actions_task: None,
 2446            quick_selection_highlight_task: None,
 2447            debounced_selection_highlight_task: None,
 2448            debounced_selection_highlight_complete: false,
 2449            document_highlights_task: None,
 2450            linked_editing_range_task: None,
 2451            pending_rename: None,
 2452            searchable: !is_minimap,
 2453            cursor_shape: EditorSettings::get_global(cx)
 2454                .cursor_shape
 2455                .unwrap_or_default(),
 2456            cursor_offset_on_selection: false,
 2457            current_line_highlight: None,
 2458            autoindent_mode: Some(AutoindentMode::EachLine),
 2459            collapse_matches: false,
 2460            workspace: None,
 2461            input_enabled: !is_minimap,
 2462            expects_character_input: !is_minimap,
 2463            use_modal_editing: full_mode,
 2464            read_only: is_minimap,
 2465            use_autoclose: true,
 2466            use_auto_surround: true,
 2467            auto_replace_emoji_shortcode: false,
 2468            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2469            leader_id: None,
 2470            remote_id: None,
 2471            hover_state: HoverState::default(),
 2472            pending_mouse_down: None,
 2473            prev_pressure_stage: None,
 2474            hovered_link_state: None,
 2475            edit_prediction_provider: None,
 2476            active_edit_prediction: None,
 2477            stale_edit_prediction_in_menu: None,
 2478            edit_prediction_preview: EditPredictionPreview::Inactive {
 2479                released_too_fast: false,
 2480            },
 2481            inline_diagnostics_enabled: full_mode,
 2482            diagnostics_enabled: full_mode,
 2483            word_completions_enabled: full_mode,
 2484            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2485            gutter_hovered: false,
 2486            pixel_position_of_newest_cursor: None,
 2487            last_bounds: None,
 2488            last_position_map: None,
 2489            expect_bounds_change: None,
 2490            gutter_dimensions: GutterDimensions::default(),
 2491            style: None,
 2492            show_cursor_names: false,
 2493            hovered_cursors: HashMap::default(),
 2494            next_editor_action_id: EditorActionId::default(),
 2495            editor_actions: Rc::default(),
 2496            edit_predictions_hidden_for_vim_mode: false,
 2497            show_edit_predictions_override: None,
 2498            show_completions_on_input_override: None,
 2499            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2500            edit_prediction_settings: EditPredictionSettings::Disabled,
 2501            in_leading_whitespace: false,
 2502            custom_context_menu: None,
 2503            show_git_blame_gutter: false,
 2504            show_git_blame_inline: false,
 2505            show_selection_menu: None,
 2506            show_git_blame_inline_delay_task: None,
 2507            git_blame_inline_enabled: full_mode
 2508                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2509            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2510            buffer_serialization: is_minimap.not().then(|| {
 2511                BufferSerialization::new(
 2512                    ProjectSettings::get_global(cx)
 2513                        .session
 2514                        .restore_unsaved_buffers,
 2515                )
 2516            }),
 2517            blame: None,
 2518            blame_subscription: None,
 2519
 2520            breakpoint_store,
 2521            gutter_breakpoint_indicator: (None, None),
 2522            gutter_diff_review_indicator: (None, None),
 2523            diff_review_drag_state: None,
 2524            diff_review_overlays: Vec::new(),
 2525            stored_review_comments: Vec::new(),
 2526            next_review_comment_id: 0,
 2527            hovered_diff_hunk_row: None,
 2528            _subscriptions: (!is_minimap)
 2529                .then(|| {
 2530                    vec![
 2531                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2532                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2533                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2534                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2535                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2536                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2537                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2538                        cx.observe_window_activation(window, |editor, window, cx| {
 2539                            let active = window.is_window_active();
 2540                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2541                                if active {
 2542                                    blink_manager.enable(cx);
 2543                                } else {
 2544                                    blink_manager.disable(cx);
 2545                                }
 2546                            });
 2547                            if active {
 2548                                editor.show_mouse_cursor(cx);
 2549                            }
 2550                        }),
 2551                    ]
 2552                })
 2553                .unwrap_or_default(),
 2554            runnables: RunnableData::new(),
 2555            pull_diagnostics_task: Task::ready(()),
 2556            colors: None,
 2557            refresh_colors_task: Task::ready(()),
 2558            use_document_folding_ranges: false,
 2559            refresh_folding_ranges_task: Task::ready(()),
 2560            inlay_hints: None,
 2561            next_color_inlay_id: 0,
 2562            post_scroll_update: Task::ready(()),
 2563            linked_edit_ranges: Default::default(),
 2564            in_project_search: false,
 2565            previous_search_ranges: None,
 2566            breadcrumb_header: None,
 2567            focused_block: None,
 2568            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2569            addons: HashMap::default(),
 2570            registered_buffers: HashMap::default(),
 2571            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2572            selection_mark_mode: false,
 2573            toggle_fold_multiple_buffers: Task::ready(()),
 2574            serialize_selections: Task::ready(()),
 2575            serialize_folds: Task::ready(()),
 2576            text_style_refinement: None,
 2577            load_diff_task: load_uncommitted_diff,
 2578            temporary_diff_override: false,
 2579            mouse_cursor_hidden: false,
 2580            minimap: None,
 2581            hide_mouse_mode: EditorSettings::get_global(cx)
 2582                .hide_mouse
 2583                .unwrap_or_default(),
 2584            change_list: ChangeList::new(),
 2585            mode,
 2586            selection_drag_state: SelectionDragState::None,
 2587            folding_newlines: Task::ready(()),
 2588            lookup_key: None,
 2589            select_next_is_case_sensitive: None,
 2590            on_local_selections_changed: None,
 2591            suppress_selection_callback: false,
 2592            applicable_language_settings: HashMap::default(),
 2593            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2594            accent_data: None,
 2595            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2596            number_deleted_lines: false,
 2597            refresh_matching_bracket_highlights_task: Task::ready(()),
 2598            refresh_document_symbols_task: Task::ready(()).shared(),
 2599            lsp_document_symbols: HashMap::default(),
 2600            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2601            outline_symbols_at_cursor: None,
 2602            sticky_headers_task: Task::ready(()),
 2603            sticky_headers: None,
 2604            colorize_brackets_task: Task::ready(()),
 2605        };
 2606
 2607        if is_minimap {
 2608            return editor;
 2609        }
 2610
 2611        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2612        editor.accent_data = editor.fetch_accent_data(cx);
 2613
 2614        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2615            editor
 2616                ._subscriptions
 2617                .push(cx.observe(breakpoints, |_, _, cx| {
 2618                    cx.notify();
 2619                }));
 2620        }
 2621        editor._subscriptions.extend(project_subscriptions);
 2622
 2623        editor._subscriptions.push(cx.subscribe_in(
 2624            &cx.entity(),
 2625            window,
 2626            |editor, _, e: &EditorEvent, window, cx| match e {
 2627                EditorEvent::ScrollPositionChanged { local, .. } => {
 2628                    if *local {
 2629                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2630                        editor.inline_blame_popover.take();
 2631                        let snapshot = editor.snapshot(window, cx);
 2632                        let new_anchor = editor
 2633                            .scroll_manager
 2634                            .native_anchor(&snapshot.display_snapshot, cx);
 2635                        editor.update_restoration_data(cx, move |data| {
 2636                            data.scroll_position = (
 2637                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2638                                new_anchor.offset,
 2639                            );
 2640                        });
 2641
 2642                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2643                            cx.background_executor()
 2644                                .timer(Duration::from_millis(50))
 2645                                .await;
 2646                            editor
 2647                                .update_in(cx, |editor, window, cx| {
 2648                                    editor.update_data_on_scroll(window, cx)
 2649                                })
 2650                                .ok();
 2651                        });
 2652                    }
 2653                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2654                }
 2655                EditorEvent::Edited { .. } => {
 2656                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2657                        .map(|vim_mode| vim_mode.0)
 2658                        .unwrap_or(false);
 2659                    if !vim_mode {
 2660                        let display_map = editor.display_snapshot(cx);
 2661                        let selections = editor.selections.all_adjusted_display(&display_map);
 2662                        let pop_state = editor
 2663                            .change_list
 2664                            .last()
 2665                            .map(|previous| {
 2666                                previous.len() == selections.len()
 2667                                    && previous.iter().enumerate().all(|(ix, p)| {
 2668                                        p.to_display_point(&display_map).row()
 2669                                            == selections[ix].head().row()
 2670                                    })
 2671                            })
 2672                            .unwrap_or(false);
 2673                        let new_positions = selections
 2674                            .into_iter()
 2675                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2676                            .collect();
 2677                        editor
 2678                            .change_list
 2679                            .push_to_change_list(pop_state, new_positions);
 2680                    }
 2681                }
 2682                _ => (),
 2683            },
 2684        ));
 2685
 2686        if let Some(dap_store) = editor
 2687            .project
 2688            .as_ref()
 2689            .map(|project| project.read(cx).dap_store())
 2690        {
 2691            let weak_editor = cx.weak_entity();
 2692
 2693            editor
 2694                ._subscriptions
 2695                .push(
 2696                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2697                        let session_entity = cx.entity();
 2698                        weak_editor
 2699                            .update(cx, |editor, cx| {
 2700                                editor._subscriptions.push(
 2701                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2702                                );
 2703                            })
 2704                            .ok();
 2705                    }),
 2706                );
 2707
 2708            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2709                editor
 2710                    ._subscriptions
 2711                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2712            }
 2713        }
 2714
 2715        // skip adding the initial selection to selection history
 2716        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2717        editor.end_selection(window, cx);
 2718        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2719
 2720        editor.scroll_manager.show_scrollbars(window, cx);
 2721        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2722
 2723        if full_mode {
 2724            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2725            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2726
 2727            if editor.git_blame_inline_enabled {
 2728                editor.start_git_blame_inline(false, window, cx);
 2729            }
 2730
 2731            editor.go_to_active_debug_line(window, cx);
 2732
 2733            editor.minimap =
 2734                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2735            editor.colors = Some(LspColorData::new(cx));
 2736            editor.use_document_folding_ranges = true;
 2737            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2738
 2739            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2740                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2741            }
 2742            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2743        }
 2744
 2745        editor
 2746    }
 2747
 2748    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2749        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2750    }
 2751
 2752    pub fn deploy_mouse_context_menu(
 2753        &mut self,
 2754        position: gpui::Point<Pixels>,
 2755        context_menu: Entity<ContextMenu>,
 2756        window: &mut Window,
 2757        cx: &mut Context<Self>,
 2758    ) {
 2759        self.mouse_context_menu = Some(MouseContextMenu::new(
 2760            self,
 2761            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2762            context_menu,
 2763            window,
 2764            cx,
 2765        ));
 2766    }
 2767
 2768    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2769        self.mouse_context_menu
 2770            .as_ref()
 2771            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2772    }
 2773
 2774    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2775        if self
 2776            .selections
 2777            .pending_anchor()
 2778            .is_some_and(|pending_selection| {
 2779                let snapshot = self.buffer().read(cx).snapshot(cx);
 2780                pending_selection.range().includes(range, &snapshot)
 2781            })
 2782        {
 2783            return true;
 2784        }
 2785
 2786        self.selections
 2787            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2788            .into_iter()
 2789            .any(|selection| {
 2790                // This is needed to cover a corner case, if we just check for an existing
 2791                // selection in the fold range, having a cursor at the start of the fold
 2792                // marks it as selected. Non-empty selections don't cause this.
 2793                let length = selection.end - selection.start;
 2794                length > 0
 2795            })
 2796    }
 2797
 2798    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2799        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2800    }
 2801
 2802    fn key_context_internal(
 2803        &self,
 2804        has_active_edit_prediction: bool,
 2805        window: &mut Window,
 2806        cx: &mut App,
 2807    ) -> KeyContext {
 2808        let mut key_context = KeyContext::new_with_defaults();
 2809        key_context.add("Editor");
 2810        let mode = match self.mode {
 2811            EditorMode::SingleLine => "single_line",
 2812            EditorMode::AutoHeight { .. } => "auto_height",
 2813            EditorMode::Minimap { .. } => "minimap",
 2814            EditorMode::Full { .. } => "full",
 2815        };
 2816
 2817        if EditorSettings::jupyter_enabled(cx) {
 2818            key_context.add("jupyter");
 2819        }
 2820
 2821        key_context.set("mode", mode);
 2822        if self.pending_rename.is_some() {
 2823            key_context.add("renaming");
 2824        }
 2825
 2826        if let Some(snippet_stack) = self.snippet_stack.last() {
 2827            key_context.add("in_snippet");
 2828
 2829            if snippet_stack.active_index > 0 {
 2830                key_context.add("has_previous_tabstop");
 2831            }
 2832
 2833            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2834                key_context.add("has_next_tabstop");
 2835            }
 2836        }
 2837
 2838        match self.context_menu.borrow().as_ref() {
 2839            Some(CodeContextMenu::Completions(menu)) => {
 2840                if menu.visible() {
 2841                    key_context.add("menu");
 2842                    key_context.add("showing_completions");
 2843                }
 2844            }
 2845            Some(CodeContextMenu::CodeActions(menu)) => {
 2846                if menu.visible() {
 2847                    key_context.add("menu");
 2848                    key_context.add("showing_code_actions")
 2849                }
 2850            }
 2851            None => {}
 2852        }
 2853
 2854        if self.signature_help_state.has_multiple_signatures() {
 2855            key_context.add("showing_signature_help");
 2856        }
 2857
 2858        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2859        if !self.focus_handle(cx).contains_focused(window, cx)
 2860            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2861        {
 2862            for addon in self.addons.values() {
 2863                addon.extend_key_context(&mut key_context, cx)
 2864            }
 2865        }
 2866
 2867        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2868            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2869                Some(
 2870                    file.full_path(cx)
 2871                        .extension()?
 2872                        .to_string_lossy()
 2873                        .to_lowercase(),
 2874                )
 2875            }) {
 2876                key_context.set("extension", extension);
 2877            }
 2878        } else {
 2879            key_context.add("multibuffer");
 2880        }
 2881
 2882        if has_active_edit_prediction {
 2883            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2884            key_context.add("copilot_suggestion");
 2885        }
 2886
 2887        if self.in_leading_whitespace {
 2888            key_context.add("in_leading_whitespace");
 2889        }
 2890        if self.edit_prediction_requires_modifier() {
 2891            key_context.set("edit_prediction_mode", "subtle")
 2892        } else {
 2893            key_context.set("edit_prediction_mode", "eager");
 2894        }
 2895
 2896        if self.selection_mark_mode {
 2897            key_context.add("selection_mode");
 2898        }
 2899
 2900        let disjoint = self.selections.disjoint_anchors();
 2901        if matches!(
 2902            &self.mode,
 2903            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2904        ) && let [selection] = disjoint
 2905            && selection.start == selection.end
 2906        {
 2907            let snapshot = self.snapshot(window, cx);
 2908            let snapshot = snapshot.buffer_snapshot();
 2909            let caret_offset = selection.end.to_offset(snapshot);
 2910
 2911            if caret_offset == MultiBufferOffset(0) {
 2912                key_context.add("start_of_input");
 2913            }
 2914
 2915            if caret_offset == snapshot.len() {
 2916                key_context.add("end_of_input");
 2917            }
 2918        }
 2919
 2920        if self.has_any_expanded_diff_hunks(cx) {
 2921            key_context.add("diffs_expanded");
 2922        }
 2923
 2924        key_context
 2925    }
 2926
 2927    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2928        self.last_bounds.as_ref()
 2929    }
 2930
 2931    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2932        if self.mouse_cursor_hidden {
 2933            self.mouse_cursor_hidden = false;
 2934            cx.notify();
 2935        }
 2936    }
 2937
 2938    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2939        let hide_mouse_cursor = match origin {
 2940            HideMouseCursorOrigin::TypingAction => {
 2941                matches!(
 2942                    self.hide_mouse_mode,
 2943                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2944                )
 2945            }
 2946            HideMouseCursorOrigin::MovementAction => {
 2947                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2948            }
 2949        };
 2950        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2951            self.mouse_cursor_hidden = hide_mouse_cursor;
 2952            cx.notify();
 2953        }
 2954    }
 2955
 2956    fn accept_edit_prediction_keystroke(
 2957        &self,
 2958        granularity: EditPredictionGranularity,
 2959        window: &mut Window,
 2960        cx: &mut App,
 2961    ) -> Option<gpui::KeybindingKeystroke> {
 2962        let key_context = self.key_context_internal(true, window, cx);
 2963
 2964        let bindings =
 2965            match granularity {
 2966                EditPredictionGranularity::Word => window
 2967                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2968                EditPredictionGranularity::Line => window
 2969                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2970                EditPredictionGranularity::Full => {
 2971                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2972                }
 2973            };
 2974
 2975        bindings
 2976            .into_iter()
 2977            .rev()
 2978            .find_map(|binding| match binding.keystrokes() {
 2979                [keystroke, ..] => Some(keystroke.clone()),
 2980                _ => None,
 2981            })
 2982    }
 2983
 2984    fn preview_edit_prediction_keystroke(
 2985        &self,
 2986        window: &mut Window,
 2987        cx: &mut App,
 2988    ) -> Option<gpui::KeybindingKeystroke> {
 2989        let key_context = self.key_context_internal(true, window, cx);
 2990        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 2991        bindings
 2992            .into_iter()
 2993            .rev()
 2994            .find_map(|binding| match binding.keystrokes() {
 2995                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 2996                _ => None,
 2997            })
 2998    }
 2999
 3000    fn edit_prediction_preview_modifiers_held(
 3001        &self,
 3002        modifiers: &Modifiers,
 3003        window: &mut Window,
 3004        cx: &mut App,
 3005    ) -> bool {
 3006        let key_context = self.key_context_internal(true, window, cx);
 3007        let actions: [&dyn Action; 3] = [
 3008            &AcceptEditPrediction,
 3009            &AcceptNextWordEditPrediction,
 3010            &AcceptNextLineEditPrediction,
 3011        ];
 3012
 3013        actions.into_iter().any(|action| {
 3014            window
 3015                .bindings_for_action_in_context(action, key_context.clone())
 3016                .into_iter()
 3017                .rev()
 3018                .any(|binding| {
 3019                    binding.keystrokes().first().is_some_and(|keystroke| {
 3020                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3021                    })
 3022                })
 3023        })
 3024    }
 3025
 3026    fn edit_prediction_cursor_popover_prefers_preview(
 3027        &self,
 3028        completion: &EditPredictionState,
 3029    ) -> bool {
 3030        match &completion.completion {
 3031            EditPrediction::Edit {
 3032                edits, snapshot, ..
 3033            } => {
 3034                let mut start_row: Option<u32> = None;
 3035                let mut end_row: Option<u32> = None;
 3036
 3037                for (range, text) in edits {
 3038                    let edit_start_row = range.start.text_anchor.to_point(snapshot).row;
 3039                    let old_end_row = range.end.text_anchor.to_point(snapshot).row;
 3040                    let inserted_newline_count = text
 3041                        .as_ref()
 3042                        .chars()
 3043                        .filter(|character| *character == '\n')
 3044                        .count() as u32;
 3045                    let deleted_newline_count = old_end_row - edit_start_row;
 3046                    let preview_end_row = edit_start_row + inserted_newline_count;
 3047
 3048                    start_row =
 3049                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3050                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3051
 3052                    if deleted_newline_count > 1 {
 3053                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3054                    }
 3055                }
 3056
 3057                start_row
 3058                    .zip(end_row)
 3059                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3060            }
 3061            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3062        }
 3063    }
 3064
 3065    fn edit_prediction_keybind_display(
 3066        &self,
 3067        surface: EditPredictionKeybindSurface,
 3068        window: &mut Window,
 3069        cx: &mut App,
 3070    ) -> EditPredictionKeybindDisplay {
 3071        let accept_keystroke =
 3072            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3073        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3074
 3075        let action = match surface {
 3076            EditPredictionKeybindSurface::Inline
 3077            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3078                if self.edit_prediction_requires_modifier() {
 3079                    EditPredictionKeybindAction::Preview
 3080                } else {
 3081                    EditPredictionKeybindAction::Accept
 3082                }
 3083            }
 3084            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3085                .active_edit_prediction
 3086                .as_ref()
 3087                .filter(|completion| {
 3088                    self.edit_prediction_cursor_popover_prefers_preview(completion)
 3089                })
 3090                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3091                    EditPredictionKeybindAction::Preview
 3092                }),
 3093        };
 3094        #[cfg(test)]
 3095        let preview_copy = preview_keystroke.clone();
 3096        #[cfg(test)]
 3097        let accept_copy = accept_keystroke.clone();
 3098
 3099        let displayed_keystroke = match surface {
 3100            EditPredictionKeybindSurface::Inline => match action {
 3101                EditPredictionKeybindAction::Accept => accept_keystroke,
 3102                EditPredictionKeybindAction::Preview => preview_keystroke,
 3103            },
 3104            EditPredictionKeybindSurface::CursorPopoverCompact
 3105            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3106                EditPredictionKeybindAction::Accept => accept_keystroke,
 3107                EditPredictionKeybindAction::Preview => {
 3108                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3109                }
 3110            },
 3111        };
 3112
 3113        let missing_accept_keystroke = displayed_keystroke.is_none();
 3114
 3115        EditPredictionKeybindDisplay {
 3116            #[cfg(test)]
 3117            accept_keystroke: accept_copy,
 3118            #[cfg(test)]
 3119            preview_keystroke: preview_copy,
 3120            displayed_keystroke,
 3121            action,
 3122            missing_accept_keystroke,
 3123            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3124                && self.edit_prediction_preview.released_too_fast(),
 3125        }
 3126    }
 3127
 3128    pub fn new_file(
 3129        workspace: &mut Workspace,
 3130        _: &workspace::NewFile,
 3131        window: &mut Window,
 3132        cx: &mut Context<Workspace>,
 3133    ) {
 3134        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3135            "Failed to create buffer",
 3136            window,
 3137            cx,
 3138            |e, _, _| match e.error_code() {
 3139                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3140                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3141                e.error_tag("required").unwrap_or("the latest version")
 3142            )),
 3143                _ => None,
 3144            },
 3145        );
 3146    }
 3147
 3148    pub fn new_in_workspace(
 3149        workspace: &mut Workspace,
 3150        window: &mut Window,
 3151        cx: &mut Context<Workspace>,
 3152    ) -> Task<Result<Entity<Editor>>> {
 3153        let project = workspace.project().clone();
 3154        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3155
 3156        cx.spawn_in(window, async move |workspace, cx| {
 3157            let buffer = create.await?;
 3158            workspace.update_in(cx, |workspace, window, cx| {
 3159                let editor =
 3160                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3161                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3162                editor
 3163            })
 3164        })
 3165    }
 3166
 3167    fn new_file_vertical(
 3168        workspace: &mut Workspace,
 3169        _: &workspace::NewFileSplitVertical,
 3170        window: &mut Window,
 3171        cx: &mut Context<Workspace>,
 3172    ) {
 3173        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3174    }
 3175
 3176    fn new_file_horizontal(
 3177        workspace: &mut Workspace,
 3178        _: &workspace::NewFileSplitHorizontal,
 3179        window: &mut Window,
 3180        cx: &mut Context<Workspace>,
 3181    ) {
 3182        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3183    }
 3184
 3185    fn new_file_split(
 3186        workspace: &mut Workspace,
 3187        action: &workspace::NewFileSplit,
 3188        window: &mut Window,
 3189        cx: &mut Context<Workspace>,
 3190    ) {
 3191        Self::new_file_in_direction(workspace, action.0, window, cx)
 3192    }
 3193
 3194    fn new_file_in_direction(
 3195        workspace: &mut Workspace,
 3196        direction: SplitDirection,
 3197        window: &mut Window,
 3198        cx: &mut Context<Workspace>,
 3199    ) {
 3200        let project = workspace.project().clone();
 3201        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3202
 3203        cx.spawn_in(window, async move |workspace, cx| {
 3204            let buffer = create.await?;
 3205            workspace.update_in(cx, move |workspace, window, cx| {
 3206                workspace.split_item(
 3207                    direction,
 3208                    Box::new(
 3209                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3210                    ),
 3211                    window,
 3212                    cx,
 3213                )
 3214            })?;
 3215            anyhow::Ok(())
 3216        })
 3217        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3218            match e.error_code() {
 3219                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3220                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3221                e.error_tag("required").unwrap_or("the latest version")
 3222            )),
 3223                _ => None,
 3224            }
 3225        });
 3226    }
 3227
 3228    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3229        self.leader_id
 3230    }
 3231
 3232    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3233        &self.buffer
 3234    }
 3235
 3236    pub fn project(&self) -> Option<&Entity<Project>> {
 3237        self.project.as_ref()
 3238    }
 3239
 3240    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3241        self.workspace.as_ref()?.0.upgrade()
 3242    }
 3243
 3244    /// Detaches a task and shows an error notification in the workspace if available,
 3245    /// otherwise just logs the error.
 3246    pub fn detach_and_notify_err<R, E>(
 3247        &self,
 3248        task: Task<Result<R, E>>,
 3249        window: &mut Window,
 3250        cx: &mut App,
 3251    ) where
 3252        E: std::fmt::Debug + std::fmt::Display + 'static,
 3253        R: 'static,
 3254    {
 3255        if let Some(workspace) = self.workspace() {
 3256            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3257        } else {
 3258            task.detach_and_log_err(cx);
 3259        }
 3260    }
 3261
 3262    /// Returns the workspace serialization ID if this editor should be serialized.
 3263    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3264        self.workspace
 3265            .as_ref()
 3266            .filter(|_| self.should_serialize_buffer())
 3267            .and_then(|workspace| workspace.1)
 3268    }
 3269
 3270    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3271        self.buffer().read(cx).title(cx)
 3272    }
 3273
 3274    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3275        let git_blame_gutter_max_author_length = self
 3276            .render_git_blame_gutter(cx)
 3277            .then(|| {
 3278                if let Some(blame) = self.blame.as_ref() {
 3279                    let max_author_length =
 3280                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3281                    Some(max_author_length)
 3282                } else {
 3283                    None
 3284                }
 3285            })
 3286            .flatten();
 3287
 3288        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3289
 3290        EditorSnapshot {
 3291            mode: self.mode.clone(),
 3292            show_gutter: self.show_gutter,
 3293            offset_content: self.offset_content,
 3294            show_line_numbers: self.show_line_numbers,
 3295            number_deleted_lines: self.number_deleted_lines,
 3296            show_git_diff_gutter: self.show_git_diff_gutter,
 3297            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3298            show_code_actions: self.show_code_actions,
 3299            show_runnables: self.show_runnables,
 3300            show_breakpoints: self.show_breakpoints,
 3301            git_blame_gutter_max_author_length,
 3302            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3303            display_snapshot,
 3304            placeholder_display_snapshot: self
 3305                .placeholder_display_map
 3306                .as_ref()
 3307                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3308            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3309            is_focused: self.focus_handle.is_focused(window),
 3310            current_line_highlight: self
 3311                .current_line_highlight
 3312                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3313            gutter_hovered: self.gutter_hovered,
 3314        }
 3315    }
 3316
 3317    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3318        self.buffer.read(cx).language_at(point, cx)
 3319    }
 3320
 3321    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3322        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3323    }
 3324
 3325    pub fn active_excerpt(
 3326        &self,
 3327        cx: &App,
 3328    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3329        self.buffer
 3330            .read(cx)
 3331            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3332    }
 3333
 3334    pub fn mode(&self) -> &EditorMode {
 3335        &self.mode
 3336    }
 3337
 3338    pub fn set_mode(&mut self, mode: EditorMode) {
 3339        self.mode = mode;
 3340    }
 3341
 3342    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3343        self.collaboration_hub.as_deref()
 3344    }
 3345
 3346    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3347        self.collaboration_hub = Some(hub);
 3348    }
 3349
 3350    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3351        self.in_project_search = in_project_search;
 3352    }
 3353
 3354    pub fn set_custom_context_menu(
 3355        &mut self,
 3356        f: impl 'static
 3357        + Fn(
 3358            &mut Self,
 3359            DisplayPoint,
 3360            &mut Window,
 3361            &mut Context<Self>,
 3362        ) -> Option<Entity<ui::ContextMenu>>,
 3363    ) {
 3364        self.custom_context_menu = Some(Box::new(f))
 3365    }
 3366
 3367    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3368        self.completion_provider = provider;
 3369    }
 3370
 3371    #[cfg(any(test, feature = "test-support"))]
 3372    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3373        self.completion_provider.clone()
 3374    }
 3375
 3376    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3377        self.semantics_provider.clone()
 3378    }
 3379
 3380    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3381        self.semantics_provider = provider;
 3382    }
 3383
 3384    pub fn set_edit_prediction_provider<T>(
 3385        &mut self,
 3386        provider: Option<Entity<T>>,
 3387        window: &mut Window,
 3388        cx: &mut Context<Self>,
 3389    ) where
 3390        T: EditPredictionDelegate,
 3391    {
 3392        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3393            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3394                if this.focus_handle.is_focused(window) {
 3395                    this.update_visible_edit_prediction(window, cx);
 3396                }
 3397            }),
 3398            provider: Arc::new(provider),
 3399        });
 3400        self.update_edit_prediction_settings(cx);
 3401        self.refresh_edit_prediction(false, false, window, cx);
 3402    }
 3403
 3404    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3405        self.placeholder_display_map
 3406            .as_ref()
 3407            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3408    }
 3409
 3410    pub fn set_placeholder_text(
 3411        &mut self,
 3412        placeholder_text: &str,
 3413        window: &mut Window,
 3414        cx: &mut Context<Self>,
 3415    ) {
 3416        let multibuffer = cx
 3417            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3418
 3419        let style = window.text_style();
 3420
 3421        self.placeholder_display_map = Some(cx.new(|cx| {
 3422            DisplayMap::new(
 3423                multibuffer,
 3424                style.font(),
 3425                style.font_size.to_pixels(window.rem_size()),
 3426                None,
 3427                FILE_HEADER_HEIGHT,
 3428                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3429                Default::default(),
 3430                DiagnosticSeverity::Off,
 3431                cx,
 3432            )
 3433        }));
 3434        cx.notify();
 3435    }
 3436
 3437    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3438        self.cursor_shape = cursor_shape;
 3439
 3440        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3441        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3442
 3443        cx.notify();
 3444    }
 3445
 3446    pub fn cursor_shape(&self) -> CursorShape {
 3447        self.cursor_shape
 3448    }
 3449
 3450    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3451        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3452    }
 3453
 3454    pub fn set_current_line_highlight(
 3455        &mut self,
 3456        current_line_highlight: Option<CurrentLineHighlight>,
 3457    ) {
 3458        self.current_line_highlight = current_line_highlight;
 3459    }
 3460
 3461    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3462        self.collapse_matches = collapse_matches;
 3463    }
 3464
 3465    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3466        if self.collapse_matches {
 3467            return range.start..range.start;
 3468        }
 3469        range.clone()
 3470    }
 3471
 3472    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3473        self.display_map.read(cx).clip_at_line_ends
 3474    }
 3475
 3476    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3477        if self.display_map.read(cx).clip_at_line_ends != clip {
 3478            self.display_map
 3479                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3480        }
 3481    }
 3482
 3483    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3484        self.input_enabled = input_enabled;
 3485    }
 3486
 3487    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3488        self.expects_character_input = expects_character_input;
 3489    }
 3490
 3491    pub fn set_edit_predictions_hidden_for_vim_mode(
 3492        &mut self,
 3493        hidden: bool,
 3494        window: &mut Window,
 3495        cx: &mut Context<Self>,
 3496    ) {
 3497        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3498            self.edit_predictions_hidden_for_vim_mode = hidden;
 3499            if hidden {
 3500                self.update_visible_edit_prediction(window, cx);
 3501            } else {
 3502                self.refresh_edit_prediction(true, false, window, cx);
 3503            }
 3504        }
 3505    }
 3506
 3507    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3508        self.menu_edit_predictions_policy = value;
 3509    }
 3510
 3511    pub fn set_autoindent(&mut self, autoindent: bool) {
 3512        if autoindent {
 3513            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3514        } else {
 3515            self.autoindent_mode = None;
 3516        }
 3517    }
 3518
 3519    pub fn capability(&self, cx: &App) -> Capability {
 3520        if self.read_only {
 3521            Capability::ReadOnly
 3522        } else {
 3523            self.buffer.read(cx).capability()
 3524        }
 3525    }
 3526
 3527    pub fn read_only(&self, cx: &App) -> bool {
 3528        self.read_only || self.buffer.read(cx).read_only()
 3529    }
 3530
 3531    pub fn set_read_only(&mut self, read_only: bool) {
 3532        self.read_only = read_only;
 3533    }
 3534
 3535    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3536        self.use_autoclose = autoclose;
 3537    }
 3538
 3539    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3540        self.use_auto_surround = auto_surround;
 3541    }
 3542
 3543    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3544        self.auto_replace_emoji_shortcode = auto_replace;
 3545    }
 3546
 3547    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3548        self.buffer_serialization = should_serialize.then(|| {
 3549            BufferSerialization::new(
 3550                ProjectSettings::get_global(cx)
 3551                    .session
 3552                    .restore_unsaved_buffers,
 3553            )
 3554        })
 3555    }
 3556
 3557    fn should_serialize_buffer(&self) -> bool {
 3558        self.buffer_serialization.is_some()
 3559    }
 3560
 3561    pub fn toggle_edit_predictions(
 3562        &mut self,
 3563        _: &ToggleEditPrediction,
 3564        window: &mut Window,
 3565        cx: &mut Context<Self>,
 3566    ) {
 3567        if self.show_edit_predictions_override.is_some() {
 3568            self.set_show_edit_predictions(None, window, cx);
 3569        } else {
 3570            let show_edit_predictions = !self.edit_predictions_enabled();
 3571            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3572        }
 3573    }
 3574
 3575    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3576        self.show_completions_on_input_override = show_completions_on_input;
 3577    }
 3578
 3579    pub fn set_show_edit_predictions(
 3580        &mut self,
 3581        show_edit_predictions: Option<bool>,
 3582        window: &mut Window,
 3583        cx: &mut Context<Self>,
 3584    ) {
 3585        self.show_edit_predictions_override = show_edit_predictions;
 3586        self.update_edit_prediction_settings(cx);
 3587
 3588        if let Some(false) = show_edit_predictions {
 3589            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3590        } else {
 3591            self.refresh_edit_prediction(false, true, window, cx);
 3592        }
 3593    }
 3594
 3595    fn edit_predictions_disabled_in_scope(
 3596        &self,
 3597        buffer: &Entity<Buffer>,
 3598        buffer_position: language::Anchor,
 3599        cx: &App,
 3600    ) -> bool {
 3601        let snapshot = buffer.read(cx).snapshot();
 3602        let settings = snapshot.settings_at(buffer_position, cx);
 3603
 3604        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3605            return false;
 3606        };
 3607
 3608        scope.override_name().is_some_and(|scope_name| {
 3609            settings
 3610                .edit_predictions_disabled_in
 3611                .iter()
 3612                .any(|s| s == scope_name)
 3613        })
 3614    }
 3615
 3616    pub fn set_use_modal_editing(&mut self, to: bool) {
 3617        self.use_modal_editing = to;
 3618    }
 3619
 3620    pub fn use_modal_editing(&self) -> bool {
 3621        self.use_modal_editing
 3622    }
 3623
 3624    fn selections_did_change(
 3625        &mut self,
 3626        local: bool,
 3627        old_cursor_position: &Anchor,
 3628        effects: SelectionEffects,
 3629        window: &mut Window,
 3630        cx: &mut Context<Self>,
 3631    ) {
 3632        window.invalidate_character_coordinates();
 3633
 3634        // Copy selections to primary selection buffer
 3635        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3636        if local {
 3637            let selections = self
 3638                .selections
 3639                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3640            let buffer_handle = self.buffer.read(cx).read(cx);
 3641
 3642            let mut text = String::new();
 3643            for (index, selection) in selections.iter().enumerate() {
 3644                let text_for_selection = buffer_handle
 3645                    .text_for_range(selection.start..selection.end)
 3646                    .collect::<String>();
 3647
 3648                text.push_str(&text_for_selection);
 3649                if index != selections.len() - 1 {
 3650                    text.push('\n');
 3651                }
 3652            }
 3653
 3654            if !text.is_empty() {
 3655                cx.write_to_primary(ClipboardItem::new_string(text));
 3656            }
 3657        }
 3658
 3659        let selection_anchors = self.selections.disjoint_anchors_arc();
 3660
 3661        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3662            self.buffer.update(cx, |buffer, cx| {
 3663                buffer.set_active_selections(
 3664                    &selection_anchors,
 3665                    self.selections.line_mode(),
 3666                    self.cursor_shape,
 3667                    cx,
 3668                )
 3669            });
 3670        }
 3671        let display_map = self
 3672            .display_map
 3673            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3674        let buffer = display_map.buffer_snapshot();
 3675        if self.selections.count() == 1 {
 3676            self.add_selections_state = None;
 3677        }
 3678        self.select_next_state = None;
 3679        self.select_prev_state = None;
 3680        self.select_syntax_node_history.try_clear();
 3681        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3682        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3683        self.take_rename(false, window, cx);
 3684
 3685        let newest_selection = self.selections.newest_anchor();
 3686        let new_cursor_position = newest_selection.head();
 3687        let selection_start = newest_selection.start;
 3688
 3689        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3690            self.push_to_nav_history(
 3691                *old_cursor_position,
 3692                Some(new_cursor_position.to_point(buffer)),
 3693                false,
 3694                effects.nav_history == Some(true),
 3695                cx,
 3696            );
 3697        }
 3698
 3699        if local {
 3700            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3701                self.register_buffer(buffer_id, cx);
 3702            }
 3703
 3704            let mut context_menu = self.context_menu.borrow_mut();
 3705            let completion_menu = match context_menu.as_ref() {
 3706                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3707                Some(CodeContextMenu::CodeActions(_)) => {
 3708                    *context_menu = None;
 3709                    None
 3710                }
 3711                None => None,
 3712            };
 3713            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3714            drop(context_menu);
 3715
 3716            if effects.completions
 3717                && let Some(completion_position) = completion_position
 3718            {
 3719                let start_offset = selection_start.to_offset(buffer);
 3720                let position_matches = start_offset == completion_position.to_offset(buffer);
 3721                let continue_showing = if let Some((snap, ..)) =
 3722                    buffer.point_to_buffer_offset(completion_position)
 3723                    && !snap.capability.editable()
 3724                {
 3725                    false
 3726                } else if position_matches {
 3727                    if self.snippet_stack.is_empty() {
 3728                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3729                            == Some(CharKind::Word)
 3730                    } else {
 3731                        // Snippet choices can be shown even when the cursor is in whitespace.
 3732                        // Dismissing the menu with actions like backspace is handled by
 3733                        // invalidation regions.
 3734                        true
 3735                    }
 3736                } else {
 3737                    false
 3738                };
 3739
 3740                if continue_showing {
 3741                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3742                } else {
 3743                    self.hide_context_menu(window, cx);
 3744                }
 3745            }
 3746
 3747            hide_hover(self, cx);
 3748
 3749            if old_cursor_position.to_display_point(&display_map).row()
 3750                != new_cursor_position.to_display_point(&display_map).row()
 3751            {
 3752                self.available_code_actions.take();
 3753            }
 3754            self.refresh_code_actions(window, cx);
 3755            self.refresh_document_highlights(cx);
 3756            refresh_linked_ranges(self, window, cx);
 3757
 3758            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3759            self.refresh_matching_bracket_highlights(&display_map, cx);
 3760            self.refresh_outline_symbols_at_cursor(cx);
 3761            self.update_visible_edit_prediction(window, cx);
 3762            self.inline_blame_popover.take();
 3763            if self.git_blame_inline_enabled {
 3764                self.start_inline_blame_timer(window, cx);
 3765            }
 3766        }
 3767
 3768        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3769
 3770        if local && !self.suppress_selection_callback {
 3771            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3772                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3773                callback(cursor_position, window, cx);
 3774            }
 3775        }
 3776
 3777        cx.emit(EditorEvent::SelectionsChanged { local });
 3778
 3779        let selections = &self.selections.disjoint_anchors_arc();
 3780        if selections.len() == 1 {
 3781            cx.emit(SearchEvent::ActiveMatchChanged)
 3782        }
 3783        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3784            let inmemory_selections = selections
 3785                .iter()
 3786                .map(|s| {
 3787                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3788                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3789                })
 3790                .collect();
 3791            self.update_restoration_data(cx, |data| {
 3792                data.selections = inmemory_selections;
 3793            });
 3794
 3795            if WorkspaceSettings::get(None, cx).restore_on_startup
 3796                != RestoreOnStartupBehavior::EmptyTab
 3797                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3798            {
 3799                let snapshot = self.buffer().read(cx).snapshot(cx);
 3800                let selections = selections.clone();
 3801                let background_executor = cx.background_executor().clone();
 3802                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3803                let db = EditorDb::global(cx);
 3804                self.serialize_selections = cx.background_spawn(async move {
 3805                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3806                    let db_selections = selections
 3807                        .iter()
 3808                        .map(|selection| {
 3809                            (
 3810                                selection.start.to_offset(&snapshot).0,
 3811                                selection.end.to_offset(&snapshot).0,
 3812                            )
 3813                        })
 3814                        .collect();
 3815
 3816                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3817                        .await
 3818                        .with_context(|| {
 3819                            format!(
 3820                                "persisting editor selections for editor {editor_id}, \
 3821                                workspace {workspace_id:?}"
 3822                            )
 3823                        })
 3824                        .log_err();
 3825                });
 3826            }
 3827        }
 3828
 3829        cx.notify();
 3830    }
 3831
 3832    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3833        use text::ToOffset as _;
 3834        use text::ToPoint as _;
 3835
 3836        if self.mode.is_minimap()
 3837            || WorkspaceSettings::get(None, cx).restore_on_startup
 3838                == RestoreOnStartupBehavior::EmptyTab
 3839        {
 3840            return;
 3841        }
 3842
 3843        if !self.buffer().read(cx).is_singleton() {
 3844            return;
 3845        }
 3846
 3847        let display_snapshot = self
 3848            .display_map
 3849            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3850        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3851            return;
 3852        };
 3853        let inmemory_folds = display_snapshot
 3854            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3855            .map(|fold| {
 3856                fold.range.start.text_anchor.to_point(&snapshot)
 3857                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3858            })
 3859            .collect();
 3860        self.update_restoration_data(cx, |data| {
 3861            data.folds = inmemory_folds;
 3862        });
 3863
 3864        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3865            return;
 3866        };
 3867
 3868        // Get file path for path-based fold storage (survives tab close)
 3869        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3870            project::File::from_dyn(buffer.read(cx).file())
 3871                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3872        }) else {
 3873            return;
 3874        };
 3875
 3876        let background_executor = cx.background_executor().clone();
 3877        const FINGERPRINT_LEN: usize = 32;
 3878        let db_folds = display_snapshot
 3879            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3880            .map(|fold| {
 3881                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3882                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3883
 3884                // Extract fingerprints - content at fold boundaries for validation on restore
 3885                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3886                // content that might change independently.
 3887                // start_fp: first min(32, fold_len) bytes of fold content
 3888                // end_fp: last min(32, fold_len) bytes of fold content
 3889                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3890                let fold_len = end - start;
 3891                let start_fp_end = snapshot
 3892                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3893                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3894                let end_fp_start = snapshot
 3895                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3896                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3897
 3898                (start, end, start_fp, end_fp)
 3899            })
 3900            .collect::<Vec<_>>();
 3901        let db = EditorDb::global(cx);
 3902        self.serialize_folds = cx.background_spawn(async move {
 3903            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3904            if db_folds.is_empty() {
 3905                // No folds - delete any persisted folds for this file
 3906                db.delete_file_folds(workspace_id, file_path)
 3907                    .await
 3908                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3909                    .log_err();
 3910            } else {
 3911                db.save_file_folds(workspace_id, file_path, db_folds)
 3912                    .await
 3913                    .with_context(|| {
 3914                        format!("persisting file folds for workspace {workspace_id:?}")
 3915                    })
 3916                    .log_err();
 3917            }
 3918        });
 3919    }
 3920
 3921    pub fn sync_selections(
 3922        &mut self,
 3923        other: Entity<Editor>,
 3924        cx: &mut Context<Self>,
 3925    ) -> gpui::Subscription {
 3926        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3927        if !other_selections.is_empty() {
 3928            self.selections
 3929                .change_with(&self.display_snapshot(cx), |selections| {
 3930                    selections.select_anchors(other_selections);
 3931                });
 3932        }
 3933
 3934        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3935            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3936                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3937                if other_selections.is_empty() {
 3938                    return;
 3939                }
 3940                let snapshot = this.display_snapshot(cx);
 3941                this.selections.change_with(&snapshot, |selections| {
 3942                    selections.select_anchors(other_selections);
 3943                });
 3944            }
 3945        });
 3946
 3947        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3948            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3949                let these_selections = this.selections.disjoint_anchors().to_vec();
 3950                if these_selections.is_empty() {
 3951                    return;
 3952                }
 3953                other.update(cx, |other_editor, cx| {
 3954                    let snapshot = other_editor.display_snapshot(cx);
 3955                    other_editor
 3956                        .selections
 3957                        .change_with(&snapshot, |selections| {
 3958                            selections.select_anchors(these_selections);
 3959                        })
 3960                });
 3961            }
 3962        });
 3963
 3964        Subscription::join(other_subscription, this_subscription)
 3965    }
 3966
 3967    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3968        if self.buffer().read(cx).is_singleton() {
 3969            return;
 3970        }
 3971        let snapshot = self.buffer.read(cx).snapshot(cx);
 3972        let buffer_ids: HashSet<BufferId> = self
 3973            .selections
 3974            .disjoint_anchor_ranges()
 3975            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3976            .collect();
 3977        for buffer_id in buffer_ids {
 3978            self.unfold_buffer(buffer_id, cx);
 3979        }
 3980    }
 3981
 3982    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3983    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3984    /// effects of selection change occur at the end of the transaction.
 3985    pub fn change_selections<R>(
 3986        &mut self,
 3987        effects: SelectionEffects,
 3988        window: &mut Window,
 3989        cx: &mut Context<Self>,
 3990        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3991    ) -> R {
 3992        let snapshot = self.display_snapshot(cx);
 3993        if let Some(state) = &mut self.deferred_selection_effects_state {
 3994            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3995            state.effects.completions = effects.completions;
 3996            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3997            let (changed, result) = self.selections.change_with(&snapshot, change);
 3998            state.changed |= changed;
 3999            return result;
 4000        }
 4001        let mut state = DeferredSelectionEffectsState {
 4002            changed: false,
 4003            effects,
 4004            old_cursor_position: self.selections.newest_anchor().head(),
 4005            history_entry: SelectionHistoryEntry {
 4006                selections: self.selections.disjoint_anchors_arc(),
 4007                select_next_state: self.select_next_state.clone(),
 4008                select_prev_state: self.select_prev_state.clone(),
 4009                add_selections_state: self.add_selections_state.clone(),
 4010            },
 4011        };
 4012        let (changed, result) = self.selections.change_with(&snapshot, change);
 4013        state.changed = state.changed || changed;
 4014        if self.defer_selection_effects {
 4015            self.deferred_selection_effects_state = Some(state);
 4016        } else {
 4017            self.apply_selection_effects(state, window, cx);
 4018        }
 4019        result
 4020    }
 4021
 4022    /// Defers the effects of selection change, so that the effects of multiple calls to
 4023    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4024    /// to selection history and the state of popovers based on selection position aren't
 4025    /// erroneously updated.
 4026    pub fn with_selection_effects_deferred<R>(
 4027        &mut self,
 4028        window: &mut Window,
 4029        cx: &mut Context<Self>,
 4030        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4031    ) -> R {
 4032        let already_deferred = self.defer_selection_effects;
 4033        self.defer_selection_effects = true;
 4034        let result = update(self, window, cx);
 4035        if !already_deferred {
 4036            self.defer_selection_effects = false;
 4037            if let Some(state) = self.deferred_selection_effects_state.take() {
 4038                self.apply_selection_effects(state, window, cx);
 4039            }
 4040        }
 4041        result
 4042    }
 4043
 4044    fn apply_selection_effects(
 4045        &mut self,
 4046        state: DeferredSelectionEffectsState,
 4047        window: &mut Window,
 4048        cx: &mut Context<Self>,
 4049    ) {
 4050        if state.changed {
 4051            self.selection_history.push(state.history_entry);
 4052
 4053            if let Some(autoscroll) = state.effects.scroll {
 4054                self.request_autoscroll(autoscroll, cx);
 4055            }
 4056
 4057            let old_cursor_position = &state.old_cursor_position;
 4058
 4059            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4060
 4061            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4062                self.show_signature_help_auto(window, cx);
 4063            }
 4064        }
 4065    }
 4066
 4067    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4068    where
 4069        I: IntoIterator<Item = (Range<S>, T)>,
 4070        S: ToOffset,
 4071        T: Into<Arc<str>>,
 4072    {
 4073        if self.read_only(cx) {
 4074            return;
 4075        }
 4076
 4077        self.buffer
 4078            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4079    }
 4080
 4081    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4082    where
 4083        I: IntoIterator<Item = (Range<S>, T)>,
 4084        S: ToOffset,
 4085        T: Into<Arc<str>>,
 4086    {
 4087        if self.read_only(cx) {
 4088            return;
 4089        }
 4090
 4091        self.buffer.update(cx, |buffer, cx| {
 4092            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4093        });
 4094    }
 4095
 4096    pub fn edit_with_block_indent<I, S, T>(
 4097        &mut self,
 4098        edits: I,
 4099        original_indent_columns: Vec<Option<u32>>,
 4100        cx: &mut Context<Self>,
 4101    ) where
 4102        I: IntoIterator<Item = (Range<S>, T)>,
 4103        S: ToOffset,
 4104        T: Into<Arc<str>>,
 4105    {
 4106        if self.read_only(cx) {
 4107            return;
 4108        }
 4109
 4110        self.buffer.update(cx, |buffer, cx| {
 4111            buffer.edit(
 4112                edits,
 4113                Some(AutoindentMode::Block {
 4114                    original_indent_columns,
 4115                }),
 4116                cx,
 4117            )
 4118        });
 4119    }
 4120
 4121    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4122        self.hide_context_menu(window, cx);
 4123
 4124        match phase {
 4125            SelectPhase::Begin {
 4126                position,
 4127                add,
 4128                click_count,
 4129            } => self.begin_selection(position, add, click_count, window, cx),
 4130            SelectPhase::BeginColumnar {
 4131                position,
 4132                goal_column,
 4133                reset,
 4134                mode,
 4135            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4136            SelectPhase::Extend {
 4137                position,
 4138                click_count,
 4139            } => self.extend_selection(position, click_count, window, cx),
 4140            SelectPhase::Update {
 4141                position,
 4142                goal_column,
 4143                scroll_delta,
 4144            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4145            SelectPhase::End => self.end_selection(window, cx),
 4146        }
 4147    }
 4148
 4149    fn extend_selection(
 4150        &mut self,
 4151        position: DisplayPoint,
 4152        click_count: usize,
 4153        window: &mut Window,
 4154        cx: &mut Context<Self>,
 4155    ) {
 4156        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4157        let tail = self
 4158            .selections
 4159            .newest::<MultiBufferOffset>(&display_map)
 4160            .tail();
 4161        let click_count = click_count.max(match self.selections.select_mode() {
 4162            SelectMode::Character => 1,
 4163            SelectMode::Word(_) => 2,
 4164            SelectMode::Line(_) => 3,
 4165            SelectMode::All => 4,
 4166        });
 4167        self.begin_selection(position, false, click_count, window, cx);
 4168
 4169        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4170
 4171        let current_selection = match self.selections.select_mode() {
 4172            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4173            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4174        };
 4175
 4176        let mut pending_selection = self
 4177            .selections
 4178            .pending_anchor()
 4179            .cloned()
 4180            .expect("extend_selection not called with pending selection");
 4181
 4182        if pending_selection
 4183            .start
 4184            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4185            == Ordering::Greater
 4186        {
 4187            pending_selection.start = current_selection.start;
 4188        }
 4189        if pending_selection
 4190            .end
 4191            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4192            == Ordering::Less
 4193        {
 4194            pending_selection.end = current_selection.end;
 4195            pending_selection.reversed = true;
 4196        }
 4197
 4198        let mut pending_mode = self.selections.pending_mode().unwrap();
 4199        match &mut pending_mode {
 4200            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4201            _ => {}
 4202        }
 4203
 4204        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4205            SelectionEffects::scroll(Autoscroll::fit())
 4206        } else {
 4207            SelectionEffects::no_scroll()
 4208        };
 4209
 4210        self.change_selections(effects, window, cx, |s| {
 4211            s.set_pending(pending_selection.clone(), pending_mode);
 4212            s.set_is_extending(true);
 4213        });
 4214    }
 4215
 4216    fn begin_selection(
 4217        &mut self,
 4218        position: DisplayPoint,
 4219        add: bool,
 4220        click_count: usize,
 4221        window: &mut Window,
 4222        cx: &mut Context<Self>,
 4223    ) {
 4224        if !self.focus_handle.is_focused(window) {
 4225            self.last_focused_descendant = None;
 4226            window.focus(&self.focus_handle, cx);
 4227        }
 4228
 4229        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4230        let buffer = display_map.buffer_snapshot();
 4231        let position = display_map.clip_point(position, Bias::Left);
 4232
 4233        let start;
 4234        let end;
 4235        let mode;
 4236        let mut auto_scroll;
 4237        match click_count {
 4238            1 => {
 4239                start = buffer.anchor_before(position.to_point(&display_map));
 4240                end = start;
 4241                mode = SelectMode::Character;
 4242                auto_scroll = true;
 4243            }
 4244            2 => {
 4245                let position = display_map
 4246                    .clip_point(position, Bias::Left)
 4247                    .to_offset(&display_map, Bias::Left);
 4248                let (range, _) = buffer.surrounding_word(position, None);
 4249                start = buffer.anchor_before(range.start);
 4250                end = buffer.anchor_before(range.end);
 4251                mode = SelectMode::Word(start..end);
 4252                auto_scroll = true;
 4253            }
 4254            3 => {
 4255                let position = display_map
 4256                    .clip_point(position, Bias::Left)
 4257                    .to_point(&display_map);
 4258                let line_start = display_map.prev_line_boundary(position).0;
 4259                let next_line_start = buffer.clip_point(
 4260                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4261                    Bias::Left,
 4262                );
 4263                start = buffer.anchor_before(line_start);
 4264                end = buffer.anchor_before(next_line_start);
 4265                mode = SelectMode::Line(start..end);
 4266                auto_scroll = true;
 4267            }
 4268            _ => {
 4269                start = buffer.anchor_before(MultiBufferOffset(0));
 4270                end = buffer.anchor_before(buffer.len());
 4271                mode = SelectMode::All;
 4272                auto_scroll = false;
 4273            }
 4274        }
 4275        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4276
 4277        let point_to_delete: Option<usize> = {
 4278            let selected_points: Vec<Selection<Point>> =
 4279                self.selections.disjoint_in_range(start..end, &display_map);
 4280
 4281            if !add || click_count > 1 {
 4282                None
 4283            } else if !selected_points.is_empty() {
 4284                Some(selected_points[0].id)
 4285            } else {
 4286                let clicked_point_already_selected =
 4287                    self.selections.disjoint_anchors().iter().find(|selection| {
 4288                        selection.start.to_point(buffer) == start.to_point(buffer)
 4289                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4290                    });
 4291
 4292                clicked_point_already_selected.map(|selection| selection.id)
 4293            }
 4294        };
 4295
 4296        let selections_count = self.selections.count();
 4297        let effects = if auto_scroll {
 4298            SelectionEffects::default()
 4299        } else {
 4300            SelectionEffects::no_scroll()
 4301        };
 4302
 4303        self.change_selections(effects, window, cx, |s| {
 4304            if let Some(point_to_delete) = point_to_delete {
 4305                s.delete(point_to_delete);
 4306
 4307                if selections_count == 1 {
 4308                    s.set_pending_anchor_range(start..end, mode);
 4309                }
 4310            } else {
 4311                if !add {
 4312                    s.clear_disjoint();
 4313                }
 4314
 4315                s.set_pending_anchor_range(start..end, mode);
 4316            }
 4317        });
 4318    }
 4319
 4320    fn begin_columnar_selection(
 4321        &mut self,
 4322        position: DisplayPoint,
 4323        goal_column: u32,
 4324        reset: bool,
 4325        mode: ColumnarMode,
 4326        window: &mut Window,
 4327        cx: &mut Context<Self>,
 4328    ) {
 4329        if !self.focus_handle.is_focused(window) {
 4330            self.last_focused_descendant = None;
 4331            window.focus(&self.focus_handle, cx);
 4332        }
 4333
 4334        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4335
 4336        if reset {
 4337            let pointer_position = display_map
 4338                .buffer_snapshot()
 4339                .anchor_before(position.to_point(&display_map));
 4340
 4341            self.change_selections(
 4342                SelectionEffects::scroll(Autoscroll::newest()),
 4343                window,
 4344                cx,
 4345                |s| {
 4346                    s.clear_disjoint();
 4347                    s.set_pending_anchor_range(
 4348                        pointer_position..pointer_position,
 4349                        SelectMode::Character,
 4350                    );
 4351                },
 4352            );
 4353        };
 4354
 4355        let tail = self.selections.newest::<Point>(&display_map).tail();
 4356        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4357        self.columnar_selection_state = match mode {
 4358            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4359                selection_tail: selection_anchor,
 4360                display_point: if reset {
 4361                    if position.column() != goal_column {
 4362                        Some(DisplayPoint::new(position.row(), goal_column))
 4363                    } else {
 4364                        None
 4365                    }
 4366                } else {
 4367                    None
 4368                },
 4369            }),
 4370            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4371                selection_tail: selection_anchor,
 4372            }),
 4373        };
 4374
 4375        if !reset {
 4376            self.select_columns(position, goal_column, &display_map, window, cx);
 4377        }
 4378    }
 4379
 4380    fn update_selection(
 4381        &mut self,
 4382        position: DisplayPoint,
 4383        goal_column: u32,
 4384        scroll_delta: gpui::Point<f32>,
 4385        window: &mut Window,
 4386        cx: &mut Context<Self>,
 4387    ) {
 4388        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4389
 4390        if self.columnar_selection_state.is_some() {
 4391            self.select_columns(position, goal_column, &display_map, window, cx);
 4392        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4393            let buffer = display_map.buffer_snapshot();
 4394            let head;
 4395            let tail;
 4396            let mode = self.selections.pending_mode().unwrap();
 4397            match &mode {
 4398                SelectMode::Character => {
 4399                    head = position.to_point(&display_map);
 4400                    tail = pending.tail().to_point(buffer);
 4401                }
 4402                SelectMode::Word(original_range) => {
 4403                    let offset = display_map
 4404                        .clip_point(position, Bias::Left)
 4405                        .to_offset(&display_map, Bias::Left);
 4406                    let original_range = original_range.to_offset(buffer);
 4407
 4408                    let head_offset = if buffer.is_inside_word(offset, None)
 4409                        || original_range.contains(&offset)
 4410                    {
 4411                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4412                        if word_range.start < original_range.start {
 4413                            word_range.start
 4414                        } else {
 4415                            word_range.end
 4416                        }
 4417                    } else {
 4418                        offset
 4419                    };
 4420
 4421                    head = head_offset.to_point(buffer);
 4422                    if head_offset <= original_range.start {
 4423                        tail = original_range.end.to_point(buffer);
 4424                    } else {
 4425                        tail = original_range.start.to_point(buffer);
 4426                    }
 4427                }
 4428                SelectMode::Line(original_range) => {
 4429                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4430
 4431                    let position = display_map
 4432                        .clip_point(position, Bias::Left)
 4433                        .to_point(&display_map);
 4434                    let line_start = display_map.prev_line_boundary(position).0;
 4435                    let next_line_start = buffer.clip_point(
 4436                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4437                        Bias::Left,
 4438                    );
 4439
 4440                    if line_start < original_range.start {
 4441                        head = line_start
 4442                    } else {
 4443                        head = next_line_start
 4444                    }
 4445
 4446                    if head <= original_range.start {
 4447                        tail = original_range.end;
 4448                    } else {
 4449                        tail = original_range.start;
 4450                    }
 4451                }
 4452                SelectMode::All => {
 4453                    return;
 4454                }
 4455            };
 4456
 4457            if head < tail {
 4458                pending.start = buffer.anchor_before(head);
 4459                pending.end = buffer.anchor_before(tail);
 4460                pending.reversed = true;
 4461            } else {
 4462                pending.start = buffer.anchor_before(tail);
 4463                pending.end = buffer.anchor_before(head);
 4464                pending.reversed = false;
 4465            }
 4466
 4467            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4468                s.set_pending(pending.clone(), mode);
 4469            });
 4470        } else {
 4471            log::error!("update_selection dispatched with no pending selection");
 4472            return;
 4473        }
 4474
 4475        self.apply_scroll_delta(scroll_delta, window, cx);
 4476        cx.notify();
 4477    }
 4478
 4479    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4480        self.columnar_selection_state.take();
 4481        if let Some(pending_mode) = self.selections.pending_mode() {
 4482            let selections = self
 4483                .selections
 4484                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4485            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4486                s.select(selections);
 4487                s.clear_pending();
 4488                if s.is_extending() {
 4489                    s.set_is_extending(false);
 4490                } else {
 4491                    s.set_select_mode(pending_mode);
 4492                }
 4493            });
 4494        }
 4495    }
 4496
 4497    fn select_columns(
 4498        &mut self,
 4499        head: DisplayPoint,
 4500        goal_column: u32,
 4501        display_map: &DisplaySnapshot,
 4502        window: &mut Window,
 4503        cx: &mut Context<Self>,
 4504    ) {
 4505        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4506            return;
 4507        };
 4508
 4509        let tail = match columnar_state {
 4510            ColumnarSelectionState::FromMouse {
 4511                selection_tail,
 4512                display_point,
 4513            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4514            ColumnarSelectionState::FromSelection { selection_tail } => {
 4515                selection_tail.to_display_point(display_map)
 4516            }
 4517        };
 4518
 4519        let start_row = cmp::min(tail.row(), head.row());
 4520        let end_row = cmp::max(tail.row(), head.row());
 4521        let start_column = cmp::min(tail.column(), goal_column);
 4522        let end_column = cmp::max(tail.column(), goal_column);
 4523        let reversed = start_column < tail.column();
 4524
 4525        let selection_ranges = (start_row.0..=end_row.0)
 4526            .map(DisplayRow)
 4527            .filter_map(|row| {
 4528                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4529                    || start_column <= display_map.line_len(row))
 4530                    && !display_map.is_block_line(row)
 4531                {
 4532                    let start = display_map
 4533                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4534                        .to_point(display_map);
 4535                    let end = display_map
 4536                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4537                        .to_point(display_map);
 4538                    if reversed {
 4539                        Some(end..start)
 4540                    } else {
 4541                        Some(start..end)
 4542                    }
 4543                } else {
 4544                    None
 4545                }
 4546            })
 4547            .collect::<Vec<_>>();
 4548        if selection_ranges.is_empty() {
 4549            return;
 4550        }
 4551
 4552        let ranges = match columnar_state {
 4553            ColumnarSelectionState::FromMouse { .. } => {
 4554                let mut non_empty_ranges = selection_ranges
 4555                    .iter()
 4556                    .filter(|selection_range| selection_range.start != selection_range.end)
 4557                    .peekable();
 4558                if non_empty_ranges.peek().is_some() {
 4559                    non_empty_ranges.cloned().collect()
 4560                } else {
 4561                    selection_ranges
 4562                }
 4563            }
 4564            _ => selection_ranges,
 4565        };
 4566
 4567        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4568            s.select_ranges(ranges);
 4569        });
 4570        cx.notify();
 4571    }
 4572
 4573    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4574        self.selections
 4575            .all_adjusted(snapshot)
 4576            .iter()
 4577            .any(|selection| !selection.is_empty())
 4578    }
 4579
 4580    pub fn has_pending_nonempty_selection(&self) -> bool {
 4581        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4582            Some(Selection { start, end, .. }) => start != end,
 4583            None => false,
 4584        };
 4585
 4586        pending_nonempty_selection
 4587            || (self.columnar_selection_state.is_some()
 4588                && self.selections.disjoint_anchors().len() > 1)
 4589    }
 4590
 4591    pub fn has_pending_selection(&self) -> bool {
 4592        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4593    }
 4594
 4595    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4596        self.selection_mark_mode = false;
 4597        self.selection_drag_state = SelectionDragState::None;
 4598
 4599        if self.dismiss_menus_and_popups(true, window, cx) {
 4600            cx.notify();
 4601            return;
 4602        }
 4603        if self.clear_expanded_diff_hunks(cx) {
 4604            cx.notify();
 4605            return;
 4606        }
 4607        if self.show_git_blame_gutter {
 4608            self.show_git_blame_gutter = false;
 4609            cx.notify();
 4610            return;
 4611        }
 4612
 4613        if self.mode.is_full()
 4614            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4615        {
 4616            cx.notify();
 4617            return;
 4618        }
 4619
 4620        cx.propagate();
 4621    }
 4622
 4623    pub fn dismiss_menus_and_popups(
 4624        &mut self,
 4625        is_user_requested: bool,
 4626        window: &mut Window,
 4627        cx: &mut Context<Self>,
 4628    ) -> bool {
 4629        let mut dismissed = false;
 4630
 4631        dismissed |= self.take_rename(false, window, cx).is_some();
 4632        dismissed |= self.hide_blame_popover(true, cx);
 4633        dismissed |= hide_hover(self, cx);
 4634        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4635        dismissed |= self.hide_context_menu(window, cx).is_some();
 4636        dismissed |= self.mouse_context_menu.take().is_some();
 4637        dismissed |= is_user_requested
 4638            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4639        dismissed |= self.snippet_stack.pop().is_some();
 4640        if self.diff_review_drag_state.is_some() {
 4641            self.cancel_diff_review_drag(cx);
 4642            dismissed = true;
 4643        }
 4644        if !self.diff_review_overlays.is_empty() {
 4645            self.dismiss_all_diff_review_overlays(cx);
 4646            dismissed = true;
 4647        }
 4648
 4649        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4650            self.dismiss_diagnostics(cx);
 4651            dismissed = true;
 4652        }
 4653
 4654        dismissed
 4655    }
 4656
 4657    fn linked_editing_ranges_for(
 4658        &self,
 4659        selection: Range<text::Anchor>,
 4660        cx: &App,
 4661    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4662        if self.linked_edit_ranges.is_empty() {
 4663            return None;
 4664        }
 4665        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4666            selection.end.buffer_id.and_then(|end_buffer_id| {
 4667                if selection.start.buffer_id != Some(end_buffer_id) {
 4668                    return None;
 4669                }
 4670                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4671                let snapshot = buffer.read(cx).snapshot();
 4672                self.linked_edit_ranges
 4673                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4674                    .map(|ranges| (ranges, snapshot, buffer))
 4675            })?;
 4676        use text::ToOffset as TO;
 4677        // find offset from the start of current range to current cursor position
 4678        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4679
 4680        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4681        let start_difference = start_offset - start_byte_offset;
 4682        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4683        let end_difference = end_offset - start_byte_offset;
 4684
 4685        // Current range has associated linked ranges.
 4686        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4687        for range in linked_ranges.iter() {
 4688            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4689            let end_offset = start_offset + end_difference;
 4690            let start_offset = start_offset + start_difference;
 4691            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4692                continue;
 4693            }
 4694            if self.selections.disjoint_anchor_ranges().any(|s| {
 4695                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4696                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4697                {
 4698                    return false;
 4699                }
 4700                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4701                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4702            }) {
 4703                continue;
 4704            }
 4705            let start = buffer_snapshot.anchor_after(start_offset);
 4706            let end = buffer_snapshot.anchor_after(end_offset);
 4707            linked_edits
 4708                .entry(buffer.clone())
 4709                .or_default()
 4710                .push(start..end);
 4711        }
 4712        Some(linked_edits)
 4713    }
 4714
 4715    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4716        let text: Arc<str> = text.into();
 4717
 4718        if self.read_only(cx) {
 4719            return;
 4720        }
 4721
 4722        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4723
 4724        self.unfold_buffers_with_selections(cx);
 4725
 4726        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4727        let mut bracket_inserted = false;
 4728        let mut edits = Vec::new();
 4729        let mut linked_edits = LinkedEdits::new();
 4730        let mut new_selections = Vec::with_capacity(selections.len());
 4731        let mut new_autoclose_regions = Vec::new();
 4732        let snapshot = self.buffer.read(cx).read(cx);
 4733        let mut clear_linked_edit_ranges = false;
 4734        let mut all_selections_read_only = true;
 4735        let mut has_adjacent_edits = false;
 4736        let mut in_adjacent_group = false;
 4737
 4738        let mut regions = self
 4739            .selections_with_autoclose_regions(selections, &snapshot)
 4740            .peekable();
 4741
 4742        while let Some((selection, autoclose_region)) = regions.next() {
 4743            if snapshot
 4744                .point_to_buffer_point(selection.head())
 4745                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4746            {
 4747                continue;
 4748            }
 4749            if snapshot
 4750                .point_to_buffer_point(selection.tail())
 4751                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4752            {
 4753                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4754                continue;
 4755            }
 4756            all_selections_read_only = false;
 4757
 4758            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4759                // Determine if the inserted text matches the opening or closing
 4760                // bracket of any of this language's bracket pairs.
 4761                let mut bracket_pair = None;
 4762                let mut is_bracket_pair_start = false;
 4763                let mut is_bracket_pair_end = false;
 4764                if !text.is_empty() {
 4765                    let mut bracket_pair_matching_end = None;
 4766                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4767                    //  and they are removing the character that triggered IME popup.
 4768                    for (pair, enabled) in scope.brackets() {
 4769                        if !pair.close && !pair.surround {
 4770                            continue;
 4771                        }
 4772
 4773                        if enabled && pair.start.ends_with(text.as_ref()) {
 4774                            let prefix_len = pair.start.len() - text.len();
 4775                            let preceding_text_matches_prefix = prefix_len == 0
 4776                                || (selection.start.column >= (prefix_len as u32)
 4777                                    && snapshot.contains_str_at(
 4778                                        Point::new(
 4779                                            selection.start.row,
 4780                                            selection.start.column - (prefix_len as u32),
 4781                                        ),
 4782                                        &pair.start[..prefix_len],
 4783                                    ));
 4784                            if preceding_text_matches_prefix {
 4785                                bracket_pair = Some(pair.clone());
 4786                                is_bracket_pair_start = true;
 4787                                break;
 4788                            }
 4789                        }
 4790                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4791                        {
 4792                            // take first bracket pair matching end, but don't break in case a later bracket
 4793                            // pair matches start
 4794                            bracket_pair_matching_end = Some(pair.clone());
 4795                        }
 4796                    }
 4797                    if let Some(end) = bracket_pair_matching_end
 4798                        && bracket_pair.is_none()
 4799                    {
 4800                        bracket_pair = Some(end);
 4801                        is_bracket_pair_end = true;
 4802                    }
 4803                }
 4804
 4805                if let Some(bracket_pair) = bracket_pair {
 4806                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4807                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4808                    let auto_surround =
 4809                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4810                    if selection.is_empty() {
 4811                        if is_bracket_pair_start {
 4812                            // If the inserted text is a suffix of an opening bracket and the
 4813                            // selection is preceded by the rest of the opening bracket, then
 4814                            // insert the closing bracket.
 4815                            let following_text_allows_autoclose = snapshot
 4816                                .chars_at(selection.start)
 4817                                .next()
 4818                                .is_none_or(|c| scope.should_autoclose_before(c));
 4819
 4820                            let preceding_text_allows_autoclose = selection.start.column == 0
 4821                                || snapshot
 4822                                    .reversed_chars_at(selection.start)
 4823                                    .next()
 4824                                    .is_none_or(|c| {
 4825                                        bracket_pair.start != bracket_pair.end
 4826                                            || !snapshot
 4827                                                .char_classifier_at(selection.start)
 4828                                                .is_word(c)
 4829                                    });
 4830
 4831                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4832                                && bracket_pair.start.len() == 1
 4833                            {
 4834                                let target = bracket_pair.start.chars().next().unwrap();
 4835                                let mut byte_offset = 0u32;
 4836                                let current_line_count = snapshot
 4837                                    .reversed_chars_at(selection.start)
 4838                                    .take_while(|&c| c != '\n')
 4839                                    .filter(|c| {
 4840                                        byte_offset += c.len_utf8() as u32;
 4841                                        if *c != target {
 4842                                            return false;
 4843                                        }
 4844
 4845                                        let point = Point::new(
 4846                                            selection.start.row,
 4847                                            selection.start.column.saturating_sub(byte_offset),
 4848                                        );
 4849
 4850                                        let is_enabled = snapshot
 4851                                            .language_scope_at(point)
 4852                                            .and_then(|scope| {
 4853                                                scope
 4854                                                    .brackets()
 4855                                                    .find(|(pair, _)| {
 4856                                                        pair.start == bracket_pair.start
 4857                                                    })
 4858                                                    .map(|(_, enabled)| enabled)
 4859                                            })
 4860                                            .unwrap_or(true);
 4861
 4862                                        let is_delimiter = snapshot
 4863                                            .language_scope_at(Point::new(
 4864                                                point.row,
 4865                                                point.column + 1,
 4866                                            ))
 4867                                            .and_then(|scope| {
 4868                                                scope
 4869                                                    .brackets()
 4870                                                    .find(|(pair, _)| {
 4871                                                        pair.start == bracket_pair.start
 4872                                                    })
 4873                                                    .map(|(_, enabled)| !enabled)
 4874                                            })
 4875                                            .unwrap_or(false);
 4876
 4877                                        is_enabled && !is_delimiter
 4878                                    })
 4879                                    .count();
 4880                                current_line_count % 2 == 1
 4881                            } else {
 4882                                false
 4883                            };
 4884
 4885                            if autoclose
 4886                                && bracket_pair.close
 4887                                && following_text_allows_autoclose
 4888                                && preceding_text_allows_autoclose
 4889                                && !is_closing_quote
 4890                            {
 4891                                let anchor = snapshot.anchor_before(selection.end);
 4892                                new_selections.push((selection.map(|_| anchor), text.len()));
 4893                                new_autoclose_regions.push((
 4894                                    anchor,
 4895                                    text.len(),
 4896                                    selection.id,
 4897                                    bracket_pair.clone(),
 4898                                ));
 4899                                edits.push((
 4900                                    selection.range(),
 4901                                    format!("{}{}", text, bracket_pair.end).into(),
 4902                                ));
 4903                                bracket_inserted = true;
 4904                                continue;
 4905                            }
 4906                        }
 4907
 4908                        if let Some(region) = autoclose_region {
 4909                            // If the selection is followed by an auto-inserted closing bracket,
 4910                            // then don't insert that closing bracket again; just move the selection
 4911                            // past the closing bracket.
 4912                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4913                                && text.as_ref() == region.pair.end.as_str()
 4914                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4915                            if should_skip {
 4916                                let anchor = snapshot.anchor_after(selection.end);
 4917                                new_selections
 4918                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4919                                continue;
 4920                            }
 4921                        }
 4922
 4923                        let always_treat_brackets_as_autoclosed = snapshot
 4924                            .language_settings_at(selection.start, cx)
 4925                            .always_treat_brackets_as_autoclosed;
 4926                        if always_treat_brackets_as_autoclosed
 4927                            && is_bracket_pair_end
 4928                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4929                        {
 4930                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4931                            // and the inserted text is a closing bracket and the selection is followed
 4932                            // by the closing bracket then move the selection past the closing bracket.
 4933                            let anchor = snapshot.anchor_after(selection.end);
 4934                            new_selections.push((selection.map(|_| anchor), text.len()));
 4935                            continue;
 4936                        }
 4937                    }
 4938                    // If an opening bracket is 1 character long and is typed while
 4939                    // text is selected, then surround that text with the bracket pair.
 4940                    else if auto_surround
 4941                        && bracket_pair.surround
 4942                        && is_bracket_pair_start
 4943                        && bracket_pair.start.chars().count() == 1
 4944                    {
 4945                        edits.push((selection.start..selection.start, text.clone()));
 4946                        edits.push((
 4947                            selection.end..selection.end,
 4948                            bracket_pair.end.as_str().into(),
 4949                        ));
 4950                        bracket_inserted = true;
 4951                        new_selections.push((
 4952                            Selection {
 4953                                id: selection.id,
 4954                                start: snapshot.anchor_after(selection.start),
 4955                                end: snapshot.anchor_before(selection.end),
 4956                                reversed: selection.reversed,
 4957                                goal: selection.goal,
 4958                            },
 4959                            0,
 4960                        ));
 4961                        continue;
 4962                    }
 4963                }
 4964            }
 4965
 4966            if self.auto_replace_emoji_shortcode
 4967                && selection.is_empty()
 4968                && text.as_ref().ends_with(':')
 4969                && let Some(possible_emoji_short_code) =
 4970                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4971                && !possible_emoji_short_code.is_empty()
 4972                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4973            {
 4974                let emoji_shortcode_start = Point::new(
 4975                    selection.start.row,
 4976                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4977                );
 4978
 4979                // Remove shortcode from buffer
 4980                edits.push((
 4981                    emoji_shortcode_start..selection.start,
 4982                    "".to_string().into(),
 4983                ));
 4984                new_selections.push((
 4985                    Selection {
 4986                        id: selection.id,
 4987                        start: snapshot.anchor_after(emoji_shortcode_start),
 4988                        end: snapshot.anchor_before(selection.start),
 4989                        reversed: selection.reversed,
 4990                        goal: selection.goal,
 4991                    },
 4992                    0,
 4993                ));
 4994
 4995                // Insert emoji
 4996                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4997                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4998                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4999
 5000                continue;
 5001            }
 5002
 5003            let next_is_adjacent = regions
 5004                .peek()
 5005                .is_some_and(|(next, _)| selection.end == next.start);
 5006
 5007            // If not handling any auto-close operation, then just replace the selected
 5008            // text with the given input and move the selection to the end of the
 5009            // newly inserted text.
 5010            let anchor = if in_adjacent_group || next_is_adjacent {
 5011                // After edits the right bias would shift those anchor to the next visible fragment
 5012                // but we want to resolve to the previous one
 5013                snapshot.anchor_before(selection.end)
 5014            } else {
 5015                snapshot.anchor_after(selection.end)
 5016            };
 5017
 5018            if !self.linked_edit_ranges.is_empty() {
 5019                let start_anchor = snapshot.anchor_before(selection.start);
 5020
 5021                let is_word_char = text.chars().next().is_none_or(|char| {
 5022                    let classifier = snapshot
 5023                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 5024                        .scope_context(Some(CharScopeContext::LinkedEdit));
 5025                    classifier.is_word(char)
 5026                });
 5027                let is_dot = text.as_ref() == ".";
 5028                let should_apply_linked_edit = is_word_char || is_dot;
 5029
 5030                if should_apply_linked_edit {
 5031                    let anchor_range = start_anchor.text_anchor..anchor.text_anchor;
 5032                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 5033                } else {
 5034                    clear_linked_edit_ranges = true;
 5035                }
 5036            }
 5037
 5038            new_selections.push((selection.map(|_| anchor), 0));
 5039            edits.push((selection.start..selection.end, text.clone()));
 5040
 5041            has_adjacent_edits |= next_is_adjacent;
 5042            in_adjacent_group = next_is_adjacent;
 5043        }
 5044
 5045        if all_selections_read_only {
 5046            return;
 5047        }
 5048
 5049        drop(regions);
 5050        drop(snapshot);
 5051
 5052        self.transact(window, cx, |this, window, cx| {
 5053            if clear_linked_edit_ranges {
 5054                this.linked_edit_ranges.clear();
 5055            }
 5056            let initial_buffer_versions =
 5057                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5058
 5059            this.buffer.update(cx, |buffer, cx| {
 5060                if has_adjacent_edits {
 5061                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5062                } else {
 5063                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5064                }
 5065            });
 5066            linked_edits.apply(cx);
 5067            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5068            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5069            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5070            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5071                new_anchor_selections,
 5072                &map,
 5073            )
 5074            .zip(new_selection_deltas)
 5075            .map(|(selection, delta)| Selection {
 5076                id: selection.id,
 5077                start: selection.start + delta,
 5078                end: selection.end + delta,
 5079                reversed: selection.reversed,
 5080                goal: SelectionGoal::None,
 5081            })
 5082            .collect::<Vec<_>>();
 5083
 5084            let mut i = 0;
 5085            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5086                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5087                let start = map.buffer_snapshot().anchor_before(position);
 5088                let end = map.buffer_snapshot().anchor_after(position);
 5089                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5090                    match existing_state
 5091                        .range
 5092                        .start
 5093                        .cmp(&start, map.buffer_snapshot())
 5094                    {
 5095                        Ordering::Less => i += 1,
 5096                        Ordering::Greater => break,
 5097                        Ordering::Equal => {
 5098                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5099                                Ordering::Less => i += 1,
 5100                                Ordering::Equal => break,
 5101                                Ordering::Greater => break,
 5102                            }
 5103                        }
 5104                    }
 5105                }
 5106                this.autoclose_regions.insert(
 5107                    i,
 5108                    AutocloseRegion {
 5109                        selection_id,
 5110                        range: start..end,
 5111                        pair,
 5112                    },
 5113                );
 5114            }
 5115
 5116            let had_active_edit_prediction = this.has_active_edit_prediction();
 5117            this.change_selections(
 5118                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5119                window,
 5120                cx,
 5121                |s| s.select(new_selections),
 5122            );
 5123
 5124            if !bracket_inserted
 5125                && let Some(on_type_format_task) =
 5126                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5127            {
 5128                on_type_format_task.detach_and_log_err(cx);
 5129            }
 5130
 5131            let editor_settings = EditorSettings::get_global(cx);
 5132            if bracket_inserted
 5133                && (editor_settings.auto_signature_help
 5134                    || editor_settings.show_signature_help_after_edits)
 5135            {
 5136                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5137            }
 5138
 5139            let trigger_in_words =
 5140                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5141            if this.hard_wrap.is_some() {
 5142                let latest: Range<Point> = this.selections.newest(&map).range();
 5143                if latest.is_empty()
 5144                    && this
 5145                        .buffer()
 5146                        .read(cx)
 5147                        .snapshot(cx)
 5148                        .line_len(MultiBufferRow(latest.start.row))
 5149                        == latest.start.column
 5150                {
 5151                    this.rewrap_impl(
 5152                        RewrapOptions {
 5153                            override_language_settings: true,
 5154                            preserve_existing_whitespace: true,
 5155                            line_length: None,
 5156                        },
 5157                        cx,
 5158                    )
 5159                }
 5160            }
 5161            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5162            refresh_linked_ranges(this, window, cx);
 5163            this.refresh_edit_prediction(true, false, window, cx);
 5164            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5165        });
 5166    }
 5167
 5168    fn find_possible_emoji_shortcode_at_position(
 5169        snapshot: &MultiBufferSnapshot,
 5170        position: Point,
 5171    ) -> Option<String> {
 5172        let mut chars = Vec::new();
 5173        let mut found_colon = false;
 5174        for char in snapshot.reversed_chars_at(position).take(100) {
 5175            // Found a possible emoji shortcode in the middle of the buffer
 5176            if found_colon {
 5177                if char.is_whitespace() {
 5178                    chars.reverse();
 5179                    return Some(chars.iter().collect());
 5180                }
 5181                // If the previous character is not a whitespace, we are in the middle of a word
 5182                // and we only want to complete the shortcode if the word is made up of other emojis
 5183                let mut containing_word = String::new();
 5184                for ch in snapshot
 5185                    .reversed_chars_at(position)
 5186                    .skip(chars.len() + 1)
 5187                    .take(100)
 5188                {
 5189                    if ch.is_whitespace() {
 5190                        break;
 5191                    }
 5192                    containing_word.push(ch);
 5193                }
 5194                let containing_word = containing_word.chars().rev().collect::<String>();
 5195                if util::word_consists_of_emojis(containing_word.as_str()) {
 5196                    chars.reverse();
 5197                    return Some(chars.iter().collect());
 5198                }
 5199            }
 5200
 5201            if char.is_whitespace() || !char.is_ascii() {
 5202                return None;
 5203            }
 5204            if char == ':' {
 5205                found_colon = true;
 5206            } else {
 5207                chars.push(char);
 5208            }
 5209        }
 5210        // Found a possible emoji shortcode at the beginning of the buffer
 5211        chars.reverse();
 5212        Some(chars.iter().collect())
 5213    }
 5214
 5215    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5216        if self.read_only(cx) {
 5217            return;
 5218        }
 5219
 5220        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5221        self.transact(window, cx, |this, window, cx| {
 5222            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5223                let selections = this
 5224                    .selections
 5225                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5226                let multi_buffer = this.buffer.read(cx);
 5227                let buffer = multi_buffer.snapshot(cx);
 5228                selections
 5229                    .iter()
 5230                    .map(|selection| {
 5231                        let start_point = selection.start.to_point(&buffer);
 5232                        let mut existing_indent =
 5233                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5234                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5235                        let start = selection.start;
 5236                        let end = selection.end;
 5237                        let selection_is_empty = start == end;
 5238                        let language_scope = buffer.language_scope_at(start);
 5239                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5240                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5241                                &buffer,
 5242                                start..end,
 5243                                language,
 5244                            )
 5245                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5246                                    &buffer,
 5247                                    start..end,
 5248                                );
 5249
 5250                            let mut newline_config = NewlineConfig::Newline {
 5251                                additional_indent: IndentSize::spaces(0),
 5252                                extra_line_additional_indent: if needs_extra_newline {
 5253                                    Some(IndentSize::spaces(0))
 5254                                } else {
 5255                                    None
 5256                                },
 5257                                prevent_auto_indent: false,
 5258                            };
 5259
 5260                            let comment_delimiter = maybe!({
 5261                                if !selection_is_empty {
 5262                                    return None;
 5263                                }
 5264
 5265                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5266                                    return None;
 5267                                }
 5268
 5269                                return comment_delimiter_for_newline(
 5270                                    &start_point,
 5271                                    &buffer,
 5272                                    language,
 5273                                );
 5274                            });
 5275
 5276                            let doc_delimiter = maybe!({
 5277                                if !selection_is_empty {
 5278                                    return None;
 5279                                }
 5280
 5281                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5282                                    return None;
 5283                                }
 5284
 5285                                return documentation_delimiter_for_newline(
 5286                                    &start_point,
 5287                                    &buffer,
 5288                                    language,
 5289                                    &mut newline_config,
 5290                                );
 5291                            });
 5292
 5293                            let list_delimiter = maybe!({
 5294                                if !selection_is_empty {
 5295                                    return None;
 5296                                }
 5297
 5298                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5299                                    return None;
 5300                                }
 5301
 5302                                return list_delimiter_for_newline(
 5303                                    &start_point,
 5304                                    &buffer,
 5305                                    language,
 5306                                    &mut newline_config,
 5307                                );
 5308                            });
 5309
 5310                            (
 5311                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5312                                newline_config,
 5313                            )
 5314                        } else {
 5315                            (
 5316                                None,
 5317                                NewlineConfig::Newline {
 5318                                    additional_indent: IndentSize::spaces(0),
 5319                                    extra_line_additional_indent: None,
 5320                                    prevent_auto_indent: false,
 5321                                },
 5322                            )
 5323                        };
 5324
 5325                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5326                            NewlineConfig::ClearCurrentLine => {
 5327                                let row_start =
 5328                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5329                                (row_start, String::new(), false)
 5330                            }
 5331                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5332                                let row_start =
 5333                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5334                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5335                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5336                                let reduced_indent =
 5337                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5338                                let mut new_text = String::new();
 5339                                new_text.extend(reduced_indent.chars());
 5340                                new_text.push_str(continuation);
 5341                                (row_start, new_text, true)
 5342                            }
 5343                            NewlineConfig::Newline {
 5344                                additional_indent,
 5345                                extra_line_additional_indent,
 5346                                prevent_auto_indent,
 5347                            } => {
 5348                                let auto_indent_mode =
 5349                                    buffer.language_settings_at(start, cx).auto_indent;
 5350                                let preserve_indent =
 5351                                    auto_indent_mode != language::AutoIndentMode::None;
 5352                                let apply_syntax_indent =
 5353                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5354                                let capacity_for_delimiter =
 5355                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5356                                let existing_indent_len = if preserve_indent {
 5357                                    existing_indent.len as usize
 5358                                } else {
 5359                                    0
 5360                                };
 5361                                let extra_line_len = extra_line_additional_indent
 5362                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5363                                    .unwrap_or(0);
 5364                                let mut new_text = String::with_capacity(
 5365                                    1 + capacity_for_delimiter
 5366                                        + existing_indent_len
 5367                                        + additional_indent.len as usize
 5368                                        + extra_line_len,
 5369                                );
 5370                                new_text.push('\n');
 5371                                if preserve_indent {
 5372                                    new_text.extend(existing_indent.chars());
 5373                                }
 5374                                new_text.extend(additional_indent.chars());
 5375                                if let Some(delimiter) = &delimiter {
 5376                                    new_text.push_str(delimiter);
 5377                                }
 5378                                if let Some(extra_indent) = extra_line_additional_indent {
 5379                                    new_text.push('\n');
 5380                                    if preserve_indent {
 5381                                        new_text.extend(existing_indent.chars());
 5382                                    }
 5383                                    new_text.extend(extra_indent.chars());
 5384                                }
 5385                                (
 5386                                    start,
 5387                                    new_text,
 5388                                    *prevent_auto_indent || !apply_syntax_indent,
 5389                                )
 5390                            }
 5391                        };
 5392
 5393                        let anchor = buffer.anchor_after(end);
 5394                        let new_selection = selection.map(|_| anchor);
 5395                        (
 5396                            ((edit_start..end, new_text), prevent_auto_indent),
 5397                            (newline_config.has_extra_line(), new_selection),
 5398                        )
 5399                    })
 5400                    .unzip()
 5401            };
 5402
 5403            let mut auto_indent_edits = Vec::new();
 5404            let mut edits = Vec::new();
 5405            for (edit, prevent_auto_indent) in edits_with_flags {
 5406                if prevent_auto_indent {
 5407                    edits.push(edit);
 5408                } else {
 5409                    auto_indent_edits.push(edit);
 5410                }
 5411            }
 5412            if !edits.is_empty() {
 5413                this.edit(edits, cx);
 5414            }
 5415            if !auto_indent_edits.is_empty() {
 5416                this.edit_with_autoindent(auto_indent_edits, cx);
 5417            }
 5418
 5419            let buffer = this.buffer.read(cx).snapshot(cx);
 5420            let new_selections = selection_info
 5421                .into_iter()
 5422                .map(|(extra_newline_inserted, new_selection)| {
 5423                    let mut cursor = new_selection.end.to_point(&buffer);
 5424                    if extra_newline_inserted {
 5425                        cursor.row -= 1;
 5426                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5427                    }
 5428                    new_selection.map(|_| cursor)
 5429                })
 5430                .collect();
 5431
 5432            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5433            this.refresh_edit_prediction(true, false, window, cx);
 5434            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5435                task.detach_and_log_err(cx);
 5436            }
 5437        });
 5438    }
 5439
 5440    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5441        if self.read_only(cx) {
 5442            return;
 5443        }
 5444
 5445        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5446
 5447        let buffer = self.buffer.read(cx);
 5448        let snapshot = buffer.snapshot(cx);
 5449
 5450        let mut edits = Vec::new();
 5451        let mut rows = Vec::new();
 5452
 5453        for (rows_inserted, selection) in self
 5454            .selections
 5455            .all_adjusted(&self.display_snapshot(cx))
 5456            .into_iter()
 5457            .enumerate()
 5458        {
 5459            let cursor = selection.head();
 5460            let row = cursor.row;
 5461
 5462            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5463
 5464            let newline = "\n".to_string();
 5465            edits.push((start_of_line..start_of_line, newline));
 5466
 5467            rows.push(row + rows_inserted as u32);
 5468        }
 5469
 5470        self.transact(window, cx, |editor, window, cx| {
 5471            editor.edit(edits, cx);
 5472
 5473            editor.change_selections(Default::default(), window, cx, |s| {
 5474                let mut index = 0;
 5475                s.move_cursors_with(&mut |map, _, _| {
 5476                    let row = rows[index];
 5477                    index += 1;
 5478
 5479                    let point = Point::new(row, 0);
 5480                    let boundary = map.next_line_boundary(point).1;
 5481                    let clipped = map.clip_point(boundary, Bias::Left);
 5482
 5483                    (clipped, SelectionGoal::None)
 5484                });
 5485            });
 5486
 5487            let mut indent_edits = Vec::new();
 5488            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5489            for row in rows {
 5490                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5491                for (row, indent) in indents {
 5492                    if indent.len == 0 {
 5493                        continue;
 5494                    }
 5495
 5496                    let text = match indent.kind {
 5497                        IndentKind::Space => " ".repeat(indent.len as usize),
 5498                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5499                    };
 5500                    let point = Point::new(row.0, 0);
 5501                    indent_edits.push((point..point, text));
 5502                }
 5503            }
 5504            editor.edit(indent_edits, cx);
 5505            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5506                format.detach_and_log_err(cx);
 5507            }
 5508        });
 5509    }
 5510
 5511    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5512        if self.read_only(cx) {
 5513            return;
 5514        }
 5515
 5516        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5517
 5518        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5519        let mut rows = Vec::new();
 5520        let mut rows_inserted = 0;
 5521
 5522        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5523            let cursor = selection.head();
 5524            let row = cursor.row;
 5525
 5526            let point = Point::new(row, 0);
 5527            let Some((buffer_handle, buffer_point, _)) =
 5528                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5529            else {
 5530                continue;
 5531            };
 5532
 5533            buffer_edits
 5534                .entry(buffer_handle.entity_id())
 5535                .or_insert_with(|| (buffer_handle, Vec::new()))
 5536                .1
 5537                .push(buffer_point);
 5538
 5539            rows_inserted += 1;
 5540            rows.push(row + rows_inserted);
 5541        }
 5542
 5543        self.transact(window, cx, |editor, window, cx| {
 5544            for (_, (buffer_handle, points)) in &buffer_edits {
 5545                buffer_handle.update(cx, |buffer, cx| {
 5546                    let edits: Vec<_> = points
 5547                        .iter()
 5548                        .map(|point| {
 5549                            let target = Point::new(point.row + 1, 0);
 5550                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5551                            (start_of_line..start_of_line, "\n")
 5552                        })
 5553                        .collect();
 5554                    buffer.edit(edits, None, cx);
 5555                });
 5556            }
 5557
 5558            editor.change_selections(Default::default(), window, cx, |s| {
 5559                let mut index = 0;
 5560                s.move_cursors_with(&mut |map, _, _| {
 5561                    let row = rows[index];
 5562                    index += 1;
 5563
 5564                    let point = Point::new(row, 0);
 5565                    let boundary = map.next_line_boundary(point).1;
 5566                    let clipped = map.clip_point(boundary, Bias::Left);
 5567
 5568                    (clipped, SelectionGoal::None)
 5569                });
 5570            });
 5571
 5572            let mut indent_edits = Vec::new();
 5573            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5574            for row in rows {
 5575                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5576                for (row, indent) in indents {
 5577                    if indent.len == 0 {
 5578                        continue;
 5579                    }
 5580
 5581                    let text = match indent.kind {
 5582                        IndentKind::Space => " ".repeat(indent.len as usize),
 5583                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5584                    };
 5585                    let point = Point::new(row.0, 0);
 5586                    indent_edits.push((point..point, text));
 5587                }
 5588            }
 5589            editor.edit(indent_edits, cx);
 5590            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5591                format.detach_and_log_err(cx);
 5592            }
 5593        });
 5594    }
 5595
 5596    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5597        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5598            original_indent_columns: Vec::new(),
 5599        });
 5600        self.replace_selections(text, autoindent, window, cx, false);
 5601    }
 5602
 5603    /// Replaces the editor's selections with the provided `text`, applying the
 5604    /// given `autoindent_mode` (`None` will skip autoindentation).
 5605    ///
 5606    /// Early returns if the editor is in read-only mode, without applying any
 5607    /// edits.
 5608    fn replace_selections(
 5609        &mut self,
 5610        text: &str,
 5611        autoindent_mode: Option<AutoindentMode>,
 5612        window: &mut Window,
 5613        cx: &mut Context<Self>,
 5614        apply_linked_edits: bool,
 5615    ) {
 5616        if self.read_only(cx) {
 5617            return;
 5618        }
 5619
 5620        let text: Arc<str> = text.into();
 5621        self.transact(window, cx, |this, window, cx| {
 5622            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5623            let linked_edits = if apply_linked_edits {
 5624                this.linked_edits_for_selections(text.clone(), cx)
 5625            } else {
 5626                LinkedEdits::new()
 5627            };
 5628
 5629            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5630                let anchors = {
 5631                    let snapshot = buffer.read(cx);
 5632                    old_selections
 5633                        .iter()
 5634                        .map(|s| {
 5635                            let anchor = snapshot.anchor_after(s.head());
 5636                            s.map(|_| anchor)
 5637                        })
 5638                        .collect::<Vec<_>>()
 5639                };
 5640                buffer.edit(
 5641                    old_selections
 5642                        .iter()
 5643                        .map(|s| (s.start..s.end, text.clone())),
 5644                    autoindent_mode,
 5645                    cx,
 5646                );
 5647                anchors
 5648            });
 5649
 5650            linked_edits.apply(cx);
 5651
 5652            this.change_selections(Default::default(), window, cx, |s| {
 5653                s.select_anchors(selection_anchors);
 5654            });
 5655
 5656            if apply_linked_edits {
 5657                refresh_linked_ranges(this, window, cx);
 5658            }
 5659
 5660            cx.notify();
 5661        });
 5662    }
 5663
 5664    /// Collects linked edits for the current selections, pairing each linked
 5665    /// range with `text`.
 5666    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5667        let mut linked_edits = LinkedEdits::new();
 5668        if !self.linked_edit_ranges.is_empty() {
 5669            for selection in self.selections.disjoint_anchors() {
 5670                let start = selection.start.text_anchor;
 5671                let end = selection.end.text_anchor;
 5672                linked_edits.push(self, start..end, text.clone(), cx);
 5673            }
 5674        }
 5675        linked_edits
 5676    }
 5677
 5678    /// Deletes the content covered by the current selections and applies
 5679    /// linked edits.
 5680    pub fn delete_selections_with_linked_edits(
 5681        &mut self,
 5682        window: &mut Window,
 5683        cx: &mut Context<Self>,
 5684    ) {
 5685        self.replace_selections("", None, window, cx, true);
 5686    }
 5687
 5688    #[cfg(any(test, feature = "test-support"))]
 5689    pub fn set_linked_edit_ranges_for_testing(
 5690        &mut self,
 5691        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5692        cx: &mut Context<Self>,
 5693    ) -> Option<()> {
 5694        let Some((buffer, _)) = self
 5695            .buffer
 5696            .read(cx)
 5697            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5698        else {
 5699            return None;
 5700        };
 5701        let buffer = buffer.read(cx);
 5702        let buffer_id = buffer.remote_id();
 5703        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5704        for (base_range, linked_ranges_points) in ranges {
 5705            let base_anchor =
 5706                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5707            let linked_anchors = linked_ranges_points
 5708                .into_iter()
 5709                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5710                .collect();
 5711            linked_ranges.push((base_anchor, linked_anchors));
 5712        }
 5713        let mut map = HashMap::default();
 5714        map.insert(buffer_id, linked_ranges);
 5715        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5716        Some(())
 5717    }
 5718
 5719    fn trigger_completion_on_input(
 5720        &mut self,
 5721        text: &str,
 5722        trigger_in_words: bool,
 5723        window: &mut Window,
 5724        cx: &mut Context<Self>,
 5725    ) {
 5726        let completions_source = self
 5727            .context_menu
 5728            .borrow()
 5729            .as_ref()
 5730            .and_then(|menu| match menu {
 5731                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5732                CodeContextMenu::CodeActions(_) => None,
 5733            });
 5734
 5735        match completions_source {
 5736            Some(CompletionsMenuSource::Words { .. }) => {
 5737                self.open_or_update_completions_menu(
 5738                    Some(CompletionsMenuSource::Words {
 5739                        ignore_threshold: false,
 5740                    }),
 5741                    None,
 5742                    trigger_in_words,
 5743                    window,
 5744                    cx,
 5745                );
 5746            }
 5747            _ => self.open_or_update_completions_menu(
 5748                None,
 5749                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5750                true,
 5751                window,
 5752                cx,
 5753            ),
 5754        }
 5755    }
 5756
 5757    /// If any empty selections is touching the start of its innermost containing autoclose
 5758    /// region, expand it to select the brackets.
 5759    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5760        let selections = self
 5761            .selections
 5762            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5763        let buffer = self.buffer.read(cx).read(cx);
 5764        let new_selections = self
 5765            .selections_with_autoclose_regions(selections, &buffer)
 5766            .map(|(mut selection, region)| {
 5767                if !selection.is_empty() {
 5768                    return selection;
 5769                }
 5770
 5771                if let Some(region) = region {
 5772                    let mut range = region.range.to_offset(&buffer);
 5773                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5774                        range.start -= region.pair.start.len();
 5775                        if buffer.contains_str_at(range.start, &region.pair.start)
 5776                            && buffer.contains_str_at(range.end, &region.pair.end)
 5777                        {
 5778                            range.end += region.pair.end.len();
 5779                            selection.start = range.start;
 5780                            selection.end = range.end;
 5781
 5782                            return selection;
 5783                        }
 5784                    }
 5785                }
 5786
 5787                let always_treat_brackets_as_autoclosed = buffer
 5788                    .language_settings_at(selection.start, cx)
 5789                    .always_treat_brackets_as_autoclosed;
 5790
 5791                if !always_treat_brackets_as_autoclosed {
 5792                    return selection;
 5793                }
 5794
 5795                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5796                    for (pair, enabled) in scope.brackets() {
 5797                        if !enabled || !pair.close {
 5798                            continue;
 5799                        }
 5800
 5801                        if buffer.contains_str_at(selection.start, &pair.end) {
 5802                            let pair_start_len = pair.start.len();
 5803                            if buffer.contains_str_at(
 5804                                selection.start.saturating_sub_usize(pair_start_len),
 5805                                &pair.start,
 5806                            ) {
 5807                                selection.start -= pair_start_len;
 5808                                selection.end += pair.end.len();
 5809
 5810                                return selection;
 5811                            }
 5812                        }
 5813                    }
 5814                }
 5815
 5816                selection
 5817            })
 5818            .collect();
 5819
 5820        drop(buffer);
 5821        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5822            selections.select(new_selections)
 5823        });
 5824    }
 5825
 5826    /// Iterate the given selections, and for each one, find the smallest surrounding
 5827    /// autoclose region. This uses the ordering of the selections and the autoclose
 5828    /// regions to avoid repeated comparisons.
 5829    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5830        &'a self,
 5831        selections: impl IntoIterator<Item = Selection<D>>,
 5832        buffer: &'a MultiBufferSnapshot,
 5833    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5834        let mut i = 0;
 5835        let mut regions = self.autoclose_regions.as_slice();
 5836        selections.into_iter().map(move |selection| {
 5837            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5838
 5839            let mut enclosing = None;
 5840            while let Some(pair_state) = regions.get(i) {
 5841                if pair_state.range.end.to_offset(buffer) < range.start {
 5842                    regions = &regions[i + 1..];
 5843                    i = 0;
 5844                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5845                    break;
 5846                } else {
 5847                    if pair_state.selection_id == selection.id {
 5848                        enclosing = Some(pair_state);
 5849                    }
 5850                    i += 1;
 5851                }
 5852            }
 5853
 5854            (selection, enclosing)
 5855        })
 5856    }
 5857
 5858    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5859    fn invalidate_autoclose_regions(
 5860        &mut self,
 5861        mut selections: &[Selection<Anchor>],
 5862        buffer: &MultiBufferSnapshot,
 5863    ) {
 5864        self.autoclose_regions.retain(|state| {
 5865            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5866                return false;
 5867            }
 5868
 5869            let mut i = 0;
 5870            while let Some(selection) = selections.get(i) {
 5871                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5872                    selections = &selections[1..];
 5873                    continue;
 5874                }
 5875                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5876                    break;
 5877                }
 5878                if selection.id == state.selection_id {
 5879                    return true;
 5880                } else {
 5881                    i += 1;
 5882                }
 5883            }
 5884            false
 5885        });
 5886    }
 5887
 5888    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5889        let offset = position.to_offset(buffer);
 5890        let (word_range, kind) =
 5891            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5892        if offset > word_range.start && kind == Some(CharKind::Word) {
 5893            Some(
 5894                buffer
 5895                    .text_for_range(word_range.start..offset)
 5896                    .collect::<String>(),
 5897            )
 5898        } else {
 5899            None
 5900        }
 5901    }
 5902
 5903    pub fn visible_excerpts(
 5904        &self,
 5905        lsp_related_only: bool,
 5906        cx: &mut Context<Editor>,
 5907    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5908        let project = self.project().cloned();
 5909        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5910        let multi_buffer = self.buffer().read(cx);
 5911        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5912        multi_buffer_snapshot
 5913            .range_to_buffer_ranges(
 5914                self.multi_buffer_visible_range(&display_snapshot, cx)
 5915                    .to_inclusive(),
 5916            )
 5917            .into_iter()
 5918            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5919            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5920                if !lsp_related_only {
 5921                    return Some((
 5922                        excerpt_id,
 5923                        (
 5924                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5925                            buffer.version().clone(),
 5926                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5927                        ),
 5928                    ));
 5929                }
 5930
 5931                let project = project.as_ref()?.read(cx);
 5932                let buffer_file = project::File::from_dyn(buffer.file())?;
 5933                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5934                let worktree_entry = buffer_worktree
 5935                    .read(cx)
 5936                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5937                if worktree_entry.is_ignored {
 5938                    None
 5939                } else {
 5940                    Some((
 5941                        excerpt_id,
 5942                        (
 5943                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5944                            buffer.version().clone(),
 5945                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5946                        ),
 5947                    ))
 5948                }
 5949            })
 5950            .collect()
 5951    }
 5952
 5953    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5954        TextLayoutDetails {
 5955            text_system: window.text_system().clone(),
 5956            editor_style: self.style.clone().unwrap(),
 5957            rem_size: window.rem_size(),
 5958            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 5959            visible_rows: self.visible_line_count(),
 5960            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5961        }
 5962    }
 5963
 5964    fn trigger_on_type_formatting(
 5965        &self,
 5966        input: String,
 5967        window: &mut Window,
 5968        cx: &mut Context<Self>,
 5969    ) -> Option<Task<Result<()>>> {
 5970        if input.chars().count() != 1 {
 5971            return None;
 5972        }
 5973
 5974        let project = self.project()?;
 5975        let position = self.selections.newest_anchor().head();
 5976        let (buffer, buffer_position) = self
 5977            .buffer
 5978            .read(cx)
 5979            .text_anchor_for_position(position, cx)?;
 5980
 5981        let settings = LanguageSettings::for_buffer_at(&buffer.read(cx), buffer_position, cx);
 5982        if !settings.use_on_type_format {
 5983            return None;
 5984        }
 5985
 5986        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5987        // hence we do LSP request & edit on host side only — add formats to host's history.
 5988        let push_to_lsp_host_history = true;
 5989        // If this is not the host, append its history with new edits.
 5990        let push_to_client_history = project.read(cx).is_via_collab();
 5991
 5992        let on_type_formatting = project.update(cx, |project, cx| {
 5993            project.on_type_format(
 5994                buffer.clone(),
 5995                buffer_position,
 5996                input,
 5997                push_to_lsp_host_history,
 5998                cx,
 5999            )
 6000        });
 6001        Some(cx.spawn_in(window, async move |editor, cx| {
 6002            if let Some(transaction) = on_type_formatting.await? {
 6003                if push_to_client_history {
 6004                    buffer.update(cx, |buffer, _| {
 6005                        buffer.push_transaction(transaction, Instant::now());
 6006                        buffer.finalize_last_transaction();
 6007                    });
 6008                }
 6009                editor.update(cx, |editor, cx| {
 6010                    editor.refresh_document_highlights(cx);
 6011                })?;
 6012            }
 6013            Ok(())
 6014        }))
 6015    }
 6016
 6017    pub fn show_word_completions(
 6018        &mut self,
 6019        _: &ShowWordCompletions,
 6020        window: &mut Window,
 6021        cx: &mut Context<Self>,
 6022    ) {
 6023        self.open_or_update_completions_menu(
 6024            Some(CompletionsMenuSource::Words {
 6025                ignore_threshold: true,
 6026            }),
 6027            None,
 6028            false,
 6029            window,
 6030            cx,
 6031        );
 6032    }
 6033
 6034    pub fn show_completions(
 6035        &mut self,
 6036        _: &ShowCompletions,
 6037        window: &mut Window,
 6038        cx: &mut Context<Self>,
 6039    ) {
 6040        self.open_or_update_completions_menu(None, None, false, window, cx);
 6041    }
 6042
 6043    fn open_or_update_completions_menu(
 6044        &mut self,
 6045        requested_source: Option<CompletionsMenuSource>,
 6046        trigger: Option<String>,
 6047        trigger_in_words: bool,
 6048        window: &mut Window,
 6049        cx: &mut Context<Self>,
 6050    ) {
 6051        if self.pending_rename.is_some() {
 6052            return;
 6053        }
 6054
 6055        let completions_source = self
 6056            .context_menu
 6057            .borrow()
 6058            .as_ref()
 6059            .and_then(|menu| match menu {
 6060                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6061                CodeContextMenu::CodeActions(_) => None,
 6062            });
 6063
 6064        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6065
 6066        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6067        // inserted and selected. To handle that case, the start of the selection is used so that
 6068        // the menu starts with all choices.
 6069        let position = self
 6070            .selections
 6071            .newest_anchor()
 6072            .start
 6073            .bias_right(&multibuffer_snapshot);
 6074        if position.diff_base_anchor.is_some() {
 6075            return;
 6076        }
 6077        let buffer_position = multibuffer_snapshot.anchor_before(position);
 6078        let Some(buffer) = buffer_position
 6079            .text_anchor
 6080            .buffer_id
 6081            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 6082        else {
 6083            return;
 6084        };
 6085        let buffer_snapshot = buffer.read(cx).snapshot();
 6086
 6087        let menu_is_open = matches!(
 6088            self.context_menu.borrow().as_ref(),
 6089            Some(CodeContextMenu::Completions(_))
 6090        );
 6091
 6092        let language = buffer_snapshot
 6093            .language_at(buffer_position.text_anchor)
 6094            .map(|language| language.name());
 6095        let language_settings = multibuffer_snapshot.language_settings_at(buffer_position, cx);
 6096        let completion_settings = language_settings.completions.clone();
 6097
 6098        let show_completions_on_input = self
 6099            .show_completions_on_input_override
 6100            .unwrap_or(language_settings.show_completions_on_input);
 6101        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6102            return;
 6103        }
 6104
 6105        let query: Option<Arc<String>> =
 6106            Self::completion_query(&multibuffer_snapshot, buffer_position)
 6107                .map(|query| query.into());
 6108
 6109        drop(multibuffer_snapshot);
 6110
 6111        // Hide the current completions menu when query is empty. Without this, cached
 6112        // completions from before the trigger char may be reused (#32774).
 6113        if query.is_none() && menu_is_open {
 6114            self.hide_context_menu(window, cx);
 6115        }
 6116
 6117        let mut ignore_word_threshold = false;
 6118        let provider = match requested_source {
 6119            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6120            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6121                ignore_word_threshold = ignore_threshold;
 6122                None
 6123            }
 6124            Some(CompletionsMenuSource::SnippetChoices)
 6125            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6126                log::error!("bug: SnippetChoices requested_source is not handled");
 6127                None
 6128            }
 6129        };
 6130
 6131        let sort_completions = provider
 6132            .as_ref()
 6133            .is_some_and(|provider| provider.sort_completions());
 6134
 6135        let filter_completions = provider
 6136            .as_ref()
 6137            .is_none_or(|provider| provider.filter_completions());
 6138
 6139        let was_snippets_only = matches!(
 6140            completions_source,
 6141            Some(CompletionsMenuSource::SnippetsOnly)
 6142        );
 6143
 6144        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6145            if filter_completions {
 6146                menu.filter(
 6147                    query.clone().unwrap_or_default(),
 6148                    buffer_position.text_anchor,
 6149                    &buffer,
 6150                    provider.clone(),
 6151                    window,
 6152                    cx,
 6153                );
 6154            }
 6155            // When `is_incomplete` is false, no need to re-query completions when the current query
 6156            // is a suffix of the initial query.
 6157            let was_complete = !menu.is_incomplete;
 6158            if was_complete && !was_snippets_only {
 6159                // If the new query is a suffix of the old query (typing more characters) and
 6160                // the previous result was complete, the existing completions can be filtered.
 6161                //
 6162                // Note that snippet completions are always complete.
 6163                let query_matches = match (&menu.initial_query, &query) {
 6164                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6165                    (None, _) => true,
 6166                    _ => false,
 6167                };
 6168                if query_matches {
 6169                    let position_matches = if menu.initial_position == position {
 6170                        true
 6171                    } else {
 6172                        let snapshot = self.buffer.read(cx).read(cx);
 6173                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6174                    };
 6175                    if position_matches {
 6176                        return;
 6177                    }
 6178                }
 6179            }
 6180        };
 6181
 6182        let Anchor {
 6183            excerpt_id: buffer_excerpt_id,
 6184            text_anchor: buffer_position,
 6185            ..
 6186        } = buffer_position;
 6187
 6188        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6189            buffer_snapshot.surrounding_word(buffer_position, None)
 6190        {
 6191            let word_to_exclude = buffer_snapshot
 6192                .text_for_range(word_range.clone())
 6193                .collect::<String>();
 6194            (
 6195                buffer_snapshot.anchor_before(word_range.start)
 6196                    ..buffer_snapshot.anchor_after(buffer_position),
 6197                Some(word_to_exclude),
 6198            )
 6199        } else {
 6200            (buffer_position..buffer_position, None)
 6201        };
 6202
 6203        let show_completion_documentation = buffer_snapshot
 6204            .settings_at(buffer_position, cx)
 6205            .show_completion_documentation;
 6206
 6207        // The document can be large, so stay in reasonable bounds when searching for words,
 6208        // otherwise completion pop-up might be slow to appear.
 6209        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6210        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6211        let min_word_search = buffer_snapshot.clip_point(
 6212            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6213            Bias::Left,
 6214        );
 6215        let max_word_search = buffer_snapshot.clip_point(
 6216            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6217            Bias::Right,
 6218        );
 6219        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6220            ..buffer_snapshot.point_to_offset(max_word_search);
 6221
 6222        let skip_digits = query
 6223            .as_ref()
 6224            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6225
 6226        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6227            trigger.as_ref().is_none_or(|trigger| {
 6228                provider.is_completion_trigger(
 6229                    &buffer,
 6230                    position.text_anchor,
 6231                    trigger,
 6232                    trigger_in_words,
 6233                    cx,
 6234                )
 6235            })
 6236        });
 6237
 6238        let provider_responses = if let Some(provider) = &provider
 6239            && load_provider_completions
 6240        {
 6241            let trigger_character =
 6242                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6243            let completion_context = CompletionContext {
 6244                trigger_kind: match &trigger_character {
 6245                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6246                    None => CompletionTriggerKind::INVOKED,
 6247                },
 6248                trigger_character,
 6249            };
 6250
 6251            provider.completions(
 6252                buffer_excerpt_id,
 6253                &buffer,
 6254                buffer_position,
 6255                completion_context,
 6256                window,
 6257                cx,
 6258            )
 6259        } else {
 6260            Task::ready(Ok(Vec::new()))
 6261        };
 6262
 6263        let load_word_completions = if !self.word_completions_enabled {
 6264            false
 6265        } else if requested_source
 6266            == Some(CompletionsMenuSource::Words {
 6267                ignore_threshold: true,
 6268            })
 6269        {
 6270            true
 6271        } else {
 6272            load_provider_completions
 6273                && completion_settings.words != WordsCompletionMode::Disabled
 6274                && (ignore_word_threshold || {
 6275                    let words_min_length = completion_settings.words_min_length;
 6276                    // check whether word has at least `words_min_length` characters
 6277                    let query_chars = query.iter().flat_map(|q| q.chars());
 6278                    query_chars.take(words_min_length).count() == words_min_length
 6279                })
 6280        };
 6281
 6282        let mut words = if load_word_completions {
 6283            cx.background_spawn({
 6284                let buffer_snapshot = buffer_snapshot.clone();
 6285                async move {
 6286                    buffer_snapshot.words_in_range(WordsQuery {
 6287                        fuzzy_contents: None,
 6288                        range: word_search_range,
 6289                        skip_digits,
 6290                    })
 6291                }
 6292            })
 6293        } else {
 6294            Task::ready(BTreeMap::default())
 6295        };
 6296
 6297        let snippets = if let Some(provider) = &provider
 6298            && provider.show_snippets()
 6299            && let Some(project) = self.project()
 6300        {
 6301            let char_classifier = buffer_snapshot
 6302                .char_classifier_at(buffer_position)
 6303                .scope_context(Some(CharScopeContext::Completion));
 6304            project.update(cx, |project, cx| {
 6305                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6306            })
 6307        } else {
 6308            Task::ready(Ok(CompletionResponse {
 6309                completions: Vec::new(),
 6310                display_options: Default::default(),
 6311                is_incomplete: false,
 6312            }))
 6313        };
 6314
 6315        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6316
 6317        let id = post_inc(&mut self.next_completion_id);
 6318        let task = cx.spawn_in(window, async move |editor, cx| {
 6319            let Ok(()) = editor.update(cx, |this, _| {
 6320                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6321            }) else {
 6322                return;
 6323            };
 6324
 6325            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6326            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6327            let mut completions = Vec::new();
 6328            let mut is_incomplete = false;
 6329            let mut display_options: Option<CompletionDisplayOptions> = None;
 6330            if let Some(provider_responses) = provider_responses.await.log_err()
 6331                && !provider_responses.is_empty()
 6332            {
 6333                for response in provider_responses {
 6334                    completions.extend(response.completions);
 6335                    is_incomplete = is_incomplete || response.is_incomplete;
 6336                    match display_options.as_mut() {
 6337                        None => {
 6338                            display_options = Some(response.display_options);
 6339                        }
 6340                        Some(options) => options.merge(&response.display_options),
 6341                    }
 6342                }
 6343                if completion_settings.words == WordsCompletionMode::Fallback {
 6344                    words = Task::ready(BTreeMap::default());
 6345                }
 6346            }
 6347            let display_options = display_options.unwrap_or_default();
 6348
 6349            let mut words = words.await;
 6350            if let Some(word_to_exclude) = &word_to_exclude {
 6351                words.remove(word_to_exclude);
 6352            }
 6353            for lsp_completion in &completions {
 6354                words.remove(&lsp_completion.new_text);
 6355            }
 6356            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6357                replace_range: word_replace_range.clone(),
 6358                new_text: word.clone(),
 6359                label: CodeLabel::plain(word, None),
 6360                match_start: None,
 6361                snippet_deduplication_key: None,
 6362                icon_path: None,
 6363                documentation: None,
 6364                source: CompletionSource::BufferWord {
 6365                    word_range,
 6366                    resolved: false,
 6367                },
 6368                insert_text_mode: Some(InsertTextMode::AS_IS),
 6369                confirm: None,
 6370            }));
 6371
 6372            completions.extend(
 6373                snippets
 6374                    .await
 6375                    .into_iter()
 6376                    .flat_map(|response| response.completions),
 6377            );
 6378
 6379            let menu = if completions.is_empty() {
 6380                None
 6381            } else {
 6382                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6383                    let languages = editor
 6384                        .workspace
 6385                        .as_ref()
 6386                        .and_then(|(workspace, _)| workspace.upgrade())
 6387                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6388                    let menu = CompletionsMenu::new(
 6389                        id,
 6390                        requested_source.unwrap_or(if load_provider_completions {
 6391                            CompletionsMenuSource::Normal
 6392                        } else {
 6393                            CompletionsMenuSource::SnippetsOnly
 6394                        }),
 6395                        sort_completions,
 6396                        show_completion_documentation,
 6397                        position,
 6398                        query.clone(),
 6399                        is_incomplete,
 6400                        buffer.clone(),
 6401                        completions.into(),
 6402                        editor
 6403                            .context_menu()
 6404                            .borrow_mut()
 6405                            .as_ref()
 6406                            .map(|menu| menu.primary_scroll_handle()),
 6407                        display_options,
 6408                        snippet_sort_order,
 6409                        languages,
 6410                        language,
 6411                        cx,
 6412                    );
 6413
 6414                    let query = if filter_completions { query } else { None };
 6415                    let matches_task = menu.do_async_filtering(
 6416                        query.unwrap_or_default(),
 6417                        buffer_position,
 6418                        &buffer,
 6419                        cx,
 6420                    );
 6421                    (menu, matches_task)
 6422                }) else {
 6423                    return;
 6424                };
 6425
 6426                let matches = matches_task.await;
 6427
 6428                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6429                    // Newer menu already set, so exit.
 6430                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6431                        editor.context_menu.borrow().as_ref()
 6432                        && prev_menu.id > id
 6433                    {
 6434                        return;
 6435                    };
 6436
 6437                    // Only valid to take prev_menu because either the new menu is immediately set
 6438                    // below, or the menu is hidden.
 6439                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6440                        editor.context_menu.borrow_mut().take()
 6441                    {
 6442                        let position_matches =
 6443                            if prev_menu.initial_position == menu.initial_position {
 6444                                true
 6445                            } else {
 6446                                let snapshot = editor.buffer.read(cx).read(cx);
 6447                                prev_menu.initial_position.to_offset(&snapshot)
 6448                                    == menu.initial_position.to_offset(&snapshot)
 6449                            };
 6450                        if position_matches {
 6451                            // Preserve markdown cache before `set_filter_results` because it will
 6452                            // try to populate the documentation cache.
 6453                            menu.preserve_markdown_cache(prev_menu);
 6454                        }
 6455                    };
 6456
 6457                    menu.set_filter_results(matches, provider, window, cx);
 6458                }) else {
 6459                    return;
 6460                };
 6461
 6462                menu.visible().then_some(menu)
 6463            };
 6464
 6465            editor
 6466                .update_in(cx, |editor, window, cx| {
 6467                    if editor.focus_handle.is_focused(window)
 6468                        && let Some(menu) = menu
 6469                    {
 6470                        *editor.context_menu.borrow_mut() =
 6471                            Some(CodeContextMenu::Completions(menu));
 6472
 6473                        crate::hover_popover::hide_hover(editor, cx);
 6474                        if editor.show_edit_predictions_in_menu() {
 6475                            editor.update_visible_edit_prediction(window, cx);
 6476                        } else {
 6477                            editor
 6478                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6479                        }
 6480
 6481                        cx.notify();
 6482                        return;
 6483                    }
 6484
 6485                    if editor.completion_tasks.len() <= 1 {
 6486                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6487                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6488                        // If it was already hidden and we don't show edit predictions in the menu,
 6489                        // we should also show the edit prediction when available.
 6490                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6491                            editor.update_visible_edit_prediction(window, cx);
 6492                        }
 6493                    }
 6494                })
 6495                .ok();
 6496        });
 6497
 6498        self.completion_tasks.push((id, task));
 6499    }
 6500
 6501    #[cfg(any(test, feature = "test-support"))]
 6502    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6503        let menu = self.context_menu.borrow();
 6504        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6505            let completions = menu.completions.borrow();
 6506            Some(completions.to_vec())
 6507        } else {
 6508            None
 6509        }
 6510    }
 6511
 6512    pub fn with_completions_menu_matching_id<R>(
 6513        &self,
 6514        id: CompletionId,
 6515        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6516    ) -> R {
 6517        let mut context_menu = self.context_menu.borrow_mut();
 6518        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6519            return f(None);
 6520        };
 6521        if completions_menu.id != id {
 6522            return f(None);
 6523        }
 6524        f(Some(completions_menu))
 6525    }
 6526
 6527    pub fn confirm_completion(
 6528        &mut self,
 6529        action: &ConfirmCompletion,
 6530        window: &mut Window,
 6531        cx: &mut Context<Self>,
 6532    ) -> Option<Task<Result<()>>> {
 6533        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6534        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6535    }
 6536
 6537    pub fn confirm_completion_insert(
 6538        &mut self,
 6539        _: &ConfirmCompletionInsert,
 6540        window: &mut Window,
 6541        cx: &mut Context<Self>,
 6542    ) -> Option<Task<Result<()>>> {
 6543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6544        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6545    }
 6546
 6547    pub fn confirm_completion_replace(
 6548        &mut self,
 6549        _: &ConfirmCompletionReplace,
 6550        window: &mut Window,
 6551        cx: &mut Context<Self>,
 6552    ) -> Option<Task<Result<()>>> {
 6553        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6554        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6555    }
 6556
 6557    pub fn compose_completion(
 6558        &mut self,
 6559        action: &ComposeCompletion,
 6560        window: &mut Window,
 6561        cx: &mut Context<Self>,
 6562    ) -> Option<Task<Result<()>>> {
 6563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6564        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6565    }
 6566
 6567    fn do_completion(
 6568        &mut self,
 6569        item_ix: Option<usize>,
 6570        intent: CompletionIntent,
 6571        window: &mut Window,
 6572        cx: &mut Context<Editor>,
 6573    ) -> Option<Task<Result<()>>> {
 6574        use language::ToOffset as _;
 6575
 6576        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6577        else {
 6578            return None;
 6579        };
 6580
 6581        let candidate_id = {
 6582            let entries = completions_menu.entries.borrow();
 6583            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6584            if self.show_edit_predictions_in_menu() {
 6585                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6586            }
 6587            mat.candidate_id
 6588        };
 6589
 6590        let completion = completions_menu
 6591            .completions
 6592            .borrow()
 6593            .get(candidate_id)?
 6594            .clone();
 6595        cx.stop_propagation();
 6596
 6597        let buffer_handle = completions_menu.buffer.clone();
 6598
 6599        let CompletionEdit {
 6600            new_text,
 6601            snippet,
 6602            replace_range,
 6603        } = process_completion_for_edit(
 6604            &completion,
 6605            intent,
 6606            &buffer_handle,
 6607            &completions_menu.initial_position.text_anchor,
 6608            cx,
 6609        );
 6610
 6611        let buffer = buffer_handle.read(cx);
 6612        let snapshot = self.buffer.read(cx).snapshot(cx);
 6613        let newest_anchor = self.selections.newest_anchor();
 6614        let replace_range_multibuffer = {
 6615            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6616            excerpt.map_range_from_buffer(replace_range.clone())
 6617        };
 6618        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6619            return None;
 6620        }
 6621
 6622        let old_text = buffer
 6623            .text_for_range(replace_range.clone())
 6624            .collect::<String>();
 6625        let lookbehind = newest_anchor
 6626            .start
 6627            .text_anchor
 6628            .to_offset(buffer)
 6629            .saturating_sub(replace_range.start.0);
 6630        let lookahead = replace_range
 6631            .end
 6632            .0
 6633            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6634        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6635        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6636
 6637        let selections = self
 6638            .selections
 6639            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6640        let mut ranges = Vec::new();
 6641        let mut all_commit_ranges = Vec::new();
 6642        let mut linked_edits = LinkedEdits::new();
 6643
 6644        let text: Arc<str> = new_text.clone().into();
 6645        for selection in &selections {
 6646            let range = if selection.id == newest_anchor.id {
 6647                replace_range_multibuffer.clone()
 6648            } else {
 6649                let mut range = selection.range();
 6650
 6651                // if prefix is present, don't duplicate it
 6652                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6653                    range.start = range.start.saturating_sub_usize(lookbehind);
 6654
 6655                    // if suffix is also present, mimic the newest cursor and replace it
 6656                    if selection.id != newest_anchor.id
 6657                        && snapshot.contains_str_at(range.end, suffix)
 6658                    {
 6659                        range.end += lookahead;
 6660                    }
 6661                }
 6662                range
 6663            };
 6664
 6665            ranges.push(range.clone());
 6666
 6667            let start_anchor = snapshot.anchor_before(range.start);
 6668            let end_anchor = snapshot.anchor_after(range.end);
 6669            let anchor_range = start_anchor.text_anchor..end_anchor.text_anchor;
 6670            all_commit_ranges.push(anchor_range.clone());
 6671
 6672            if !self.linked_edit_ranges.is_empty() {
 6673                linked_edits.push(&self, anchor_range, text.clone(), cx);
 6674            }
 6675        }
 6676
 6677        let common_prefix_len = old_text
 6678            .chars()
 6679            .zip(new_text.chars())
 6680            .take_while(|(a, b)| a == b)
 6681            .map(|(a, _)| a.len_utf8())
 6682            .sum::<usize>();
 6683
 6684        cx.emit(EditorEvent::InputHandled {
 6685            utf16_range_to_replace: None,
 6686            text: new_text[common_prefix_len..].into(),
 6687        });
 6688
 6689        self.transact(window, cx, |editor, window, cx| {
 6690            if let Some(mut snippet) = snippet {
 6691                snippet.text = new_text.to_string();
 6692                editor
 6693                    .insert_snippet(&ranges, snippet, window, cx)
 6694                    .log_err();
 6695            } else {
 6696                editor.buffer.update(cx, |multi_buffer, cx| {
 6697                    let auto_indent = match completion.insert_text_mode {
 6698                        Some(InsertTextMode::AS_IS) => None,
 6699                        _ => editor.autoindent_mode.clone(),
 6700                    };
 6701                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6702                    multi_buffer.edit(edits, auto_indent, cx);
 6703                });
 6704            }
 6705            linked_edits.apply(cx);
 6706            editor.refresh_edit_prediction(true, false, window, cx);
 6707        });
 6708        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6709
 6710        let show_new_completions_on_confirm = completion
 6711            .confirm
 6712            .as_ref()
 6713            .is_some_and(|confirm| confirm(intent, window, cx));
 6714        if show_new_completions_on_confirm {
 6715            self.open_or_update_completions_menu(None, None, false, window, cx);
 6716        }
 6717
 6718        let provider = self.completion_provider.as_ref()?;
 6719
 6720        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6721        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6722            let CompletionSource::Lsp {
 6723                lsp_completion,
 6724                server_id,
 6725                ..
 6726            } = &completion.source
 6727            else {
 6728                return None;
 6729            };
 6730            let lsp_command = lsp_completion.command.as_ref()?;
 6731            let available_commands = lsp_store
 6732                .read(cx)
 6733                .lsp_server_capabilities
 6734                .get(server_id)
 6735                .and_then(|server_capabilities| {
 6736                    server_capabilities
 6737                        .execute_command_provider
 6738                        .as_ref()
 6739                        .map(|options| options.commands.as_slice())
 6740                })?;
 6741            if available_commands.contains(&lsp_command.command) {
 6742                Some(CodeAction {
 6743                    server_id: *server_id,
 6744                    range: language::Anchor::MIN..language::Anchor::MIN,
 6745                    lsp_action: LspAction::Command(lsp_command.clone()),
 6746                    resolved: false,
 6747                })
 6748            } else {
 6749                None
 6750            }
 6751        });
 6752
 6753        drop(completion);
 6754        let apply_edits = provider.apply_additional_edits_for_completion(
 6755            buffer_handle.clone(),
 6756            completions_menu.completions.clone(),
 6757            candidate_id,
 6758            true,
 6759            all_commit_ranges,
 6760            cx,
 6761        );
 6762
 6763        let editor_settings = EditorSettings::get_global(cx);
 6764        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6765            // After the code completion is finished, users often want to know what signatures are needed.
 6766            // so we should automatically call signature_help
 6767            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6768        }
 6769
 6770        Some(cx.spawn_in(window, async move |editor, cx| {
 6771            apply_edits.await?;
 6772
 6773            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6774                let title = command.lsp_action.title().to_owned();
 6775                let project_transaction = lsp_store
 6776                    .update(cx, |lsp_store, cx| {
 6777                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6778                    })
 6779                    .await
 6780                    .context("applying post-completion command")?;
 6781                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6782                    Self::open_project_transaction(
 6783                        &editor,
 6784                        workspace.downgrade(),
 6785                        project_transaction,
 6786                        title,
 6787                        cx,
 6788                    )
 6789                    .await?;
 6790                }
 6791            }
 6792
 6793            Ok(())
 6794        }))
 6795    }
 6796
 6797    pub fn toggle_code_actions(
 6798        &mut self,
 6799        action: &ToggleCodeActions,
 6800        window: &mut Window,
 6801        cx: &mut Context<Self>,
 6802    ) {
 6803        let quick_launch = action.quick_launch;
 6804        let mut context_menu = self.context_menu.borrow_mut();
 6805        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6806            if code_actions.deployed_from == action.deployed_from {
 6807                // Toggle if we're selecting the same one
 6808                *context_menu = None;
 6809                cx.notify();
 6810                return;
 6811            } else {
 6812                // Otherwise, clear it and start a new one
 6813                *context_menu = None;
 6814                cx.notify();
 6815            }
 6816        }
 6817        drop(context_menu);
 6818        let snapshot = self.snapshot(window, cx);
 6819        let deployed_from = action.deployed_from.clone();
 6820        let action = action.clone();
 6821        self.completion_tasks.clear();
 6822        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6823
 6824        let multibuffer_point = match &action.deployed_from {
 6825            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6826                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6827            }
 6828            _ => self
 6829                .selections
 6830                .newest::<Point>(&snapshot.display_snapshot)
 6831                .head(),
 6832        };
 6833        let Some((buffer, buffer_row)) = snapshot
 6834            .buffer_snapshot()
 6835            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6836            .and_then(|(buffer_snapshot, range)| {
 6837                self.buffer()
 6838                    .read(cx)
 6839                    .buffer(buffer_snapshot.remote_id())
 6840                    .map(|buffer| (buffer, range.start.row))
 6841            })
 6842        else {
 6843            return;
 6844        };
 6845        let buffer_id = buffer.read(cx).remote_id();
 6846        let tasks = self
 6847            .runnables
 6848            .runnables((buffer_id, buffer_row))
 6849            .map(|t| Arc::new(t.to_owned()));
 6850
 6851        if !self.focus_handle.is_focused(window) {
 6852            return;
 6853        }
 6854        let project = self.project.clone();
 6855
 6856        let code_actions_task = match deployed_from {
 6857            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6858            _ => self.code_actions(buffer_row, window, cx),
 6859        };
 6860
 6861        let runnable_task = match deployed_from {
 6862            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6863            _ => {
 6864                let mut task_context_task = Task::ready(None);
 6865                if let Some(tasks) = &tasks
 6866                    && let Some(project) = project
 6867                {
 6868                    task_context_task =
 6869                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6870                }
 6871
 6872                cx.spawn_in(window, {
 6873                    let buffer = buffer.clone();
 6874                    async move |editor, cx| {
 6875                        let task_context = task_context_task.await;
 6876
 6877                        let resolved_tasks =
 6878                            tasks
 6879                                .zip(task_context.clone())
 6880                                .map(|(tasks, task_context)| ResolvedTasks {
 6881                                    templates: tasks.resolve(&task_context).collect(),
 6882                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6883                                        multibuffer_point.row,
 6884                                        tasks.column,
 6885                                    )),
 6886                                });
 6887                        let debug_scenarios = editor
 6888                            .update(cx, |editor, cx| {
 6889                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6890                            })?
 6891                            .await;
 6892                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6893                    }
 6894                })
 6895            }
 6896        };
 6897
 6898        cx.spawn_in(window, async move |editor, cx| {
 6899            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6900            let code_actions = code_actions_task.await;
 6901            let spawn_straight_away = quick_launch
 6902                && resolved_tasks
 6903                    .as_ref()
 6904                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6905                && code_actions
 6906                    .as_ref()
 6907                    .is_none_or(|actions| actions.is_empty())
 6908                && debug_scenarios.is_empty();
 6909
 6910            editor.update_in(cx, |editor, window, cx| {
 6911                crate::hover_popover::hide_hover(editor, cx);
 6912                let actions = CodeActionContents::new(
 6913                    resolved_tasks,
 6914                    code_actions,
 6915                    debug_scenarios,
 6916                    task_context.unwrap_or_default(),
 6917                );
 6918
 6919                // Don't show the menu if there are no actions available
 6920                if actions.is_empty() {
 6921                    cx.notify();
 6922                    return Task::ready(Ok(()));
 6923                }
 6924
 6925                *editor.context_menu.borrow_mut() =
 6926                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6927                        buffer,
 6928                        actions,
 6929                        selected_item: Default::default(),
 6930                        scroll_handle: UniformListScrollHandle::default(),
 6931                        deployed_from,
 6932                    }));
 6933                cx.notify();
 6934                if spawn_straight_away
 6935                    && let Some(task) = editor.confirm_code_action(
 6936                        &ConfirmCodeAction { item_ix: Some(0) },
 6937                        window,
 6938                        cx,
 6939                    )
 6940                {
 6941                    return task;
 6942                }
 6943
 6944                Task::ready(Ok(()))
 6945            })
 6946        })
 6947        .detach_and_log_err(cx);
 6948    }
 6949
 6950    fn debug_scenarios(
 6951        &mut self,
 6952        resolved_tasks: &Option<ResolvedTasks>,
 6953        buffer: &Entity<Buffer>,
 6954        cx: &mut App,
 6955    ) -> Task<Vec<task::DebugScenario>> {
 6956        maybe!({
 6957            let project = self.project()?;
 6958            let dap_store = project.read(cx).dap_store();
 6959            let mut scenarios = vec![];
 6960            let resolved_tasks = resolved_tasks.as_ref()?;
 6961            let buffer = buffer.read(cx);
 6962            let language = buffer.language()?;
 6963            let debug_adapter = LanguageSettings::for_buffer(&buffer, cx)
 6964                .debuggers
 6965                .first()
 6966                .map(SharedString::from)
 6967                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6968
 6969            dap_store.update(cx, |dap_store, cx| {
 6970                for (_, task) in &resolved_tasks.templates {
 6971                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6972                        task.original_task().clone(),
 6973                        debug_adapter.clone().into(),
 6974                        task.display_label().to_owned().into(),
 6975                        cx,
 6976                    );
 6977                    scenarios.push(maybe_scenario);
 6978                }
 6979            });
 6980            Some(cx.background_spawn(async move {
 6981                futures::future::join_all(scenarios)
 6982                    .await
 6983                    .into_iter()
 6984                    .flatten()
 6985                    .collect::<Vec<_>>()
 6986            }))
 6987        })
 6988        .unwrap_or_else(|| Task::ready(vec![]))
 6989    }
 6990
 6991    fn code_actions(
 6992        &mut self,
 6993        buffer_row: u32,
 6994        window: &mut Window,
 6995        cx: &mut Context<Self>,
 6996    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6997        let mut task = self.code_actions_task.take();
 6998        cx.spawn_in(window, async move |editor, cx| {
 6999            while let Some(prev_task) = task {
 7000                prev_task.await.log_err();
 7001                task = editor
 7002                    .update(cx, |this, _| this.code_actions_task.take())
 7003                    .ok()?;
 7004            }
 7005
 7006            editor
 7007                .update(cx, |editor, cx| {
 7008                    editor
 7009                        .available_code_actions
 7010                        .clone()
 7011                        .and_then(|(location, code_actions)| {
 7012                            let snapshot = location.buffer.read(cx).snapshot();
 7013                            let point_range = location.range.to_point(&snapshot);
 7014                            let point_range = point_range.start.row..=point_range.end.row;
 7015                            if point_range.contains(&buffer_row) {
 7016                                Some(code_actions)
 7017                            } else {
 7018                                None
 7019                            }
 7020                        })
 7021                })
 7022                .ok()
 7023                .flatten()
 7024        })
 7025    }
 7026
 7027    pub fn confirm_code_action(
 7028        &mut self,
 7029        action: &ConfirmCodeAction,
 7030        window: &mut Window,
 7031        cx: &mut Context<Self>,
 7032    ) -> Option<Task<Result<()>>> {
 7033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7034
 7035        let actions_menu =
 7036            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7037                menu
 7038            } else {
 7039                return None;
 7040            };
 7041
 7042        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7043        let action = actions_menu.actions.get(action_ix)?;
 7044        let title = action.label();
 7045        let buffer = actions_menu.buffer;
 7046        let workspace = self.workspace()?;
 7047
 7048        match action {
 7049            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7050                workspace.update(cx, |workspace, cx| {
 7051                    workspace.schedule_resolved_task(
 7052                        task_source_kind,
 7053                        resolved_task,
 7054                        false,
 7055                        window,
 7056                        cx,
 7057                    );
 7058
 7059                    Some(Task::ready(Ok(())))
 7060                })
 7061            }
 7062            CodeActionsItem::CodeAction {
 7063                excerpt_id,
 7064                action,
 7065                provider,
 7066            } => {
 7067                let apply_code_action =
 7068                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 7069                let workspace = workspace.downgrade();
 7070                Some(cx.spawn_in(window, async move |editor, cx| {
 7071                    let project_transaction = apply_code_action.await?;
 7072                    Self::open_project_transaction(
 7073                        &editor,
 7074                        workspace,
 7075                        project_transaction,
 7076                        title,
 7077                        cx,
 7078                    )
 7079                    .await
 7080                }))
 7081            }
 7082            CodeActionsItem::DebugScenario(scenario) => {
 7083                let context = actions_menu.actions.context.into();
 7084
 7085                workspace.update(cx, |workspace, cx| {
 7086                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7087                    workspace.start_debug_session(
 7088                        scenario,
 7089                        context,
 7090                        Some(buffer),
 7091                        None,
 7092                        window,
 7093                        cx,
 7094                    );
 7095                });
 7096                Some(Task::ready(Ok(())))
 7097            }
 7098        }
 7099    }
 7100
 7101    fn open_transaction_for_hidden_buffers(
 7102        workspace: Entity<Workspace>,
 7103        transaction: ProjectTransaction,
 7104        title: String,
 7105        window: &mut Window,
 7106        cx: &mut Context<Self>,
 7107    ) {
 7108        if transaction.0.is_empty() {
 7109            return;
 7110        }
 7111
 7112        let edited_buffers_already_open = {
 7113            let other_editors: Vec<Entity<Editor>> = workspace
 7114                .read(cx)
 7115                .panes()
 7116                .iter()
 7117                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7118                .filter(|editor| editor.entity_id() != cx.entity_id())
 7119                .collect();
 7120
 7121            transaction.0.keys().all(|buffer| {
 7122                other_editors.iter().any(|editor| {
 7123                    let multi_buffer = editor.read(cx).buffer();
 7124                    multi_buffer.read(cx).is_singleton()
 7125                        && multi_buffer
 7126                            .read(cx)
 7127                            .as_singleton()
 7128                            .map_or(false, |singleton| {
 7129                                singleton.entity_id() == buffer.entity_id()
 7130                            })
 7131                })
 7132            })
 7133        };
 7134        if !edited_buffers_already_open {
 7135            let workspace = workspace.downgrade();
 7136            cx.defer_in(window, move |_, window, cx| {
 7137                cx.spawn_in(window, async move |editor, cx| {
 7138                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7139                        .await
 7140                        .ok()
 7141                })
 7142                .detach();
 7143            });
 7144        }
 7145    }
 7146
 7147    pub async fn open_project_transaction(
 7148        editor: &WeakEntity<Editor>,
 7149        workspace: WeakEntity<Workspace>,
 7150        transaction: ProjectTransaction,
 7151        title: String,
 7152        cx: &mut AsyncWindowContext,
 7153    ) -> Result<()> {
 7154        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7155        cx.update(|_, cx| {
 7156            entries.sort_unstable_by_key(|(buffer, _)| {
 7157                buffer.read(cx).file().map(|f| f.path().clone())
 7158            });
 7159        })?;
 7160        if entries.is_empty() {
 7161            return Ok(());
 7162        }
 7163
 7164        // If the project transaction's edits are all contained within this editor, then
 7165        // avoid opening a new editor to display them.
 7166
 7167        if let [(buffer, transaction)] = &*entries {
 7168            let excerpt = editor.update(cx, |editor, cx| {
 7169                editor
 7170                    .buffer()
 7171                    .read(cx)
 7172                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 7173            })?;
 7174            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 7175                && excerpted_buffer == *buffer
 7176            {
 7177                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7178                    let excerpt_range = excerpt_range.to_offset(buffer);
 7179                    buffer
 7180                        .edited_ranges_for_transaction::<usize>(transaction)
 7181                        .all(|range| {
 7182                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7183                        })
 7184                });
 7185
 7186                if all_edits_within_excerpt {
 7187                    return Ok(());
 7188                }
 7189            }
 7190        }
 7191
 7192        let mut ranges_to_highlight = Vec::new();
 7193        let excerpt_buffer = cx.new(|cx| {
 7194            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7195            for (buffer_handle, transaction) in &entries {
 7196                let edited_ranges = buffer_handle
 7197                    .read(cx)
 7198                    .edited_ranges_for_transaction::<Point>(transaction)
 7199                    .collect::<Vec<_>>();
 7200                let (ranges, _) = multibuffer.set_excerpts_for_path(
 7201                    PathKey::for_buffer(buffer_handle, cx),
 7202                    buffer_handle.clone(),
 7203                    edited_ranges,
 7204                    multibuffer_context_lines(cx),
 7205                    cx,
 7206                );
 7207
 7208                ranges_to_highlight.extend(ranges);
 7209            }
 7210            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7211            multibuffer
 7212        });
 7213
 7214        workspace.update_in(cx, |workspace, window, cx| {
 7215            let project = workspace.project().clone();
 7216            let editor =
 7217                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7218            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7219            editor.update(cx, |editor, cx| {
 7220                editor.highlight_background(
 7221                    HighlightKey::Editor,
 7222                    &ranges_to_highlight,
 7223                    |_, theme| theme.colors().editor_highlighted_line_background,
 7224                    cx,
 7225                );
 7226            });
 7227        })?;
 7228
 7229        Ok(())
 7230    }
 7231
 7232    pub fn clear_code_action_providers(&mut self) {
 7233        self.code_action_providers.clear();
 7234        self.available_code_actions.take();
 7235    }
 7236
 7237    pub fn add_code_action_provider(
 7238        &mut self,
 7239        provider: Rc<dyn CodeActionProvider>,
 7240        window: &mut Window,
 7241        cx: &mut Context<Self>,
 7242    ) {
 7243        if self
 7244            .code_action_providers
 7245            .iter()
 7246            .any(|existing_provider| existing_provider.id() == provider.id())
 7247        {
 7248            return;
 7249        }
 7250
 7251        self.code_action_providers.push(provider);
 7252        self.refresh_code_actions(window, cx);
 7253    }
 7254
 7255    pub fn remove_code_action_provider(
 7256        &mut self,
 7257        id: Arc<str>,
 7258        window: &mut Window,
 7259        cx: &mut Context<Self>,
 7260    ) {
 7261        self.code_action_providers
 7262            .retain(|provider| provider.id() != id);
 7263        self.refresh_code_actions(window, cx);
 7264    }
 7265
 7266    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7267        !self.code_action_providers.is_empty()
 7268            && EditorSettings::get_global(cx).toolbar.code_actions
 7269    }
 7270
 7271    pub fn has_available_code_actions(&self) -> bool {
 7272        self.available_code_actions
 7273            .as_ref()
 7274            .is_some_and(|(_, actions)| !actions.is_empty())
 7275    }
 7276
 7277    fn render_inline_code_actions(
 7278        &self,
 7279        icon_size: ui::IconSize,
 7280        display_row: DisplayRow,
 7281        is_active: bool,
 7282        cx: &mut Context<Self>,
 7283    ) -> AnyElement {
 7284        let show_tooltip = !self.context_menu_visible();
 7285        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7286            .icon_size(icon_size)
 7287            .shape(ui::IconButtonShape::Square)
 7288            .icon_color(ui::Color::Hidden)
 7289            .toggle_state(is_active)
 7290            .when(show_tooltip, |this| {
 7291                this.tooltip({
 7292                    let focus_handle = self.focus_handle.clone();
 7293                    move |_window, cx| {
 7294                        Tooltip::for_action_in(
 7295                            "Toggle Code Actions",
 7296                            &ToggleCodeActions {
 7297                                deployed_from: None,
 7298                                quick_launch: false,
 7299                            },
 7300                            &focus_handle,
 7301                            cx,
 7302                        )
 7303                    }
 7304                })
 7305            })
 7306            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7307                window.focus(&editor.focus_handle(cx), cx);
 7308                editor.toggle_code_actions(
 7309                    &crate::actions::ToggleCodeActions {
 7310                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7311                            display_row,
 7312                        )),
 7313                        quick_launch: false,
 7314                    },
 7315                    window,
 7316                    cx,
 7317                );
 7318            }))
 7319            .into_any_element()
 7320    }
 7321
 7322    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7323        &self.context_menu
 7324    }
 7325
 7326    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7327        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7328            cx.background_executor()
 7329                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7330                .await;
 7331
 7332            let (start_buffer, start, _, end, newest_selection) = this
 7333                .update(cx, |this, cx| {
 7334                    let newest_selection = this.selections.newest_anchor().clone();
 7335                    if newest_selection.head().diff_base_anchor.is_some() {
 7336                        return None;
 7337                    }
 7338                    let display_snapshot = this.display_snapshot(cx);
 7339                    let newest_selection_adjusted =
 7340                        this.selections.newest_adjusted(&display_snapshot);
 7341                    let buffer = this.buffer.read(cx);
 7342
 7343                    let (start_buffer, start) =
 7344                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7345                    let (end_buffer, end) =
 7346                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7347
 7348                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7349                })?
 7350                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7351                .context(
 7352                    "Expected selection to lie in a single buffer when refreshing code actions",
 7353                )?;
 7354            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7355                let providers = this.code_action_providers.clone();
 7356                let tasks = this
 7357                    .code_action_providers
 7358                    .iter()
 7359                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7360                    .collect::<Vec<_>>();
 7361                (providers, tasks)
 7362            })?;
 7363
 7364            let mut actions = Vec::new();
 7365            for (provider, provider_actions) in
 7366                providers.into_iter().zip(future::join_all(tasks).await)
 7367            {
 7368                if let Some(provider_actions) = provider_actions.log_err() {
 7369                    actions.extend(provider_actions.into_iter().map(|action| {
 7370                        AvailableCodeAction {
 7371                            excerpt_id: newest_selection.start.excerpt_id,
 7372                            action,
 7373                            provider: provider.clone(),
 7374                        }
 7375                    }));
 7376                }
 7377            }
 7378
 7379            this.update(cx, |this, cx| {
 7380                this.available_code_actions = if actions.is_empty() {
 7381                    None
 7382                } else {
 7383                    Some((
 7384                        Location {
 7385                            buffer: start_buffer,
 7386                            range: start..end,
 7387                        },
 7388                        actions.into(),
 7389                    ))
 7390                };
 7391                cx.notify();
 7392            })
 7393        }));
 7394    }
 7395
 7396    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7397        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7398            self.show_git_blame_inline = false;
 7399
 7400            self.show_git_blame_inline_delay_task =
 7401                Some(cx.spawn_in(window, async move |this, cx| {
 7402                    cx.background_executor().timer(delay).await;
 7403
 7404                    this.update(cx, |this, cx| {
 7405                        this.show_git_blame_inline = true;
 7406                        cx.notify();
 7407                    })
 7408                    .log_err();
 7409                }));
 7410        }
 7411    }
 7412
 7413    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7414        let snapshot = self.snapshot(window, cx);
 7415        let cursor = self
 7416            .selections
 7417            .newest::<Point>(&snapshot.display_snapshot)
 7418            .head();
 7419        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7420        else {
 7421            return;
 7422        };
 7423
 7424        if self.blame.is_none() {
 7425            self.start_git_blame(true, window, cx);
 7426        }
 7427        let Some(blame) = self.blame.as_ref() else {
 7428            return;
 7429        };
 7430
 7431        let row_info = RowInfo {
 7432            buffer_id: Some(buffer.remote_id()),
 7433            buffer_row: Some(point.row),
 7434            ..Default::default()
 7435        };
 7436        let Some((buffer, blame_entry)) = blame
 7437            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7438            .flatten()
 7439        else {
 7440            return;
 7441        };
 7442
 7443        let anchor = self.selections.newest_anchor().head();
 7444        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7445        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7446            self.show_blame_popover(
 7447                buffer,
 7448                &blame_entry,
 7449                position + last_bounds.origin,
 7450                true,
 7451                cx,
 7452            );
 7453        };
 7454    }
 7455
 7456    fn show_blame_popover(
 7457        &mut self,
 7458        buffer: BufferId,
 7459        blame_entry: &BlameEntry,
 7460        position: gpui::Point<Pixels>,
 7461        ignore_timeout: bool,
 7462        cx: &mut Context<Self>,
 7463    ) {
 7464        if let Some(state) = &mut self.inline_blame_popover {
 7465            state.hide_task.take();
 7466        } else {
 7467            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7468            let blame_entry = blame_entry.clone();
 7469            let show_task = cx.spawn(async move |editor, cx| {
 7470                if !ignore_timeout {
 7471                    cx.background_executor()
 7472                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7473                        .await;
 7474                }
 7475                editor
 7476                    .update(cx, |editor, cx| {
 7477                        editor.inline_blame_popover_show_task.take();
 7478                        let Some(blame) = editor.blame.as_ref() else {
 7479                            return;
 7480                        };
 7481                        let blame = blame.read(cx);
 7482                        let details = blame.details_for_entry(buffer, &blame_entry);
 7483                        let markdown = cx.new(|cx| {
 7484                            Markdown::new(
 7485                                details
 7486                                    .as_ref()
 7487                                    .map(|message| message.message.clone())
 7488                                    .unwrap_or_default(),
 7489                                None,
 7490                                None,
 7491                                cx,
 7492                            )
 7493                        });
 7494                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7495                            position,
 7496                            hide_task: None,
 7497                            popover_bounds: None,
 7498                            popover_state: InlineBlamePopoverState {
 7499                                scroll_handle: ScrollHandle::new(),
 7500                                commit_message: details,
 7501                                markdown,
 7502                            },
 7503                            keyboard_grace: ignore_timeout,
 7504                        });
 7505                        cx.notify();
 7506                    })
 7507                    .ok();
 7508            });
 7509            self.inline_blame_popover_show_task = Some(show_task);
 7510        }
 7511    }
 7512
 7513    pub fn has_mouse_context_menu(&self) -> bool {
 7514        self.mouse_context_menu.is_some()
 7515    }
 7516
 7517    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7518        self.inline_blame_popover_show_task.take();
 7519        if let Some(state) = &mut self.inline_blame_popover {
 7520            let hide_task = cx.spawn(async move |editor, cx| {
 7521                if !ignore_timeout {
 7522                    cx.background_executor()
 7523                        .timer(std::time::Duration::from_millis(100))
 7524                        .await;
 7525                }
 7526                editor
 7527                    .update(cx, |editor, cx| {
 7528                        editor.inline_blame_popover.take();
 7529                        cx.notify();
 7530                    })
 7531                    .ok();
 7532            });
 7533            state.hide_task = Some(hide_task);
 7534            true
 7535        } else {
 7536            false
 7537        }
 7538    }
 7539
 7540    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7541        if self.pending_rename.is_some() {
 7542            return None;
 7543        }
 7544
 7545        let provider = self.semantics_provider.clone()?;
 7546        let buffer = self.buffer.read(cx);
 7547        let newest_selection = self.selections.newest_anchor().clone();
 7548        let cursor_position = newest_selection.head();
 7549        let (cursor_buffer, cursor_buffer_position) =
 7550            buffer.text_anchor_for_position(cursor_position, cx)?;
 7551        let (tail_buffer, tail_buffer_position) =
 7552            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7553        if cursor_buffer != tail_buffer {
 7554            return None;
 7555        }
 7556
 7557        let snapshot = cursor_buffer.read(cx).snapshot();
 7558        let word_ranges = cx.background_spawn(async move {
 7559            // this might look odd to put on the background thread, but
 7560            // `surrounding_word` can be quite expensive as it calls into
 7561            // tree-sitter language scopes
 7562            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7563            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7564            (start_word_range, end_word_range)
 7565        });
 7566
 7567        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7568        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7569            let (start_word_range, end_word_range) = word_ranges.await;
 7570            if start_word_range != end_word_range {
 7571                this.update(cx, |this, cx| {
 7572                    this.document_highlights_task.take();
 7573                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7574                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7575                })
 7576                .ok();
 7577                return;
 7578            }
 7579            cx.background_executor()
 7580                .timer(Duration::from_millis(debounce))
 7581                .await;
 7582
 7583            let highlights = if let Some(highlights) = cx.update(|cx| {
 7584                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7585            }) {
 7586                highlights.await.log_err()
 7587            } else {
 7588                None
 7589            };
 7590
 7591            if let Some(highlights) = highlights {
 7592                this.update(cx, |this, cx| {
 7593                    if this.pending_rename.is_some() {
 7594                        return;
 7595                    }
 7596
 7597                    let buffer = this.buffer.read(cx);
 7598                    if buffer
 7599                        .text_anchor_for_position(cursor_position, cx)
 7600                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7601                    {
 7602                        return;
 7603                    }
 7604
 7605                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7606                    let mut write_ranges = Vec::new();
 7607                    let mut read_ranges = Vec::new();
 7608                    for highlight in highlights {
 7609                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7610                        for (excerpt_id, _, excerpt_range) in
 7611                            buffer.excerpts_for_buffer(buffer_id, cx)
 7612                        {
 7613                            let start = highlight
 7614                                .range
 7615                                .start
 7616                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7617                            let end = highlight
 7618                                .range
 7619                                .end
 7620                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7621                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7622                                continue;
 7623                            }
 7624
 7625                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7626                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7627                                write_ranges.push(range);
 7628                            } else {
 7629                                read_ranges.push(range);
 7630                            }
 7631                        }
 7632                    }
 7633
 7634                    this.highlight_background(
 7635                        HighlightKey::DocumentHighlightRead,
 7636                        &read_ranges,
 7637                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7638                        cx,
 7639                    );
 7640                    this.highlight_background(
 7641                        HighlightKey::DocumentHighlightWrite,
 7642                        &write_ranges,
 7643                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7644                        cx,
 7645                    );
 7646                    cx.notify();
 7647                })
 7648                .log_err();
 7649            }
 7650        }));
 7651        None
 7652    }
 7653
 7654    fn prepare_highlight_query_from_selection(
 7655        &mut self,
 7656        snapshot: &DisplaySnapshot,
 7657        cx: &mut Context<Editor>,
 7658    ) -> Option<(String, Range<Anchor>)> {
 7659        if matches!(self.mode, EditorMode::SingleLine) {
 7660            return None;
 7661        }
 7662        if !EditorSettings::get_global(cx).selection_highlight {
 7663            return None;
 7664        }
 7665        if self.selections.count() != 1 || self.selections.line_mode() {
 7666            return None;
 7667        }
 7668        let selection = self.selections.newest::<Point>(&snapshot);
 7669        // If the selection spans multiple rows OR it is empty
 7670        if selection.start.row != selection.end.row
 7671            || selection.start.column == selection.end.column
 7672        {
 7673            return None;
 7674        }
 7675        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7676        let query = snapshot
 7677            .buffer_snapshot()
 7678            .text_for_range(selection_anchor_range.clone())
 7679            .collect::<String>();
 7680        if query.trim().is_empty() {
 7681            return None;
 7682        }
 7683        Some((query, selection_anchor_range))
 7684    }
 7685
 7686    #[ztracing::instrument(skip_all)]
 7687    fn update_selection_occurrence_highlights(
 7688        &mut self,
 7689        multi_buffer_snapshot: MultiBufferSnapshot,
 7690        query_text: String,
 7691        query_range: Range<Anchor>,
 7692        multi_buffer_range_to_query: Range<Point>,
 7693        use_debounce: bool,
 7694        window: &mut Window,
 7695        cx: &mut Context<Editor>,
 7696    ) -> Task<()> {
 7697        cx.spawn_in(window, async move |editor, cx| {
 7698            if use_debounce {
 7699                cx.background_executor()
 7700                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7701                    .await;
 7702            }
 7703            let match_task = cx.background_spawn(async move {
 7704                let buffer_ranges = multi_buffer_snapshot
 7705                    .range_to_buffer_ranges(
 7706                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7707                    )
 7708                    .into_iter()
 7709                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7710                let mut match_ranges = Vec::new();
 7711                let Ok(regex) = project::search::SearchQuery::text(
 7712                    query_text,
 7713                    false,
 7714                    false,
 7715                    false,
 7716                    Default::default(),
 7717                    Default::default(),
 7718                    false,
 7719                    None,
 7720                ) else {
 7721                    return Vec::default();
 7722                };
 7723                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7724                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7725                    match_ranges.extend(
 7726                        regex
 7727                            .search(
 7728                                buffer_snapshot,
 7729                                Some(search_range.start.0..search_range.end.0),
 7730                            )
 7731                            .await
 7732                            .into_iter()
 7733                            .filter_map(|match_range| {
 7734                                let match_start = buffer_snapshot
 7735                                    .anchor_after(search_range.start + match_range.start);
 7736                                let match_end = buffer_snapshot
 7737                                    .anchor_before(search_range.start + match_range.end);
 7738                                let match_anchor_range =
 7739                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7740                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7741                            }),
 7742                    );
 7743                }
 7744                match_ranges
 7745            });
 7746            let match_ranges = match_task.await;
 7747            editor
 7748                .update_in(cx, |editor, _, cx| {
 7749                    if use_debounce {
 7750                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7751                        editor.debounced_selection_highlight_complete = true;
 7752                    } else if editor.debounced_selection_highlight_complete {
 7753                        return;
 7754                    }
 7755                    if !match_ranges.is_empty() {
 7756                        editor.highlight_background(
 7757                            HighlightKey::SelectedTextHighlight,
 7758                            &match_ranges,
 7759                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7760                            cx,
 7761                        )
 7762                    }
 7763                })
 7764                .log_err();
 7765        })
 7766    }
 7767
 7768    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7769        struct NewlineFold;
 7770        let type_id = std::any::TypeId::of::<NewlineFold>();
 7771        if !self.mode.is_single_line() {
 7772            return;
 7773        }
 7774        let snapshot = self.snapshot(window, cx);
 7775        if snapshot.buffer_snapshot().max_point().row == 0 {
 7776            return;
 7777        }
 7778        let task = cx.background_spawn(async move {
 7779            let new_newlines = snapshot
 7780                .buffer_chars_at(MultiBufferOffset(0))
 7781                .filter_map(|(c, i)| {
 7782                    if c == '\n' {
 7783                        Some(
 7784                            snapshot.buffer_snapshot().anchor_after(i)
 7785                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7786                        )
 7787                    } else {
 7788                        None
 7789                    }
 7790                })
 7791                .collect::<Vec<_>>();
 7792            let existing_newlines = snapshot
 7793                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7794                .filter_map(|fold| {
 7795                    if fold.placeholder.type_tag == Some(type_id) {
 7796                        Some(fold.range.start..fold.range.end)
 7797                    } else {
 7798                        None
 7799                    }
 7800                })
 7801                .collect::<Vec<_>>();
 7802
 7803            (new_newlines, existing_newlines)
 7804        });
 7805        self.folding_newlines = cx.spawn(async move |this, cx| {
 7806            let (new_newlines, existing_newlines) = task.await;
 7807            if new_newlines == existing_newlines {
 7808                return;
 7809            }
 7810            let placeholder = FoldPlaceholder {
 7811                render: Arc::new(move |_, _, cx| {
 7812                    div()
 7813                        .bg(cx.theme().status().hint_background)
 7814                        .border_b_1()
 7815                        .size_full()
 7816                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7817                        .border_color(cx.theme().status().hint)
 7818                        .child("\\n")
 7819                        .into_any()
 7820                }),
 7821                constrain_width: false,
 7822                merge_adjacent: false,
 7823                type_tag: Some(type_id),
 7824                collapsed_text: None,
 7825            };
 7826            let creases = new_newlines
 7827                .into_iter()
 7828                .map(|range| Crease::simple(range, placeholder.clone()))
 7829                .collect();
 7830            this.update(cx, |this, cx| {
 7831                this.display_map.update(cx, |display_map, cx| {
 7832                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7833                    display_map.fold(creases, cx);
 7834                });
 7835            })
 7836            .ok();
 7837        });
 7838    }
 7839
 7840    #[ztracing::instrument(skip_all)]
 7841    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7842        if !self.lsp_data_enabled() {
 7843            return;
 7844        }
 7845        let cursor = self.selections.newest_anchor().head();
 7846        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7847
 7848        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7849            self.outline_symbols_at_cursor =
 7850                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7851            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7852            cx.notify();
 7853        } else {
 7854            let syntax = cx.theme().syntax().clone();
 7855            let background_task = cx.background_spawn(async move {
 7856                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7857            });
 7858            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7859                cx.spawn(async move |this, cx| {
 7860                    let symbols = background_task.await;
 7861                    this.update(cx, |this, cx| {
 7862                        this.outline_symbols_at_cursor = symbols;
 7863                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7864                        cx.notify();
 7865                    })
 7866                    .ok();
 7867                });
 7868        }
 7869    }
 7870
 7871    #[ztracing::instrument(skip_all)]
 7872    fn refresh_selected_text_highlights(
 7873        &mut self,
 7874        snapshot: &DisplaySnapshot,
 7875        on_buffer_edit: bool,
 7876        window: &mut Window,
 7877        cx: &mut Context<Editor>,
 7878    ) {
 7879        let Some((query_text, query_range)) =
 7880            self.prepare_highlight_query_from_selection(snapshot, cx)
 7881        else {
 7882            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7883            self.quick_selection_highlight_task.take();
 7884            self.debounced_selection_highlight_task.take();
 7885            self.debounced_selection_highlight_complete = false;
 7886            return;
 7887        };
 7888        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7889        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7890        let query_changed = self
 7891            .quick_selection_highlight_task
 7892            .as_ref()
 7893            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7894        if query_changed {
 7895            self.debounced_selection_highlight_complete = false;
 7896        }
 7897        if on_buffer_edit || query_changed {
 7898            self.quick_selection_highlight_task = Some((
 7899                query_range.clone(),
 7900                self.update_selection_occurrence_highlights(
 7901                    snapshot.buffer.clone(),
 7902                    query_text.clone(),
 7903                    query_range.clone(),
 7904                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7905                    false,
 7906                    window,
 7907                    cx,
 7908                ),
 7909            ));
 7910        }
 7911        if on_buffer_edit
 7912            || self
 7913                .debounced_selection_highlight_task
 7914                .as_ref()
 7915                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7916        {
 7917            let multi_buffer_start = multi_buffer_snapshot
 7918                .anchor_before(MultiBufferOffset(0))
 7919                .to_point(&multi_buffer_snapshot);
 7920            let multi_buffer_end = multi_buffer_snapshot
 7921                .anchor_after(multi_buffer_snapshot.len())
 7922                .to_point(&multi_buffer_snapshot);
 7923            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7924            self.debounced_selection_highlight_task = Some((
 7925                query_range.clone(),
 7926                self.update_selection_occurrence_highlights(
 7927                    snapshot.buffer.clone(),
 7928                    query_text,
 7929                    query_range,
 7930                    multi_buffer_full_range,
 7931                    true,
 7932                    window,
 7933                    cx,
 7934                ),
 7935            ));
 7936        }
 7937    }
 7938
 7939    pub fn multi_buffer_visible_range(
 7940        &self,
 7941        display_snapshot: &DisplaySnapshot,
 7942        cx: &App,
 7943    ) -> Range<Point> {
 7944        let visible_start = self
 7945            .scroll_manager
 7946            .native_anchor(display_snapshot, cx)
 7947            .anchor
 7948            .to_point(display_snapshot.buffer_snapshot())
 7949            .to_display_point(display_snapshot);
 7950
 7951        let mut target_end = visible_start;
 7952        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 7953
 7954        visible_start.to_point(display_snapshot)
 7955            ..display_snapshot
 7956                .clip_point(target_end, Bias::Right)
 7957                .to_point(display_snapshot)
 7958    }
 7959
 7960    pub fn refresh_edit_prediction(
 7961        &mut self,
 7962        debounce: bool,
 7963        user_requested: bool,
 7964        window: &mut Window,
 7965        cx: &mut Context<Self>,
 7966    ) -> Option<()> {
 7967        if self.leader_id.is_some() {
 7968            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7969            return None;
 7970        }
 7971
 7972        let cursor = self.selections.newest_anchor().head();
 7973        let (buffer, cursor_buffer_position) =
 7974            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7975
 7976        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 7977            return None;
 7978        }
 7979
 7980        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7981            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7982            return None;
 7983        }
 7984
 7985        self.update_visible_edit_prediction(window, cx);
 7986
 7987        if !user_requested
 7988            && (!self.should_show_edit_predictions()
 7989                || !self.is_focused(window)
 7990                || buffer.read(cx).is_empty())
 7991        {
 7992            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7993            return None;
 7994        }
 7995
 7996        self.edit_prediction_provider()?
 7997            .refresh(buffer, cursor_buffer_position, debounce, cx);
 7998        Some(())
 7999    }
 8000
 8001    fn show_edit_predictions_in_menu(&self) -> bool {
 8002        match self.edit_prediction_settings {
 8003            EditPredictionSettings::Disabled => false,
 8004            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8005        }
 8006    }
 8007
 8008    pub fn edit_predictions_enabled(&self) -> bool {
 8009        match self.edit_prediction_settings {
 8010            EditPredictionSettings::Disabled => false,
 8011            EditPredictionSettings::Enabled { .. } => true,
 8012        }
 8013    }
 8014
 8015    fn edit_prediction_requires_modifier(&self) -> bool {
 8016        match self.edit_prediction_settings {
 8017            EditPredictionSettings::Disabled => false,
 8018            EditPredictionSettings::Enabled {
 8019                preview_requires_modifier,
 8020                ..
 8021            } => preview_requires_modifier,
 8022        }
 8023    }
 8024
 8025    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8026        if self.edit_prediction_provider.is_none() {
 8027            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8028            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8029            return;
 8030        }
 8031
 8032        let selection = self.selections.newest_anchor();
 8033        let cursor = selection.head();
 8034
 8035        if let Some((buffer, cursor_buffer_position)) =
 8036            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8037        {
 8038            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8039                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8040                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8041                return;
 8042            }
 8043            self.edit_prediction_settings =
 8044                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8045        }
 8046    }
 8047
 8048    fn edit_prediction_settings_at_position(
 8049        &self,
 8050        buffer: &Entity<Buffer>,
 8051        buffer_position: language::Anchor,
 8052        cx: &App,
 8053    ) -> EditPredictionSettings {
 8054        if !self.mode.is_full()
 8055            || !self.show_edit_predictions_override.unwrap_or(true)
 8056            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8057        {
 8058            return EditPredictionSettings::Disabled;
 8059        }
 8060
 8061        if !LanguageSettings::for_buffer(&buffer.read(cx), cx).show_edit_predictions {
 8062            return EditPredictionSettings::Disabled;
 8063        };
 8064
 8065        let by_provider = matches!(
 8066            self.menu_edit_predictions_policy,
 8067            MenuEditPredictionsPolicy::ByProvider
 8068        );
 8069
 8070        let show_in_menu = by_provider
 8071            && self
 8072                .edit_prediction_provider
 8073                .as_ref()
 8074                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8075
 8076        let file = buffer.read(cx).file();
 8077        let preview_requires_modifier =
 8078            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8079
 8080        EditPredictionSettings::Enabled {
 8081            show_in_menu,
 8082            preview_requires_modifier,
 8083        }
 8084    }
 8085
 8086    fn should_show_edit_predictions(&self) -> bool {
 8087        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8088    }
 8089
 8090    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8091        matches!(
 8092            self.edit_prediction_preview,
 8093            EditPredictionPreview::Active { .. }
 8094        )
 8095    }
 8096
 8097    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8098        let cursor = self.selections.newest_anchor().head();
 8099        if let Some((buffer, cursor_position)) =
 8100            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8101        {
 8102            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8103        } else {
 8104            false
 8105        }
 8106    }
 8107
 8108    pub fn supports_minimap(&self, cx: &App) -> bool {
 8109        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8110    }
 8111
 8112    fn edit_predictions_enabled_in_buffer(
 8113        &self,
 8114        buffer: &Entity<Buffer>,
 8115        buffer_position: language::Anchor,
 8116        cx: &App,
 8117    ) -> bool {
 8118        maybe!({
 8119            if self.read_only(cx) || self.leader_id.is_some() {
 8120                return Some(false);
 8121            }
 8122            let provider = self.edit_prediction_provider()?;
 8123            if !provider.is_enabled(buffer, buffer_position, cx) {
 8124                return Some(false);
 8125            }
 8126            let buffer = buffer.read(cx);
 8127            let Some(file) = buffer.file() else {
 8128                return Some(true);
 8129            };
 8130            let settings = all_language_settings(Some(file), cx);
 8131            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8132        })
 8133        .unwrap_or(false)
 8134    }
 8135
 8136    pub fn show_edit_prediction(
 8137        &mut self,
 8138        _: &ShowEditPrediction,
 8139        window: &mut Window,
 8140        cx: &mut Context<Self>,
 8141    ) {
 8142        if !self.has_active_edit_prediction() {
 8143            self.refresh_edit_prediction(false, true, window, cx);
 8144            return;
 8145        }
 8146
 8147        self.update_visible_edit_prediction(window, cx);
 8148    }
 8149
 8150    pub fn display_cursor_names(
 8151        &mut self,
 8152        _: &DisplayCursorNames,
 8153        window: &mut Window,
 8154        cx: &mut Context<Self>,
 8155    ) {
 8156        self.show_cursor_names(window, cx);
 8157    }
 8158
 8159    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8160        self.show_cursor_names = true;
 8161        cx.notify();
 8162        cx.spawn_in(window, async move |this, cx| {
 8163            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8164            this.update(cx, |this, cx| {
 8165                this.show_cursor_names = false;
 8166                cx.notify()
 8167            })
 8168            .ok()
 8169        })
 8170        .detach();
 8171    }
 8172
 8173    pub fn accept_partial_edit_prediction(
 8174        &mut self,
 8175        granularity: EditPredictionGranularity,
 8176        window: &mut Window,
 8177        cx: &mut Context<Self>,
 8178    ) {
 8179        if self.show_edit_predictions_in_menu() {
 8180            self.hide_context_menu(window, cx);
 8181        }
 8182
 8183        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8184            return;
 8185        };
 8186
 8187        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8188            return;
 8189        }
 8190
 8191        match &active_edit_prediction.completion {
 8192            EditPrediction::MoveWithin { target, .. } => {
 8193                let target = *target;
 8194
 8195                if matches!(granularity, EditPredictionGranularity::Full) {
 8196                    if let Some(position_map) = &self.last_position_map {
 8197                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8198                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8199
 8200                        if is_visible || !self.edit_prediction_requires_modifier() {
 8201                            self.unfold_ranges(&[target..target], true, false, cx);
 8202                            self.change_selections(
 8203                                SelectionEffects::scroll(Autoscroll::newest()),
 8204                                window,
 8205                                cx,
 8206                                |selections| {
 8207                                    selections.select_anchor_ranges([target..target]);
 8208                                },
 8209                            );
 8210                            self.clear_row_highlights::<EditPredictionPreview>();
 8211                            self.edit_prediction_preview
 8212                                .set_previous_scroll_position(None);
 8213                        } else {
 8214                            // Highlight and request scroll
 8215                            self.edit_prediction_preview
 8216                                .set_previous_scroll_position(Some(
 8217                                    position_map.snapshot.scroll_anchor,
 8218                                ));
 8219                            self.highlight_rows::<EditPredictionPreview>(
 8220                                target..target,
 8221                                cx.theme().colors().editor_highlighted_line_background,
 8222                                RowHighlightOptions {
 8223                                    autoscroll: true,
 8224                                    ..Default::default()
 8225                                },
 8226                                cx,
 8227                            );
 8228                            self.request_autoscroll(Autoscroll::fit(), cx);
 8229                        }
 8230                    }
 8231                } else {
 8232                    self.change_selections(
 8233                        SelectionEffects::scroll(Autoscroll::newest()),
 8234                        window,
 8235                        cx,
 8236                        |selections| {
 8237                            selections.select_anchor_ranges([target..target]);
 8238                        },
 8239                    );
 8240                }
 8241            }
 8242            EditPrediction::MoveOutside { snapshot, target } => {
 8243                if let Some(workspace) = self.workspace() {
 8244                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8245                        .detach_and_log_err(cx);
 8246                }
 8247            }
 8248            EditPrediction::Edit {
 8249                edits,
 8250                cursor_position,
 8251                ..
 8252            } => {
 8253                self.report_edit_prediction_event(
 8254                    active_edit_prediction.completion_id.clone(),
 8255                    true,
 8256                    cx,
 8257                );
 8258
 8259                match granularity {
 8260                    EditPredictionGranularity::Full => {
 8261                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8262
 8263                        // Compute fallback cursor position BEFORE applying the edit,
 8264                        // so the anchor tracks through the edit correctly
 8265                        let fallback_cursor_target = {
 8266                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8267                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8268                        };
 8269
 8270                        self.buffer.update(cx, |buffer, cx| {
 8271                            buffer.edit(edits.iter().cloned(), None, cx)
 8272                        });
 8273
 8274                        if let Some(provider) = self.edit_prediction_provider() {
 8275                            provider.accept(cx);
 8276                        }
 8277
 8278                        // Resolve cursor position after the edit is applied
 8279                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8280                            // The anchor tracks through the edit, then we add the offset
 8281                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8282                            let base_offset = anchor.to_offset(&snapshot).0;
 8283                            let target_offset =
 8284                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8285                            snapshot.anchor_after(target_offset)
 8286                        } else {
 8287                            fallback_cursor_target
 8288                        };
 8289
 8290                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8291                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8292                        });
 8293
 8294                        let selections = self.selections.disjoint_anchors_arc();
 8295                        if let Some(transaction_id_now) =
 8296                            self.buffer.read(cx).last_transaction_id(cx)
 8297                        {
 8298                            if transaction_id_prev != Some(transaction_id_now) {
 8299                                self.selection_history
 8300                                    .insert_transaction(transaction_id_now, selections);
 8301                            }
 8302                        }
 8303
 8304                        self.update_visible_edit_prediction(window, cx);
 8305                        if self.active_edit_prediction.is_none() {
 8306                            self.refresh_edit_prediction(true, true, window, cx);
 8307                        }
 8308                        cx.notify();
 8309                    }
 8310                    _ => {
 8311                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8312                        let cursor_offset = self
 8313                            .selections
 8314                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8315                            .head();
 8316
 8317                        let insertion = edits.iter().find_map(|(range, text)| {
 8318                            let range = range.to_offset(&snapshot);
 8319                            if range.is_empty() && range.start == cursor_offset {
 8320                                Some(text)
 8321                            } else {
 8322                                None
 8323                            }
 8324                        });
 8325
 8326                        if let Some(text) = insertion {
 8327                            let text_to_insert = match granularity {
 8328                                EditPredictionGranularity::Word => {
 8329                                    let mut partial = text
 8330                                        .chars()
 8331                                        .by_ref()
 8332                                        .take_while(|c| c.is_alphabetic())
 8333                                        .collect::<String>();
 8334                                    if partial.is_empty() {
 8335                                        partial = text
 8336                                            .chars()
 8337                                            .by_ref()
 8338                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8339                                            .collect::<String>();
 8340                                    }
 8341                                    partial
 8342                                }
 8343                                EditPredictionGranularity::Line => {
 8344                                    if let Some(line) = text.split_inclusive('\n').next() {
 8345                                        line.to_string()
 8346                                    } else {
 8347                                        text.to_string()
 8348                                    }
 8349                                }
 8350                                EditPredictionGranularity::Full => unreachable!(),
 8351                            };
 8352
 8353                            cx.emit(EditorEvent::InputHandled {
 8354                                utf16_range_to_replace: None,
 8355                                text: text_to_insert.clone().into(),
 8356                            });
 8357
 8358                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8359                            self.refresh_edit_prediction(true, true, window, cx);
 8360                            cx.notify();
 8361                        } else {
 8362                            self.accept_partial_edit_prediction(
 8363                                EditPredictionGranularity::Full,
 8364                                window,
 8365                                cx,
 8366                            );
 8367                        }
 8368                    }
 8369                }
 8370            }
 8371        }
 8372    }
 8373
 8374    pub fn accept_next_word_edit_prediction(
 8375        &mut self,
 8376        _: &AcceptNextWordEditPrediction,
 8377        window: &mut Window,
 8378        cx: &mut Context<Self>,
 8379    ) {
 8380        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8381    }
 8382
 8383    pub fn accept_next_line_edit_prediction(
 8384        &mut self,
 8385        _: &AcceptNextLineEditPrediction,
 8386        window: &mut Window,
 8387        cx: &mut Context<Self>,
 8388    ) {
 8389        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8390    }
 8391
 8392    pub fn accept_edit_prediction(
 8393        &mut self,
 8394        _: &AcceptEditPrediction,
 8395        window: &mut Window,
 8396        cx: &mut Context<Self>,
 8397    ) {
 8398        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8399    }
 8400
 8401    fn discard_edit_prediction(
 8402        &mut self,
 8403        reason: EditPredictionDiscardReason,
 8404        cx: &mut Context<Self>,
 8405    ) -> bool {
 8406        if reason == EditPredictionDiscardReason::Rejected {
 8407            let completion_id = self
 8408                .active_edit_prediction
 8409                .as_ref()
 8410                .and_then(|active_completion| active_completion.completion_id.clone());
 8411
 8412            self.report_edit_prediction_event(completion_id, false, cx);
 8413        }
 8414
 8415        if let Some(provider) = self.edit_prediction_provider() {
 8416            provider.discard(reason, cx);
 8417        }
 8418
 8419        self.take_active_edit_prediction(reason == EditPredictionDiscardReason::Ignored, cx)
 8420    }
 8421
 8422    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8423        let Some(provider) = self.edit_prediction_provider() else {
 8424            return;
 8425        };
 8426
 8427        let Some((_, buffer, _)) = self
 8428            .buffer
 8429            .read(cx)
 8430            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8431        else {
 8432            return;
 8433        };
 8434
 8435        let extension = buffer
 8436            .read(cx)
 8437            .file()
 8438            .and_then(|file| Some(file.path().extension()?.to_string()));
 8439
 8440        let event_type = match accepted {
 8441            true => "Edit Prediction Accepted",
 8442            false => "Edit Prediction Discarded",
 8443        };
 8444        telemetry::event!(
 8445            event_type,
 8446            provider = provider.name(),
 8447            prediction_id = id,
 8448            suggestion_accepted = accepted,
 8449            file_extension = extension,
 8450        );
 8451    }
 8452
 8453    fn open_editor_at_anchor(
 8454        snapshot: &language::BufferSnapshot,
 8455        target: language::Anchor,
 8456        workspace: &Entity<Workspace>,
 8457        window: &mut Window,
 8458        cx: &mut App,
 8459    ) -> Task<Result<()>> {
 8460        workspace.update(cx, |workspace, cx| {
 8461            let path = snapshot.file().map(|file| file.full_path(cx));
 8462            let Some(path) =
 8463                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8464            else {
 8465                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8466            };
 8467            let target = text::ToPoint::to_point(&target, snapshot);
 8468            let item = workspace.open_path(path, None, true, window, cx);
 8469            window.spawn(cx, async move |cx| {
 8470                let Some(editor) = item.await?.downcast::<Editor>() else {
 8471                    return Ok(());
 8472                };
 8473                editor
 8474                    .update_in(cx, |editor, window, cx| {
 8475                        editor.go_to_singleton_buffer_point(target, window, cx);
 8476                    })
 8477                    .ok();
 8478                anyhow::Ok(())
 8479            })
 8480        })
 8481    }
 8482
 8483    pub fn has_active_edit_prediction(&self) -> bool {
 8484        self.active_edit_prediction.is_some()
 8485    }
 8486
 8487    fn take_active_edit_prediction(
 8488        &mut self,
 8489        preserve_stale_in_menu: bool,
 8490        cx: &mut Context<Self>,
 8491    ) -> bool {
 8492        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8493            if !preserve_stale_in_menu {
 8494                self.stale_edit_prediction_in_menu = None;
 8495            }
 8496            return false;
 8497        };
 8498
 8499        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8500        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8501        self.stale_edit_prediction_in_menu =
 8502            preserve_stale_in_menu.then_some(active_edit_prediction);
 8503        true
 8504    }
 8505
 8506    /// Returns true when we're displaying the edit prediction popover below the cursor
 8507    /// like we are not previewing and the LSP autocomplete menu is visible
 8508    /// or we are in `when_holding_modifier` mode.
 8509    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8510        if self.edit_prediction_preview_is_active()
 8511            || !self.show_edit_predictions_in_menu()
 8512            || !self.edit_predictions_enabled()
 8513        {
 8514            return false;
 8515        }
 8516
 8517        if self.has_visible_completions_menu() {
 8518            return true;
 8519        }
 8520
 8521        has_completion && self.edit_prediction_requires_modifier()
 8522    }
 8523
 8524    fn handle_modifiers_changed(
 8525        &mut self,
 8526        modifiers: Modifiers,
 8527        position_map: &PositionMap,
 8528        window: &mut Window,
 8529        cx: &mut Context<Self>,
 8530    ) {
 8531        self.update_edit_prediction_settings(cx);
 8532
 8533        // Ensure that the edit prediction preview is updated, even when not
 8534        // enabled, if there's an active edit prediction preview.
 8535        if self.show_edit_predictions_in_menu()
 8536            || self.edit_prediction_requires_modifier()
 8537            || matches!(
 8538                self.edit_prediction_preview,
 8539                EditPredictionPreview::Active { .. }
 8540            )
 8541        {
 8542            self.update_edit_prediction_preview(&modifiers, window, cx);
 8543        }
 8544
 8545        self.update_selection_mode(&modifiers, position_map, window, cx);
 8546
 8547        let mouse_position = window.mouse_position();
 8548        if !position_map.text_hitbox.is_hovered(window) {
 8549            return;
 8550        }
 8551
 8552        self.update_hovered_link(
 8553            position_map.point_for_position(mouse_position),
 8554            Some(mouse_position),
 8555            &position_map.snapshot,
 8556            modifiers,
 8557            window,
 8558            cx,
 8559        )
 8560    }
 8561
 8562    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8563        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8564            MultiCursorModifier::Alt => modifiers.secondary(),
 8565            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8566        }
 8567    }
 8568
 8569    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8570        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8571            MultiCursorModifier::Alt => modifiers.alt,
 8572            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8573        }
 8574    }
 8575
 8576    fn columnar_selection_mode(
 8577        modifiers: &Modifiers,
 8578        cx: &mut Context<Self>,
 8579    ) -> Option<ColumnarMode> {
 8580        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8581            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8582                Some(ColumnarMode::FromMouse)
 8583            } else if Self::is_alt_pressed(modifiers, cx) {
 8584                Some(ColumnarMode::FromSelection)
 8585            } else {
 8586                None
 8587            }
 8588        } else {
 8589            None
 8590        }
 8591    }
 8592
 8593    fn update_selection_mode(
 8594        &mut self,
 8595        modifiers: &Modifiers,
 8596        position_map: &PositionMap,
 8597        window: &mut Window,
 8598        cx: &mut Context<Self>,
 8599    ) {
 8600        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8601            return;
 8602        };
 8603        if self.selections.pending_anchor().is_none() {
 8604            return;
 8605        }
 8606
 8607        let mouse_position = window.mouse_position();
 8608        let point_for_position = position_map.point_for_position(mouse_position);
 8609        let position = point_for_position.previous_valid;
 8610
 8611        self.select(
 8612            SelectPhase::BeginColumnar {
 8613                position,
 8614                reset: false,
 8615                mode,
 8616                goal_column: point_for_position.exact_unclipped.column(),
 8617            },
 8618            window,
 8619            cx,
 8620        );
 8621    }
 8622
 8623    fn update_edit_prediction_preview(
 8624        &mut self,
 8625        modifiers: &Modifiers,
 8626        window: &mut Window,
 8627        cx: &mut Context<Self>,
 8628    ) {
 8629        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8630
 8631        if modifiers_held {
 8632            if matches!(
 8633                self.edit_prediction_preview,
 8634                EditPredictionPreview::Inactive { .. }
 8635            ) {
 8636                self.edit_prediction_preview = EditPredictionPreview::Active {
 8637                    previous_scroll_position: None,
 8638                    since: Instant::now(),
 8639                };
 8640
 8641                self.update_visible_edit_prediction(window, cx);
 8642                cx.notify();
 8643            }
 8644        } else if let EditPredictionPreview::Active {
 8645            previous_scroll_position,
 8646            since,
 8647        } = self.edit_prediction_preview
 8648        {
 8649            if let (Some(previous_scroll_position), Some(position_map)) =
 8650                (previous_scroll_position, self.last_position_map.as_ref())
 8651            {
 8652                self.set_scroll_position(
 8653                    previous_scroll_position
 8654                        .scroll_position(&position_map.snapshot.display_snapshot),
 8655                    window,
 8656                    cx,
 8657                );
 8658            }
 8659
 8660            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8661                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8662            };
 8663            self.clear_row_highlights::<EditPredictionPreview>();
 8664            self.update_visible_edit_prediction(window, cx);
 8665            cx.notify();
 8666        }
 8667    }
 8668
 8669    fn update_visible_edit_prediction(
 8670        &mut self,
 8671        _window: &mut Window,
 8672        cx: &mut Context<Self>,
 8673    ) -> Option<()> {
 8674        if self.ime_transaction.is_some() {
 8675            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8676            return None;
 8677        }
 8678
 8679        let selection = self.selections.newest_anchor();
 8680        let cursor = selection.head();
 8681        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8682
 8683        // Check project-level disable_ai setting for the current buffer
 8684        if let Some((buffer, _)) = self.buffer.read(cx).text_anchor_for_position(cursor, cx) {
 8685            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8686                return None;
 8687            }
 8688        }
 8689        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8690        let excerpt_id = cursor.excerpt_id;
 8691
 8692        let show_in_menu = self.show_edit_predictions_in_menu();
 8693        let completions_menu_has_precedence = !show_in_menu
 8694            && (self.context_menu.borrow().is_some()
 8695                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8696
 8697        if completions_menu_has_precedence
 8698            || !offset_selection.is_empty()
 8699            || self
 8700                .active_edit_prediction
 8701                .as_ref()
 8702                .is_some_and(|completion| {
 8703                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8704                        return false;
 8705                    };
 8706                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8707                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8708                    !invalidation_range.contains(&offset_selection.head())
 8709                })
 8710        {
 8711            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8712            return None;
 8713        }
 8714
 8715        self.take_active_edit_prediction(true, cx);
 8716        let Some(provider) = self.edit_prediction_provider() else {
 8717            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8718            return None;
 8719        };
 8720
 8721        let (buffer, cursor_buffer_position) =
 8722            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8723
 8724        self.edit_prediction_settings =
 8725            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8726
 8727        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8728
 8729        if self.in_leading_whitespace {
 8730            let cursor_point = cursor.to_point(&multibuffer);
 8731            let mut suggested_indent = None;
 8732            multibuffer.suggested_indents_callback(
 8733                cursor_point.row..cursor_point.row + 1,
 8734                &mut |_, indent| {
 8735                    suggested_indent = Some(indent);
 8736                    ControlFlow::Break(())
 8737                },
 8738                cx,
 8739            );
 8740
 8741            if let Some(indent) = suggested_indent
 8742                && indent.len == cursor_point.column
 8743            {
 8744                self.in_leading_whitespace = false;
 8745            }
 8746        }
 8747
 8748        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8749
 8750        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8751        {
 8752            edit_prediction_types::EditPrediction::Local {
 8753                id,
 8754                edits,
 8755                cursor_position,
 8756                edit_preview,
 8757            } => (id, edits, cursor_position, edit_preview),
 8758            edit_prediction_types::EditPrediction::Jump {
 8759                id,
 8760                snapshot,
 8761                target,
 8762            } => {
 8763                if let Some(provider) = &self.edit_prediction_provider {
 8764                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8765                }
 8766                self.stale_edit_prediction_in_menu = None;
 8767                self.active_edit_prediction = Some(EditPredictionState {
 8768                    inlay_ids: vec![],
 8769                    completion: EditPrediction::MoveOutside { snapshot, target },
 8770                    completion_id: id,
 8771                    invalidation_range: None,
 8772                });
 8773                cx.notify();
 8774                return Some(());
 8775            }
 8776        };
 8777
 8778        let edits = edits
 8779            .into_iter()
 8780            .flat_map(|(range, new_text)| {
 8781                Some((
 8782                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8783                    new_text,
 8784                ))
 8785            })
 8786            .collect::<Vec<_>>();
 8787        if edits.is_empty() {
 8788            return None;
 8789        }
 8790
 8791        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8792            let anchor = multibuffer.anchor_in_excerpt(excerpt_id, predicted.anchor)?;
 8793            Some((anchor, predicted.offset))
 8794        });
 8795
 8796        let first_edit_start = edits.first().unwrap().0.start;
 8797        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8798        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8799
 8800        let last_edit_end = edits.last().unwrap().0.end;
 8801        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8802        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8803
 8804        let cursor_row = cursor.to_point(&multibuffer).row;
 8805
 8806        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8807
 8808        let mut inlay_ids = Vec::new();
 8809        let invalidation_row_range;
 8810        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8811            Some(cursor_row..edit_end_row)
 8812        } else if cursor_row > edit_end_row {
 8813            Some(edit_start_row..cursor_row)
 8814        } else {
 8815            None
 8816        };
 8817        let supports_jump = self
 8818            .edit_prediction_provider
 8819            .as_ref()
 8820            .map(|provider| provider.provider.supports_jump_to_edit())
 8821            .unwrap_or(true);
 8822
 8823        let is_move = supports_jump
 8824            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8825        let completion = if is_move {
 8826            if let Some(provider) = &self.edit_prediction_provider {
 8827                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8828            }
 8829            invalidation_row_range =
 8830                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8831            let target = first_edit_start;
 8832            EditPrediction::MoveWithin { target, snapshot }
 8833        } else {
 8834            let show_completions_in_menu = self.has_visible_completions_menu();
 8835            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8836                && !self.edit_predictions_hidden_for_vim_mode;
 8837
 8838            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8839                if provider.show_tab_accept_marker() {
 8840                    EditDisplayMode::TabAccept
 8841                } else {
 8842                    EditDisplayMode::Inline
 8843                }
 8844            } else {
 8845                EditDisplayMode::DiffPopover
 8846            };
 8847
 8848            let report_shown = match display_mode {
 8849                EditDisplayMode::DiffPopover | EditDisplayMode::Inline => {
 8850                    show_completions_in_buffer || show_completions_in_menu
 8851                }
 8852                EditDisplayMode::TabAccept => {
 8853                    show_completions_in_menu || self.edit_prediction_preview_is_active()
 8854                }
 8855            };
 8856
 8857            if report_shown && let Some(provider) = &self.edit_prediction_provider {
 8858                let suggestion_display_type = match display_mode {
 8859                    EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8860                    EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8861                        SuggestionDisplayType::GhostText
 8862                    }
 8863                };
 8864                provider.provider.did_show(suggestion_display_type, cx);
 8865            }
 8866
 8867            if show_completions_in_buffer {
 8868                if edits
 8869                    .iter()
 8870                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8871                {
 8872                    let mut inlays = Vec::new();
 8873                    for (range, new_text) in &edits {
 8874                        let inlay = Inlay::edit_prediction(
 8875                            post_inc(&mut self.next_inlay_id),
 8876                            range.start,
 8877                            new_text.as_ref(),
 8878                        );
 8879                        inlay_ids.push(inlay.id);
 8880                        inlays.push(inlay);
 8881                    }
 8882
 8883                    self.splice_inlays(&[], inlays, cx);
 8884                } else {
 8885                    let background_color = cx.theme().status().deleted_background;
 8886                    self.highlight_text(
 8887                        HighlightKey::EditPredictionHighlight,
 8888                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8889                        HighlightStyle {
 8890                            background_color: Some(background_color),
 8891                            ..Default::default()
 8892                        },
 8893                        cx,
 8894                    );
 8895                }
 8896            }
 8897
 8898            invalidation_row_range = edit_start_row..edit_end_row;
 8899
 8900            EditPrediction::Edit {
 8901                edits,
 8902                cursor_position,
 8903                edit_preview,
 8904                display_mode,
 8905                snapshot,
 8906            }
 8907        };
 8908
 8909        let invalidation_range = multibuffer
 8910            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8911            ..multibuffer.anchor_after(Point::new(
 8912                invalidation_row_range.end,
 8913                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8914            ));
 8915
 8916        self.stale_edit_prediction_in_menu = None;
 8917        self.active_edit_prediction = Some(EditPredictionState {
 8918            inlay_ids,
 8919            completion,
 8920            completion_id,
 8921            invalidation_range: Some(invalidation_range),
 8922        });
 8923
 8924        cx.notify();
 8925
 8926        Some(())
 8927    }
 8928
 8929    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8930        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8931    }
 8932
 8933    /// Get all display points of breakpoints that will be rendered within editor
 8934    ///
 8935    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8936    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8937    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8938    fn active_breakpoints(
 8939        &self,
 8940        range: Range<DisplayRow>,
 8941        window: &mut Window,
 8942        cx: &mut Context<Self>,
 8943    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8944        let mut breakpoint_display_points = HashMap::default();
 8945
 8946        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8947            return breakpoint_display_points;
 8948        };
 8949
 8950        let snapshot = self.snapshot(window, cx);
 8951
 8952        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8953        let Some(project) = self.project() else {
 8954            return breakpoint_display_points;
 8955        };
 8956
 8957        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8958            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8959
 8960        for (buffer_snapshot, range, excerpt_id) in
 8961            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8962        {
 8963            let Some(buffer) = project
 8964                .read(cx)
 8965                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8966            else {
 8967                continue;
 8968            };
 8969            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8970                &buffer,
 8971                Some(
 8972                    buffer_snapshot.anchor_before(range.start)
 8973                        ..buffer_snapshot.anchor_after(range.end),
 8974                ),
 8975                buffer_snapshot,
 8976                cx,
 8977            );
 8978            for (breakpoint, state) in breakpoints {
 8979                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8980                let position = multi_buffer_anchor
 8981                    .to_point(&multi_buffer_snapshot)
 8982                    .to_display_point(&snapshot);
 8983
 8984                breakpoint_display_points.insert(
 8985                    position.row(),
 8986                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8987                );
 8988            }
 8989        }
 8990
 8991        breakpoint_display_points
 8992    }
 8993
 8994    fn breakpoint_context_menu(
 8995        &self,
 8996        anchor: Anchor,
 8997        window: &mut Window,
 8998        cx: &mut Context<Self>,
 8999    ) -> Entity<ui::ContextMenu> {
 9000        let weak_editor = cx.weak_entity();
 9001        let focus_handle = self.focus_handle(cx);
 9002
 9003        let row = self
 9004            .buffer
 9005            .read(cx)
 9006            .snapshot(cx)
 9007            .summary_for_anchor::<Point>(&anchor)
 9008            .row;
 9009
 9010        let breakpoint = self
 9011            .breakpoint_at_row(row, window, cx)
 9012            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9013
 9014        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9015            "Edit Log Breakpoint"
 9016        } else {
 9017            "Set Log Breakpoint"
 9018        };
 9019
 9020        let condition_breakpoint_msg = if breakpoint
 9021            .as_ref()
 9022            .is_some_and(|bp| bp.1.condition.is_some())
 9023        {
 9024            "Edit Condition Breakpoint"
 9025        } else {
 9026            "Set Condition Breakpoint"
 9027        };
 9028
 9029        let hit_condition_breakpoint_msg = if breakpoint
 9030            .as_ref()
 9031            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9032        {
 9033            "Edit Hit Condition Breakpoint"
 9034        } else {
 9035            "Set Hit Condition Breakpoint"
 9036        };
 9037
 9038        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9039            "Unset Breakpoint"
 9040        } else {
 9041            "Set Breakpoint"
 9042        };
 9043
 9044        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9045
 9046        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9047            BreakpointState::Enabled => Some("Disable"),
 9048            BreakpointState::Disabled => Some("Enable"),
 9049        });
 9050
 9051        let (anchor, breakpoint) =
 9052            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9053
 9054        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9055            menu.on_blur_subscription(Subscription::new(|| {}))
 9056                .context(focus_handle)
 9057                .when(run_to_cursor, |this| {
 9058                    let weak_editor = weak_editor.clone();
 9059                    this.entry("Run to Cursor", None, move |window, cx| {
 9060                        weak_editor
 9061                            .update(cx, |editor, cx| {
 9062                                editor.change_selections(
 9063                                    SelectionEffects::no_scroll(),
 9064                                    window,
 9065                                    cx,
 9066                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9067                                );
 9068                            })
 9069                            .ok();
 9070
 9071                        window.dispatch_action(Box::new(RunToCursor), cx);
 9072                    })
 9073                    .separator()
 9074                })
 9075                .when_some(toggle_state_msg, |this, msg| {
 9076                    this.entry(msg, None, {
 9077                        let weak_editor = weak_editor.clone();
 9078                        let breakpoint = breakpoint.clone();
 9079                        move |_window, cx| {
 9080                            weak_editor
 9081                                .update(cx, |this, cx| {
 9082                                    this.edit_breakpoint_at_anchor(
 9083                                        anchor,
 9084                                        breakpoint.as_ref().clone(),
 9085                                        BreakpointEditAction::InvertState,
 9086                                        cx,
 9087                                    );
 9088                                })
 9089                                .log_err();
 9090                        }
 9091                    })
 9092                })
 9093                .entry(set_breakpoint_msg, None, {
 9094                    let weak_editor = weak_editor.clone();
 9095                    let breakpoint = breakpoint.clone();
 9096                    move |_window, cx| {
 9097                        weak_editor
 9098                            .update(cx, |this, cx| {
 9099                                this.edit_breakpoint_at_anchor(
 9100                                    anchor,
 9101                                    breakpoint.as_ref().clone(),
 9102                                    BreakpointEditAction::Toggle,
 9103                                    cx,
 9104                                );
 9105                            })
 9106                            .log_err();
 9107                    }
 9108                })
 9109                .entry(log_breakpoint_msg, None, {
 9110                    let breakpoint = breakpoint.clone();
 9111                    let weak_editor = weak_editor.clone();
 9112                    move |window, cx| {
 9113                        weak_editor
 9114                            .update(cx, |this, cx| {
 9115                                this.add_edit_breakpoint_block(
 9116                                    anchor,
 9117                                    breakpoint.as_ref(),
 9118                                    BreakpointPromptEditAction::Log,
 9119                                    window,
 9120                                    cx,
 9121                                );
 9122                            })
 9123                            .log_err();
 9124                    }
 9125                })
 9126                .entry(condition_breakpoint_msg, None, {
 9127                    let breakpoint = breakpoint.clone();
 9128                    let weak_editor = weak_editor.clone();
 9129                    move |window, cx| {
 9130                        weak_editor
 9131                            .update(cx, |this, cx| {
 9132                                this.add_edit_breakpoint_block(
 9133                                    anchor,
 9134                                    breakpoint.as_ref(),
 9135                                    BreakpointPromptEditAction::Condition,
 9136                                    window,
 9137                                    cx,
 9138                                );
 9139                            })
 9140                            .log_err();
 9141                    }
 9142                })
 9143                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9144                    weak_editor
 9145                        .update(cx, |this, cx| {
 9146                            this.add_edit_breakpoint_block(
 9147                                anchor,
 9148                                breakpoint.as_ref(),
 9149                                BreakpointPromptEditAction::HitCondition,
 9150                                window,
 9151                                cx,
 9152                            );
 9153                        })
 9154                        .log_err();
 9155                })
 9156        })
 9157    }
 9158
 9159    fn render_breakpoint(
 9160        &self,
 9161        position: Anchor,
 9162        row: DisplayRow,
 9163        breakpoint: &Breakpoint,
 9164        state: Option<BreakpointSessionState>,
 9165        cx: &mut Context<Self>,
 9166    ) -> IconButton {
 9167        let is_rejected = state.is_some_and(|s| !s.verified);
 9168        // Is it a breakpoint that shows up when hovering over gutter?
 9169        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9170            (false, false),
 9171            |PhantomBreakpointIndicator {
 9172                 is_active,
 9173                 display_row,
 9174                 collides_with_existing_breakpoint,
 9175             }| {
 9176                (
 9177                    is_active && display_row == row,
 9178                    collides_with_existing_breakpoint,
 9179                )
 9180            },
 9181        );
 9182
 9183        let (color, icon) = {
 9184            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9185                (false, false) => ui::IconName::DebugBreakpoint,
 9186                (true, false) => ui::IconName::DebugLogBreakpoint,
 9187                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9188                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9189            };
 9190
 9191            let theme_colors = cx.theme().colors();
 9192
 9193            let color = if is_phantom {
 9194                if collides_with_existing {
 9195                    Color::Custom(
 9196                        theme_colors
 9197                            .debugger_accent
 9198                            .blend(theme_colors.text.opacity(0.6)),
 9199                    )
 9200                } else {
 9201                    Color::Hint
 9202                }
 9203            } else if is_rejected {
 9204                Color::Disabled
 9205            } else {
 9206                Color::Debugger
 9207            };
 9208
 9209            (color, icon)
 9210        };
 9211
 9212        let breakpoint = Arc::from(breakpoint.clone());
 9213
 9214        let alt_as_text = gpui::Keystroke {
 9215            modifiers: Modifiers::secondary_key(),
 9216            ..Default::default()
 9217        };
 9218        let primary_action_text = if breakpoint.is_disabled() {
 9219            "Enable breakpoint"
 9220        } else if is_phantom && !collides_with_existing {
 9221            "Set breakpoint"
 9222        } else {
 9223            "Unset breakpoint"
 9224        };
 9225        let focus_handle = self.focus_handle.clone();
 9226
 9227        let meta = if is_rejected {
 9228            SharedString::from("No executable code is associated with this line.")
 9229        } else if collides_with_existing && !breakpoint.is_disabled() {
 9230            SharedString::from(format!(
 9231                "{alt_as_text}-click to disable,\nright-click for more options."
 9232            ))
 9233        } else {
 9234            SharedString::from("Right-click for more options.")
 9235        };
 9236        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9237            .icon_size(IconSize::XSmall)
 9238            .size(ui::ButtonSize::None)
 9239            .when(is_rejected, |this| {
 9240                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9241            })
 9242            .icon_color(color)
 9243            .style(ButtonStyle::Transparent)
 9244            .on_click(cx.listener({
 9245                move |editor, event: &ClickEvent, window, cx| {
 9246                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9247                        BreakpointEditAction::InvertState
 9248                    } else {
 9249                        BreakpointEditAction::Toggle
 9250                    };
 9251
 9252                    window.focus(&editor.focus_handle(cx), cx);
 9253                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9254                    editor.edit_breakpoint_at_anchor(
 9255                        position,
 9256                        breakpoint.as_ref().clone(),
 9257                        edit_action,
 9258                        cx,
 9259                    );
 9260                }
 9261            }))
 9262            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9263                editor.set_breakpoint_context_menu(
 9264                    row,
 9265                    Some(position),
 9266                    event.position(),
 9267                    window,
 9268                    cx,
 9269                );
 9270            }))
 9271            .tooltip(move |_window, cx| {
 9272                Tooltip::with_meta_in(
 9273                    primary_action_text,
 9274                    Some(&ToggleBreakpoint),
 9275                    meta.clone(),
 9276                    &focus_handle,
 9277                    cx,
 9278                )
 9279            })
 9280    }
 9281
 9282    fn build_tasks_context(
 9283        project: &Entity<Project>,
 9284        buffer: &Entity<Buffer>,
 9285        buffer_row: u32,
 9286        tasks: &Arc<RunnableTasks>,
 9287        cx: &mut Context<Self>,
 9288    ) -> Task<Option<task::TaskContext>> {
 9289        let position = Point::new(buffer_row, tasks.column);
 9290        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9291        let location = Location {
 9292            buffer: buffer.clone(),
 9293            range: range_start..range_start,
 9294        };
 9295        // Fill in the environmental variables from the tree-sitter captures
 9296        let mut captured_task_variables = TaskVariables::default();
 9297        for (capture_name, value) in tasks.extra_variables.clone() {
 9298            captured_task_variables.insert(
 9299                task::VariableName::Custom(capture_name.into()),
 9300                value.clone(),
 9301            );
 9302        }
 9303        project.update(cx, |project, cx| {
 9304            project.task_store().update(cx, |task_store, cx| {
 9305                task_store.task_context_for_location(captured_task_variables, location, cx)
 9306            })
 9307        })
 9308    }
 9309
 9310    pub fn context_menu_visible(&self) -> bool {
 9311        !self.edit_prediction_preview_is_active()
 9312            && self
 9313                .context_menu
 9314                .borrow()
 9315                .as_ref()
 9316                .is_some_and(|menu| menu.visible())
 9317    }
 9318
 9319    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9320        self.context_menu
 9321            .borrow()
 9322            .as_ref()
 9323            .map(|menu| menu.origin())
 9324    }
 9325
 9326    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9327        self.context_menu_options = Some(options);
 9328    }
 9329
 9330    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9331    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9332
 9333    fn render_edit_prediction_popover(
 9334        &mut self,
 9335        text_bounds: &Bounds<Pixels>,
 9336        content_origin: gpui::Point<Pixels>,
 9337        right_margin: Pixels,
 9338        editor_snapshot: &EditorSnapshot,
 9339        visible_row_range: Range<DisplayRow>,
 9340        scroll_top: ScrollOffset,
 9341        scroll_bottom: ScrollOffset,
 9342        line_layouts: &[LineWithInvisibles],
 9343        line_height: Pixels,
 9344        scroll_position: gpui::Point<ScrollOffset>,
 9345        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9346        newest_selection_head: Option<DisplayPoint>,
 9347        editor_width: Pixels,
 9348        style: &EditorStyle,
 9349        window: &mut Window,
 9350        cx: &mut App,
 9351    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9352        if self.mode().is_minimap() {
 9353            return None;
 9354        }
 9355        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9356
 9357        if self.edit_prediction_visible_in_cursor_popover(true) {
 9358            return None;
 9359        }
 9360
 9361        match &active_edit_prediction.completion {
 9362            EditPrediction::MoveWithin { target, .. } => {
 9363                let target_display_point = target.to_display_point(editor_snapshot);
 9364
 9365                if self.edit_prediction_requires_modifier() {
 9366                    if !self.edit_prediction_preview_is_active() {
 9367                        return None;
 9368                    }
 9369
 9370                    self.render_edit_prediction_modifier_jump_popover(
 9371                        text_bounds,
 9372                        content_origin,
 9373                        visible_row_range,
 9374                        line_layouts,
 9375                        line_height,
 9376                        scroll_pixel_position,
 9377                        newest_selection_head,
 9378                        target_display_point,
 9379                        window,
 9380                        cx,
 9381                    )
 9382                } else {
 9383                    self.render_edit_prediction_eager_jump_popover(
 9384                        text_bounds,
 9385                        content_origin,
 9386                        editor_snapshot,
 9387                        visible_row_range,
 9388                        scroll_top,
 9389                        scroll_bottom,
 9390                        line_height,
 9391                        scroll_pixel_position,
 9392                        target_display_point,
 9393                        editor_width,
 9394                        window,
 9395                        cx,
 9396                    )
 9397                }
 9398            }
 9399            EditPrediction::Edit {
 9400                display_mode: EditDisplayMode::Inline,
 9401                ..
 9402            } => None,
 9403            EditPrediction::Edit {
 9404                display_mode: EditDisplayMode::TabAccept,
 9405                edits,
 9406                ..
 9407            } => {
 9408                let range = &edits.first()?.0;
 9409                let target_display_point = range.end.to_display_point(editor_snapshot);
 9410
 9411                self.render_edit_prediction_end_of_line_popover(
 9412                    "Accept",
 9413                    editor_snapshot,
 9414                    visible_row_range,
 9415                    target_display_point,
 9416                    line_height,
 9417                    scroll_pixel_position,
 9418                    content_origin,
 9419                    editor_width,
 9420                    window,
 9421                    cx,
 9422                )
 9423            }
 9424            EditPrediction::Edit {
 9425                edits,
 9426                edit_preview,
 9427                display_mode: EditDisplayMode::DiffPopover,
 9428                snapshot,
 9429                ..
 9430            } => self.render_edit_prediction_diff_popover(
 9431                text_bounds,
 9432                content_origin,
 9433                right_margin,
 9434                editor_snapshot,
 9435                visible_row_range,
 9436                line_layouts,
 9437                line_height,
 9438                scroll_position,
 9439                scroll_pixel_position,
 9440                newest_selection_head,
 9441                editor_width,
 9442                style,
 9443                edits,
 9444                edit_preview,
 9445                snapshot,
 9446                window,
 9447                cx,
 9448            ),
 9449            EditPrediction::MoveOutside { snapshot, .. } => {
 9450                let mut element = self
 9451                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9452                    .into_any();
 9453
 9454                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9455                let origin_x = text_bounds.size.width - size.width - px(30.);
 9456                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9457                element.prepaint_at(origin, window, cx);
 9458
 9459                Some((element, origin))
 9460            }
 9461        }
 9462    }
 9463
 9464    fn render_edit_prediction_modifier_jump_popover(
 9465        &mut self,
 9466        text_bounds: &Bounds<Pixels>,
 9467        content_origin: gpui::Point<Pixels>,
 9468        visible_row_range: Range<DisplayRow>,
 9469        line_layouts: &[LineWithInvisibles],
 9470        line_height: Pixels,
 9471        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9472        newest_selection_head: Option<DisplayPoint>,
 9473        target_display_point: DisplayPoint,
 9474        window: &mut Window,
 9475        cx: &mut App,
 9476    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9477        let scrolled_content_origin =
 9478            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9479
 9480        const SCROLL_PADDING_Y: Pixels = px(12.);
 9481
 9482        if target_display_point.row() < visible_row_range.start {
 9483            return self.render_edit_prediction_scroll_popover(
 9484                &|_| SCROLL_PADDING_Y,
 9485                IconName::ArrowUp,
 9486                visible_row_range,
 9487                line_layouts,
 9488                newest_selection_head,
 9489                scrolled_content_origin,
 9490                window,
 9491                cx,
 9492            );
 9493        } else if target_display_point.row() >= visible_row_range.end {
 9494            return self.render_edit_prediction_scroll_popover(
 9495                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9496                IconName::ArrowDown,
 9497                visible_row_range,
 9498                line_layouts,
 9499                newest_selection_head,
 9500                scrolled_content_origin,
 9501                window,
 9502                cx,
 9503            );
 9504        }
 9505
 9506        const POLE_WIDTH: Pixels = px(2.);
 9507
 9508        let line_layout =
 9509            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9510        let target_column = target_display_point.column() as usize;
 9511
 9512        let target_x = line_layout.x_for_index(target_column);
 9513        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9514            - scroll_pixel_position.y;
 9515
 9516        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9517
 9518        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9519        border_color.l += 0.001;
 9520
 9521        let mut element = v_flex()
 9522            .items_end()
 9523            .when(flag_on_right, |el| el.items_start())
 9524            .child(if flag_on_right {
 9525                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9526                    .rounded_bl(px(0.))
 9527                    .rounded_tl(px(0.))
 9528                    .border_l_2()
 9529                    .border_color(border_color)
 9530            } else {
 9531                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9532                    .rounded_br(px(0.))
 9533                    .rounded_tr(px(0.))
 9534                    .border_r_2()
 9535                    .border_color(border_color)
 9536            })
 9537            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9538            .into_any();
 9539
 9540        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9541
 9542        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9543            - point(
 9544                if flag_on_right {
 9545                    POLE_WIDTH
 9546                } else {
 9547                    size.width - POLE_WIDTH
 9548                },
 9549                size.height - line_height,
 9550            );
 9551
 9552        origin.x = origin.x.max(content_origin.x);
 9553
 9554        element.prepaint_at(origin, window, cx);
 9555
 9556        Some((element, origin))
 9557    }
 9558
 9559    fn render_edit_prediction_scroll_popover(
 9560        &mut self,
 9561        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9562        scroll_icon: IconName,
 9563        visible_row_range: Range<DisplayRow>,
 9564        line_layouts: &[LineWithInvisibles],
 9565        newest_selection_head: Option<DisplayPoint>,
 9566        scrolled_content_origin: gpui::Point<Pixels>,
 9567        window: &mut Window,
 9568        cx: &mut App,
 9569    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9570        let mut element = self
 9571            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9572            .into_any();
 9573
 9574        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9575
 9576        let cursor = newest_selection_head?;
 9577        let cursor_row_layout =
 9578            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9579        let cursor_column = cursor.column() as usize;
 9580
 9581        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9582
 9583        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9584
 9585        element.prepaint_at(origin, window, cx);
 9586        Some((element, origin))
 9587    }
 9588
 9589    fn render_edit_prediction_eager_jump_popover(
 9590        &mut self,
 9591        text_bounds: &Bounds<Pixels>,
 9592        content_origin: gpui::Point<Pixels>,
 9593        editor_snapshot: &EditorSnapshot,
 9594        visible_row_range: Range<DisplayRow>,
 9595        scroll_top: ScrollOffset,
 9596        scroll_bottom: ScrollOffset,
 9597        line_height: Pixels,
 9598        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9599        target_display_point: DisplayPoint,
 9600        editor_width: Pixels,
 9601        window: &mut Window,
 9602        cx: &mut App,
 9603    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9604        if target_display_point.row().as_f64() < scroll_top {
 9605            let mut element = self
 9606                .render_edit_prediction_line_popover(
 9607                    "Jump to Edit",
 9608                    Some(IconName::ArrowUp),
 9609                    window,
 9610                    cx,
 9611                )
 9612                .into_any();
 9613
 9614            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9615            let offset = point(
 9616                (text_bounds.size.width - size.width) / 2.,
 9617                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9618            );
 9619
 9620            let origin = text_bounds.origin + offset;
 9621            element.prepaint_at(origin, window, cx);
 9622            Some((element, origin))
 9623        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9624            let mut element = self
 9625                .render_edit_prediction_line_popover(
 9626                    "Jump to Edit",
 9627                    Some(IconName::ArrowDown),
 9628                    window,
 9629                    cx,
 9630                )
 9631                .into_any();
 9632
 9633            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9634            let offset = point(
 9635                (text_bounds.size.width - size.width) / 2.,
 9636                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9637            );
 9638
 9639            let origin = text_bounds.origin + offset;
 9640            element.prepaint_at(origin, window, cx);
 9641            Some((element, origin))
 9642        } else {
 9643            self.render_edit_prediction_end_of_line_popover(
 9644                "Jump to Edit",
 9645                editor_snapshot,
 9646                visible_row_range,
 9647                target_display_point,
 9648                line_height,
 9649                scroll_pixel_position,
 9650                content_origin,
 9651                editor_width,
 9652                window,
 9653                cx,
 9654            )
 9655        }
 9656    }
 9657
 9658    fn render_edit_prediction_end_of_line_popover(
 9659        self: &mut Editor,
 9660        label: &'static str,
 9661        editor_snapshot: &EditorSnapshot,
 9662        visible_row_range: Range<DisplayRow>,
 9663        target_display_point: DisplayPoint,
 9664        line_height: Pixels,
 9665        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9666        content_origin: gpui::Point<Pixels>,
 9667        editor_width: Pixels,
 9668        window: &mut Window,
 9669        cx: &mut App,
 9670    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9671        let target_line_end = DisplayPoint::new(
 9672            target_display_point.row(),
 9673            editor_snapshot.line_len(target_display_point.row()),
 9674        );
 9675
 9676        let mut element = self
 9677            .render_edit_prediction_line_popover(label, None, window, cx)
 9678            .into_any();
 9679
 9680        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9681
 9682        let line_origin =
 9683            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9684
 9685        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9686        let mut origin = start_point
 9687            + line_origin
 9688            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9689        origin.x = origin.x.max(content_origin.x);
 9690
 9691        let max_x = content_origin.x + editor_width - size.width;
 9692
 9693        if origin.x > max_x {
 9694            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9695
 9696            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9697                origin.y += offset;
 9698                IconName::ArrowUp
 9699            } else {
 9700                origin.y -= offset;
 9701                IconName::ArrowDown
 9702            };
 9703
 9704            element = self
 9705                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9706                .into_any();
 9707
 9708            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9709
 9710            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9711        }
 9712
 9713        element.prepaint_at(origin, window, cx);
 9714        Some((element, origin))
 9715    }
 9716
 9717    fn render_edit_prediction_diff_popover(
 9718        self: &Editor,
 9719        text_bounds: &Bounds<Pixels>,
 9720        content_origin: gpui::Point<Pixels>,
 9721        right_margin: Pixels,
 9722        editor_snapshot: &EditorSnapshot,
 9723        visible_row_range: Range<DisplayRow>,
 9724        line_layouts: &[LineWithInvisibles],
 9725        line_height: Pixels,
 9726        scroll_position: gpui::Point<ScrollOffset>,
 9727        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9728        newest_selection_head: Option<DisplayPoint>,
 9729        editor_width: Pixels,
 9730        style: &EditorStyle,
 9731        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9732        edit_preview: &Option<language::EditPreview>,
 9733        snapshot: &language::BufferSnapshot,
 9734        window: &mut Window,
 9735        cx: &mut App,
 9736    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9737        let edit_start = edits
 9738            .first()
 9739            .unwrap()
 9740            .0
 9741            .start
 9742            .to_display_point(editor_snapshot);
 9743        let edit_end = edits
 9744            .last()
 9745            .unwrap()
 9746            .0
 9747            .end
 9748            .to_display_point(editor_snapshot);
 9749
 9750        let is_visible = visible_row_range.contains(&edit_start.row())
 9751            || visible_row_range.contains(&edit_end.row());
 9752        if !is_visible {
 9753            return None;
 9754        }
 9755
 9756        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9757            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9758        } else {
 9759            // Fallback for providers without edit_preview
 9760            crate::edit_prediction_fallback_text(edits, cx)
 9761        };
 9762
 9763        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9764        let line_count = highlighted_edits.text.lines().count();
 9765
 9766        const BORDER_WIDTH: Pixels = px(1.);
 9767
 9768        let keybind = self.render_edit_prediction_keybind(window, cx);
 9769        let has_keybind = keybind.is_some();
 9770
 9771        let mut element = h_flex()
 9772            .items_start()
 9773            .child(
 9774                h_flex()
 9775                    .bg(cx.theme().colors().editor_background)
 9776                    .border(BORDER_WIDTH)
 9777                    .shadow_xs()
 9778                    .border_color(cx.theme().colors().border)
 9779                    .rounded_l_lg()
 9780                    .when(line_count > 1, |el| el.rounded_br_lg())
 9781                    .pr_1()
 9782                    .child(styled_text),
 9783            )
 9784            .child(
 9785                h_flex()
 9786                    .h(line_height + BORDER_WIDTH * 2.)
 9787                    .px_1p5()
 9788                    .gap_1()
 9789                    // Workaround: For some reason, there's a gap if we don't do this
 9790                    .ml(-BORDER_WIDTH)
 9791                    .shadow(vec![gpui::BoxShadow {
 9792                        color: gpui::black().opacity(0.05),
 9793                        offset: point(px(1.), px(1.)),
 9794                        blur_radius: px(2.),
 9795                        spread_radius: px(0.),
 9796                    }])
 9797                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9798                    .border(BORDER_WIDTH)
 9799                    .border_color(cx.theme().colors().border)
 9800                    .rounded_r_lg()
 9801                    .id("edit_prediction_diff_popover_keybind")
 9802                    .when(!has_keybind, |el| {
 9803                        let status_colors = cx.theme().status();
 9804
 9805                        el.bg(status_colors.error_background)
 9806                            .border_color(status_colors.error.opacity(0.6))
 9807                            .child(Icon::new(IconName::Info).color(Color::Error))
 9808                            .cursor_default()
 9809                            .hoverable_tooltip(move |_window, cx| {
 9810                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9811                            })
 9812                    })
 9813                    .children(keybind),
 9814            )
 9815            .into_any();
 9816
 9817        let longest_row =
 9818            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9819        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9820            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9821        } else {
 9822            layout_line(
 9823                longest_row,
 9824                editor_snapshot,
 9825                style,
 9826                editor_width,
 9827                |_| false,
 9828                window,
 9829                cx,
 9830            )
 9831            .width
 9832        };
 9833
 9834        let viewport_bounds =
 9835            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9836                right: -right_margin,
 9837                ..Default::default()
 9838            });
 9839
 9840        let x_after_longest = Pixels::from(
 9841            ScrollPixelOffset::from(
 9842                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9843            ) - scroll_pixel_position.x,
 9844        );
 9845
 9846        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9847
 9848        // Fully visible if it can be displayed within the window (allow overlapping other
 9849        // panes). However, this is only allowed if the popover starts within text_bounds.
 9850        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9851            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9852
 9853        let mut origin = if can_position_to_the_right {
 9854            point(
 9855                x_after_longest,
 9856                text_bounds.origin.y
 9857                    + Pixels::from(
 9858                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9859                            - scroll_pixel_position.y,
 9860                    ),
 9861            )
 9862        } else {
 9863            let cursor_row = newest_selection_head.map(|head| head.row());
 9864            let above_edit = edit_start
 9865                .row()
 9866                .0
 9867                .checked_sub(line_count as u32)
 9868                .map(DisplayRow);
 9869            let below_edit = Some(edit_end.row() + 1);
 9870            let above_cursor =
 9871                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9872            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9873
 9874            // Place the edit popover adjacent to the edit if there is a location
 9875            // available that is onscreen and does not obscure the cursor. Otherwise,
 9876            // place it adjacent to the cursor.
 9877            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9878                .into_iter()
 9879                .flatten()
 9880                .find(|&start_row| {
 9881                    let end_row = start_row + line_count as u32;
 9882                    visible_row_range.contains(&start_row)
 9883                        && visible_row_range.contains(&end_row)
 9884                        && cursor_row
 9885                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9886                })?;
 9887
 9888            content_origin
 9889                + point(
 9890                    Pixels::from(-scroll_pixel_position.x),
 9891                    Pixels::from(
 9892                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9893                    ),
 9894                )
 9895        };
 9896
 9897        origin.x -= BORDER_WIDTH;
 9898
 9899        window.with_content_mask(
 9900            Some(gpui::ContentMask {
 9901                bounds: *text_bounds,
 9902            }),
 9903            |window| {
 9904                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9905            },
 9906        );
 9907
 9908        // Do not return an element, since it will already be drawn due to defer_draw.
 9909        None
 9910    }
 9911
 9912    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9913        px(30.)
 9914    }
 9915
 9916    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9917        if self.read_only(cx) {
 9918            cx.theme().players().read_only()
 9919        } else {
 9920            self.style.as_ref().unwrap().local_player
 9921        }
 9922    }
 9923
 9924    fn render_edit_prediction_inline_keystroke(
 9925        &self,
 9926        keystroke: &gpui::KeybindingKeystroke,
 9927        modifiers_color: Color,
 9928        cx: &App,
 9929    ) -> AnyElement {
 9930        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9931
 9932        h_flex()
 9933            .px_0p5()
 9934            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9935            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9936            .text_size(TextSize::XSmall.rems(cx))
 9937            .child(h_flex().children(ui::render_modifiers(
 9938                keystroke.modifiers(),
 9939                PlatformStyle::platform(),
 9940                Some(modifiers_color),
 9941                Some(IconSize::XSmall.rems().into()),
 9942                true,
 9943            )))
 9944            .when(is_platform_style_mac, |parent| {
 9945                parent.child(keystroke.key().to_string())
 9946            })
 9947            .when(!is_platform_style_mac, |parent| {
 9948                parent.child(
 9949                    Key::new(util::capitalize(keystroke.key()), Some(Color::Default))
 9950                        .size(Some(IconSize::XSmall.rems().into())),
 9951                )
 9952            })
 9953            .into_any()
 9954    }
 9955
 9956    fn render_edit_prediction_popover_keystroke(
 9957        &self,
 9958        keystroke: &gpui::KeybindingKeystroke,
 9959        color: Color,
 9960        cx: &App,
 9961    ) -> AnyElement {
 9962        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9963
 9964        if keystroke.modifiers().modified() {
 9965            h_flex()
 9966                .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9967                .when(is_platform_style_mac, |parent| parent.gap_1())
 9968                .child(h_flex().children(ui::render_modifiers(
 9969                    keystroke.modifiers(),
 9970                    PlatformStyle::platform(),
 9971                    Some(color),
 9972                    None,
 9973                    false,
 9974                )))
 9975                .into_any()
 9976        } else {
 9977            Key::new(util::capitalize(keystroke.key()), Some(color))
 9978                .size(Some(IconSize::XSmall.rems().into()))
 9979                .into_any_element()
 9980        }
 9981    }
 9982
 9983    fn render_edit_prediction_keybind(
 9984        &self,
 9985        window: &mut Window,
 9986        cx: &mut App,
 9987    ) -> Option<AnyElement> {
 9988        let keybind_display =
 9989            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
 9990        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
 9991
 9992        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
 9993            Color::Accent
 9994        } else {
 9995            Color::Muted
 9996        };
 9997
 9998        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
 9999    }
10000
10001    fn render_edit_prediction_line_popover(
10002        &self,
10003        label: impl Into<SharedString>,
10004        icon: Option<IconName>,
10005        window: &mut Window,
10006        cx: &mut App,
10007    ) -> Stateful<Div> {
10008        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10009
10010        let keybind = self.render_edit_prediction_keybind(window, cx);
10011        let has_keybind = keybind.is_some();
10012        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10013
10014        h_flex()
10015            .id("ep-line-popover")
10016            .py_0p5()
10017            .pl_1()
10018            .pr(padding_right)
10019            .gap_1()
10020            .rounded_md()
10021            .border_1()
10022            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10023            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10024            .shadow_xs()
10025            .when(!has_keybind, |el| {
10026                let status_colors = cx.theme().status();
10027
10028                el.bg(status_colors.error_background)
10029                    .border_color(status_colors.error.opacity(0.6))
10030                    .pl_2()
10031                    .child(Icon::new(icons.error).color(Color::Error))
10032                    .cursor_default()
10033                    .hoverable_tooltip(move |_window, cx| {
10034                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10035                    })
10036            })
10037            .children(keybind)
10038            .child(
10039                Label::new(label)
10040                    .size(LabelSize::Small)
10041                    .when(!has_keybind, |el| {
10042                        el.color(cx.theme().status().error.into()).strikethrough()
10043                    }),
10044            )
10045            .when(!has_keybind, |el| {
10046                el.child(
10047                    h_flex().ml_1().child(
10048                        Icon::new(IconName::Info)
10049                            .size(IconSize::Small)
10050                            .color(cx.theme().status().error.into()),
10051                    ),
10052                )
10053            })
10054            .when_some(icon, |element, icon| {
10055                element.child(
10056                    div()
10057                        .mt(px(1.5))
10058                        .child(Icon::new(icon).size(IconSize::Small)),
10059                )
10060            })
10061    }
10062
10063    fn render_edit_prediction_jump_outside_popover(
10064        &self,
10065        snapshot: &BufferSnapshot,
10066        window: &mut Window,
10067        cx: &mut App,
10068    ) -> Stateful<Div> {
10069        let keybind = self.render_edit_prediction_keybind(window, cx);
10070        let has_keybind = keybind.is_some();
10071        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10072
10073        let file_name = snapshot
10074            .file()
10075            .map(|file| SharedString::new(file.file_name(cx)))
10076            .unwrap_or(SharedString::new_static("untitled"));
10077
10078        h_flex()
10079            .id("ep-jump-outside-popover")
10080            .py_1()
10081            .px_2()
10082            .gap_1()
10083            .rounded_md()
10084            .border_1()
10085            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10086            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10087            .shadow_xs()
10088            .when(!has_keybind, |el| {
10089                let status_colors = cx.theme().status();
10090
10091                el.bg(status_colors.error_background)
10092                    .border_color(status_colors.error.opacity(0.6))
10093                    .pl_2()
10094                    .child(Icon::new(icons.error).color(Color::Error))
10095                    .cursor_default()
10096                    .hoverable_tooltip(move |_window, cx| {
10097                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10098                    })
10099            })
10100            .children(keybind)
10101            .child(
10102                Label::new(file_name)
10103                    .size(LabelSize::Small)
10104                    .buffer_font(cx)
10105                    .when(!has_keybind, |el| {
10106                        el.color(cx.theme().status().error.into()).strikethrough()
10107                    }),
10108            )
10109            .when(!has_keybind, |el| {
10110                el.child(
10111                    h_flex().ml_1().child(
10112                        Icon::new(IconName::Info)
10113                            .size(IconSize::Small)
10114                            .color(cx.theme().status().error.into()),
10115                    ),
10116                )
10117            })
10118            .child(
10119                div()
10120                    .mt(px(1.5))
10121                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10122            )
10123    }
10124
10125    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10126        let accent_color = cx.theme().colors().text_accent;
10127        let editor_bg_color = cx.theme().colors().editor_background;
10128        editor_bg_color.blend(accent_color.opacity(0.1))
10129    }
10130
10131    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
10132        let accent_color = cx.theme().colors().text_accent;
10133        let editor_bg_color = cx.theme().colors().editor_background;
10134        editor_bg_color.blend(accent_color.opacity(0.6))
10135    }
10136    fn get_prediction_provider_icons(
10137        provider: &Option<RegisteredEditPredictionDelegate>,
10138        cx: &App,
10139    ) -> edit_prediction_types::EditPredictionIconSet {
10140        match provider {
10141            Some(provider) => provider.provider.icons(cx),
10142            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10143        }
10144    }
10145
10146    fn render_edit_prediction_cursor_popover(
10147        &self,
10148        min_width: Pixels,
10149        max_width: Pixels,
10150        cursor_point: Point,
10151        style: &EditorStyle,
10152        window: &mut Window,
10153        cx: &mut Context<Editor>,
10154    ) -> Option<AnyElement> {
10155        let provider = self.edit_prediction_provider.as_ref()?;
10156        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10157
10158        let is_refreshing = provider.provider.is_refreshing(cx);
10159
10160        fn pending_completion_container(icon: IconName) -> Div {
10161            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10162        }
10163
10164        let completion = match &self.active_edit_prediction {
10165            Some(prediction) => {
10166                if !self.has_visible_completions_menu() {
10167                    const RADIUS: Pixels = px(6.);
10168                    const BORDER_WIDTH: Pixels = px(1.);
10169                    let keybind_display = self.edit_prediction_keybind_display(
10170                        EditPredictionKeybindSurface::CursorPopoverCompact,
10171                        window,
10172                        cx,
10173                    );
10174
10175                    return Some(
10176                        h_flex()
10177                            .elevation_2(cx)
10178                            .border(BORDER_WIDTH)
10179                            .border_color(cx.theme().colors().border)
10180                            .when(keybind_display.missing_accept_keystroke, |el| {
10181                                el.border_color(cx.theme().status().error)
10182                            })
10183                            .rounded(RADIUS)
10184                            .rounded_tl(px(0.))
10185                            .overflow_hidden()
10186                            .child(div().px_1p5().child(match &prediction.completion {
10187                                EditPrediction::MoveWithin { target, snapshot } => {
10188                                    use text::ToPoint as _;
10189                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
10190                                    {
10191                                        Icon::new(icons.down)
10192                                    } else {
10193                                        Icon::new(icons.up)
10194                                    }
10195                                }
10196                                EditPrediction::MoveOutside { .. } => {
10197                                    // TODO [zeta2] custom icon for external jump?
10198                                    Icon::new(icons.base)
10199                                }
10200                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10201                            }))
10202                            .child(
10203                                h_flex()
10204                                    .gap_1()
10205                                    .py_1()
10206                                    .px_2()
10207                                    .rounded_r(RADIUS - BORDER_WIDTH)
10208                                    .border_l_1()
10209                                    .border_color(cx.theme().colors().border)
10210                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10211                                    .when(keybind_display.show_hold_label, |el| {
10212                                        el.child(
10213                                            Label::new("Hold")
10214                                                .size(LabelSize::Small)
10215                                                .when(
10216                                                    keybind_display.missing_accept_keystroke,
10217                                                    |el| el.strikethrough(),
10218                                                )
10219                                                .line_height_style(LineHeightStyle::UiLabel),
10220                                        )
10221                                    })
10222                                    .id("edit_prediction_cursor_popover_keybind")
10223                                    .when(keybind_display.missing_accept_keystroke, |el| {
10224                                        let status_colors = cx.theme().status();
10225
10226                                        el.bg(status_colors.error_background)
10227                                            .border_color(status_colors.error.opacity(0.6))
10228                                            .child(Icon::new(IconName::Info).color(Color::Error))
10229                                            .cursor_default()
10230                                            .hoverable_tooltip(move |_window, cx| {
10231                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10232                                                    .into()
10233                                            })
10234                                    })
10235                                    .when_some(
10236                                        keybind_display.displayed_keystroke.as_ref(),
10237                                        |el, compact_keystroke| {
10238                                            el.child(self.render_edit_prediction_popover_keystroke(
10239                                                compact_keystroke,
10240                                                Color::Default,
10241                                                cx,
10242                                            ))
10243                                        },
10244                                    ),
10245                            )
10246                            .into_any(),
10247                    );
10248                }
10249
10250                self.render_edit_prediction_cursor_popover_preview(
10251                    prediction,
10252                    cursor_point,
10253                    style,
10254                    cx,
10255                )?
10256            }
10257
10258            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10259                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10260                    stale_completion,
10261                    cursor_point,
10262                    style,
10263                    cx,
10264                )?,
10265
10266                None => pending_completion_container(icons.base)
10267                    .child(Label::new("...").size(LabelSize::Small)),
10268            },
10269
10270            None => pending_completion_container(icons.base)
10271                .child(Label::new("...").size(LabelSize::Small)),
10272        };
10273
10274        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10275            completion
10276                .with_animation(
10277                    "loading-completion",
10278                    Animation::new(Duration::from_secs(2))
10279                        .repeat()
10280                        .with_easing(pulsating_between(0.4, 0.8)),
10281                    |label, delta| label.opacity(delta),
10282                )
10283                .into_any_element()
10284        } else {
10285            completion.into_any_element()
10286        };
10287
10288        let has_completion = self.active_edit_prediction.is_some();
10289        let keybind_display = self.edit_prediction_keybind_display(
10290            EditPredictionKeybindSurface::CursorPopoverExpanded,
10291            window,
10292            cx,
10293        );
10294
10295        Some(
10296            h_flex()
10297                .min_w(min_width)
10298                .max_w(max_width)
10299                .flex_1()
10300                .elevation_2(cx)
10301                .border_color(cx.theme().colors().border)
10302                .child(
10303                    div()
10304                        .flex_1()
10305                        .py_1()
10306                        .px_2()
10307                        .overflow_hidden()
10308                        .child(completion),
10309                )
10310                .when_some(
10311                    keybind_display.displayed_keystroke.as_ref(),
10312                    |el, keystroke| {
10313                        let key_color = if !has_completion {
10314                            Color::Muted
10315                        } else {
10316                            Color::Default
10317                        };
10318
10319                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10320                            el.child(
10321                                h_flex()
10322                                    .h_full()
10323                                    .border_l_1()
10324                                    .rounded_r_lg()
10325                                    .border_color(cx.theme().colors().border)
10326                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10327                                    .gap_1()
10328                                    .py_1()
10329                                    .px_2()
10330                                    .child(self.render_edit_prediction_popover_keystroke(
10331                                        keystroke, key_color, cx,
10332                                    ))
10333                                    .child(Label::new("Preview").into_any_element())
10334                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10335                            )
10336                        } else {
10337                            el.child(
10338                                h_flex()
10339                                    .h_full()
10340                                    .border_l_1()
10341                                    .rounded_r_lg()
10342                                    .border_color(cx.theme().colors().border)
10343                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10344                                    .gap_1()
10345                                    .py_1()
10346                                    .px_2()
10347                                    .child(self.render_edit_prediction_popover_keystroke(
10348                                        keystroke, key_color, cx,
10349                                    ))
10350                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10351                            )
10352                        }
10353                    },
10354                )
10355                .into_any(),
10356        )
10357    }
10358
10359    fn render_edit_prediction_cursor_popover_preview(
10360        &self,
10361        completion: &EditPredictionState,
10362        cursor_point: Point,
10363        style: &EditorStyle,
10364        cx: &mut Context<Editor>,
10365    ) -> Option<Div> {
10366        use text::ToPoint as _;
10367
10368        fn render_relative_row_jump(
10369            prefix: impl Into<String>,
10370            current_row: u32,
10371            target_row: u32,
10372        ) -> Div {
10373            let (row_diff, arrow) = if target_row < current_row {
10374                (current_row - target_row, IconName::ArrowUp)
10375            } else {
10376                (target_row - current_row, IconName::ArrowDown)
10377            };
10378
10379            h_flex()
10380                .child(
10381                    Label::new(format!("{}{}", prefix.into(), row_diff))
10382                        .color(Color::Muted)
10383                        .size(LabelSize::Small),
10384                )
10385                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10386        }
10387
10388        let supports_jump = self
10389            .edit_prediction_provider
10390            .as_ref()
10391            .map(|provider| provider.provider.supports_jump_to_edit())
10392            .unwrap_or(true);
10393
10394        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10395
10396        match &completion.completion {
10397            EditPrediction::MoveWithin {
10398                target, snapshot, ..
10399            } => {
10400                if !supports_jump {
10401                    return None;
10402                }
10403
10404                Some(
10405                    h_flex()
10406                        .px_2()
10407                        .gap_2()
10408                        .flex_1()
10409                        .child(
10410                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10411                                Icon::new(icons.down)
10412                            } else {
10413                                Icon::new(icons.up)
10414                            },
10415                        )
10416                        .child(Label::new("Jump to Edit")),
10417                )
10418            }
10419            EditPrediction::MoveOutside { snapshot, .. } => {
10420                let file_name = snapshot
10421                    .file()
10422                    .map(|file| file.file_name(cx))
10423                    .unwrap_or("untitled");
10424                Some(
10425                    h_flex()
10426                        .px_2()
10427                        .gap_2()
10428                        .flex_1()
10429                        .child(Icon::new(icons.base))
10430                        .child(Label::new(format!("Jump to {file_name}"))),
10431                )
10432            }
10433            EditPrediction::Edit {
10434                edits,
10435                edit_preview,
10436                snapshot,
10437                ..
10438            } => {
10439                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10440
10441                let (highlighted_edits, has_more_lines) =
10442                    if let Some(edit_preview) = edit_preview.as_ref() {
10443                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10444                            .first_line_preview()
10445                    } else {
10446                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10447                    };
10448
10449                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10450                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10451
10452                let preview = h_flex()
10453                    .gap_1()
10454                    .min_w_16()
10455                    .child(styled_text)
10456                    .when(has_more_lines, |parent| parent.child(""));
10457
10458                let left = if supports_jump && first_edit_row != cursor_point.row {
10459                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10460                        .into_any_element()
10461                } else {
10462                    Icon::new(icons.base).into_any_element()
10463                };
10464
10465                Some(
10466                    h_flex()
10467                        .h_full()
10468                        .flex_1()
10469                        .gap_2()
10470                        .pr_1()
10471                        .overflow_x_hidden()
10472                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10473                        .child(left)
10474                        .child(preview),
10475                )
10476            }
10477        }
10478    }
10479
10480    pub fn render_context_menu(
10481        &mut self,
10482        max_height_in_lines: u32,
10483        window: &mut Window,
10484        cx: &mut Context<Editor>,
10485    ) -> Option<AnyElement> {
10486        let menu = self.context_menu.borrow();
10487        let menu = menu.as_ref()?;
10488        if !menu.visible() {
10489            return None;
10490        };
10491        self.style
10492            .as_ref()
10493            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10494    }
10495
10496    fn render_context_menu_aside(
10497        &mut self,
10498        max_size: Size<Pixels>,
10499        window: &mut Window,
10500        cx: &mut Context<Editor>,
10501    ) -> Option<AnyElement> {
10502        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10503            if menu.visible() {
10504                menu.render_aside(max_size, window, cx)
10505            } else {
10506                None
10507            }
10508        })
10509    }
10510
10511    fn hide_context_menu(
10512        &mut self,
10513        window: &mut Window,
10514        cx: &mut Context<Self>,
10515    ) -> Option<CodeContextMenu> {
10516        cx.notify();
10517        self.completion_tasks.clear();
10518        let context_menu = self.context_menu.borrow_mut().take();
10519        self.stale_edit_prediction_in_menu.take();
10520        self.update_visible_edit_prediction(window, cx);
10521        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10522            && let Some(completion_provider) = &self.completion_provider
10523        {
10524            completion_provider.selection_changed(None, window, cx);
10525        }
10526        context_menu
10527    }
10528
10529    fn show_snippet_choices(
10530        &mut self,
10531        choices: &Vec<String>,
10532        selection: Range<Anchor>,
10533        cx: &mut Context<Self>,
10534    ) {
10535        let Some((_, buffer, _)) = self
10536            .buffer()
10537            .read(cx)
10538            .excerpt_containing(selection.start, cx)
10539        else {
10540            return;
10541        };
10542        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10543        else {
10544            return;
10545        };
10546        if buffer != end_buffer {
10547            log::error!("expected anchor range to have matching buffer IDs");
10548            return;
10549        }
10550
10551        let id = post_inc(&mut self.next_completion_id);
10552        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10553        let mut context_menu = self.context_menu.borrow_mut();
10554        let old_menu = context_menu.take();
10555        *context_menu = Some(CodeContextMenu::Completions(
10556            CompletionsMenu::new_snippet_choices(
10557                id,
10558                true,
10559                choices,
10560                selection,
10561                buffer,
10562                old_menu.map(|menu| menu.primary_scroll_handle()),
10563                snippet_sort_order,
10564            ),
10565        ));
10566    }
10567
10568    pub fn insert_snippet(
10569        &mut self,
10570        insertion_ranges: &[Range<MultiBufferOffset>],
10571        snippet: Snippet,
10572        window: &mut Window,
10573        cx: &mut Context<Self>,
10574    ) -> Result<()> {
10575        struct Tabstop<T> {
10576            is_end_tabstop: bool,
10577            ranges: Vec<Range<T>>,
10578            choices: Option<Vec<String>>,
10579        }
10580
10581        let tabstops = self.buffer.update(cx, |buffer, cx| {
10582            let snippet_text: Arc<str> = snippet.text.clone().into();
10583            let edits = insertion_ranges
10584                .iter()
10585                .cloned()
10586                .map(|range| (range, snippet_text.clone()));
10587            let autoindent_mode = AutoindentMode::Block {
10588                original_indent_columns: Vec::new(),
10589            };
10590            buffer.edit(edits, Some(autoindent_mode), cx);
10591
10592            let snapshot = &*buffer.read(cx);
10593            let snippet = &snippet;
10594            snippet
10595                .tabstops
10596                .iter()
10597                .map(|tabstop| {
10598                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10599                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10600                    });
10601                    let mut tabstop_ranges = tabstop
10602                        .ranges
10603                        .iter()
10604                        .flat_map(|tabstop_range| {
10605                            let mut delta = 0_isize;
10606                            insertion_ranges.iter().map(move |insertion_range| {
10607                                let insertion_start = insertion_range.start + delta;
10608                                delta += snippet.text.len() as isize
10609                                    - (insertion_range.end - insertion_range.start) as isize;
10610
10611                                let start =
10612                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10613                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10614                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10615                            })
10616                        })
10617                        .collect::<Vec<_>>();
10618                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10619
10620                    Tabstop {
10621                        is_end_tabstop,
10622                        ranges: tabstop_ranges,
10623                        choices: tabstop.choices.clone(),
10624                    }
10625                })
10626                .collect::<Vec<_>>()
10627        });
10628        if let Some(tabstop) = tabstops.first() {
10629            self.change_selections(Default::default(), window, cx, |s| {
10630                // Reverse order so that the first range is the newest created selection.
10631                // Completions will use it and autoscroll will prioritize it.
10632                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10633            });
10634
10635            if let Some(choices) = &tabstop.choices
10636                && let Some(selection) = tabstop.ranges.first()
10637            {
10638                self.show_snippet_choices(choices, selection.clone(), cx)
10639            }
10640
10641            // If we're already at the last tabstop and it's at the end of the snippet,
10642            // we're done, we don't need to keep the state around.
10643            if !tabstop.is_end_tabstop {
10644                let choices = tabstops
10645                    .iter()
10646                    .map(|tabstop| tabstop.choices.clone())
10647                    .collect();
10648
10649                let ranges = tabstops
10650                    .into_iter()
10651                    .map(|tabstop| tabstop.ranges)
10652                    .collect::<Vec<_>>();
10653
10654                self.snippet_stack.push(SnippetState {
10655                    active_index: 0,
10656                    ranges,
10657                    choices,
10658                });
10659            }
10660
10661            // Check whether the just-entered snippet ends with an auto-closable bracket.
10662            if self.autoclose_regions.is_empty() {
10663                let snapshot = self.buffer.read(cx).snapshot(cx);
10664                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10665                    let selection_head = selection.head();
10666                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10667                        continue;
10668                    };
10669
10670                    let mut bracket_pair = None;
10671                    let max_lookup_length = scope
10672                        .brackets()
10673                        .map(|(pair, _)| {
10674                            pair.start
10675                                .as_str()
10676                                .chars()
10677                                .count()
10678                                .max(pair.end.as_str().chars().count())
10679                        })
10680                        .max();
10681                    if let Some(max_lookup_length) = max_lookup_length {
10682                        let next_text = snapshot
10683                            .chars_at(selection_head)
10684                            .take(max_lookup_length)
10685                            .collect::<String>();
10686                        let prev_text = snapshot
10687                            .reversed_chars_at(selection_head)
10688                            .take(max_lookup_length)
10689                            .collect::<String>();
10690
10691                        for (pair, enabled) in scope.brackets() {
10692                            if enabled
10693                                && pair.close
10694                                && prev_text.starts_with(pair.start.as_str())
10695                                && next_text.starts_with(pair.end.as_str())
10696                            {
10697                                bracket_pair = Some(pair.clone());
10698                                break;
10699                            }
10700                        }
10701                    }
10702
10703                    if let Some(pair) = bracket_pair {
10704                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10705                        let autoclose_enabled =
10706                            self.use_autoclose && snapshot_settings.use_autoclose;
10707                        if autoclose_enabled {
10708                            let start = snapshot.anchor_after(selection_head);
10709                            let end = snapshot.anchor_after(selection_head);
10710                            self.autoclose_regions.push(AutocloseRegion {
10711                                selection_id: selection.id,
10712                                range: start..end,
10713                                pair,
10714                            });
10715                        }
10716                    }
10717                }
10718            }
10719        }
10720        Ok(())
10721    }
10722
10723    pub fn move_to_next_snippet_tabstop(
10724        &mut self,
10725        window: &mut Window,
10726        cx: &mut Context<Self>,
10727    ) -> bool {
10728        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10729    }
10730
10731    pub fn move_to_prev_snippet_tabstop(
10732        &mut self,
10733        window: &mut Window,
10734        cx: &mut Context<Self>,
10735    ) -> bool {
10736        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10737    }
10738
10739    pub fn move_to_snippet_tabstop(
10740        &mut self,
10741        bias: Bias,
10742        window: &mut Window,
10743        cx: &mut Context<Self>,
10744    ) -> bool {
10745        if let Some(mut snippet) = self.snippet_stack.pop() {
10746            match bias {
10747                Bias::Left => {
10748                    if snippet.active_index > 0 {
10749                        snippet.active_index -= 1;
10750                    } else {
10751                        self.snippet_stack.push(snippet);
10752                        return false;
10753                    }
10754                }
10755                Bias::Right => {
10756                    if snippet.active_index + 1 < snippet.ranges.len() {
10757                        snippet.active_index += 1;
10758                    } else {
10759                        self.snippet_stack.push(snippet);
10760                        return false;
10761                    }
10762                }
10763            }
10764            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10765                self.change_selections(Default::default(), window, cx, |s| {
10766                    // Reverse order so that the first range is the newest created selection.
10767                    // Completions will use it and autoscroll will prioritize it.
10768                    s.select_ranges(current_ranges.iter().rev().cloned())
10769                });
10770
10771                if let Some(choices) = &snippet.choices[snippet.active_index]
10772                    && let Some(selection) = current_ranges.first()
10773                {
10774                    self.show_snippet_choices(choices, selection.clone(), cx);
10775                }
10776
10777                // If snippet state is not at the last tabstop, push it back on the stack
10778                if snippet.active_index + 1 < snippet.ranges.len() {
10779                    self.snippet_stack.push(snippet);
10780                }
10781                return true;
10782            }
10783        }
10784
10785        false
10786    }
10787
10788    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10789        self.transact(window, cx, |this, window, cx| {
10790            this.select_all(&SelectAll, window, cx);
10791            this.insert("", window, cx);
10792        });
10793    }
10794
10795    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10796        if self.read_only(cx) {
10797            return;
10798        }
10799        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10800        self.transact(window, cx, |this, window, cx| {
10801            this.select_autoclose_pair(window, cx);
10802
10803            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10804
10805            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10806            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10807            for selection in &mut selections {
10808                if selection.is_empty() {
10809                    let old_head = selection.head();
10810                    let mut new_head =
10811                        movement::left(&display_map, old_head.to_display_point(&display_map))
10812                            .to_point(&display_map);
10813                    if let Some((buffer, line_buffer_range)) = display_map
10814                        .buffer_snapshot()
10815                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10816                    {
10817                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10818                        let indent_len = match indent_size.kind {
10819                            IndentKind::Space => {
10820                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10821                            }
10822                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10823                        };
10824                        if old_head.column <= indent_size.len && old_head.column > 0 {
10825                            let indent_len = indent_len.get();
10826                            new_head = cmp::min(
10827                                new_head,
10828                                MultiBufferPoint::new(
10829                                    old_head.row,
10830                                    ((old_head.column - 1) / indent_len) * indent_len,
10831                                ),
10832                            );
10833                        }
10834                    }
10835
10836                    selection.set_head(new_head, SelectionGoal::None);
10837                }
10838            }
10839
10840            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10841            this.insert("", window, cx);
10842            linked_edits.apply_with_left_expansion(cx);
10843            this.refresh_edit_prediction(true, false, window, cx);
10844            refresh_linked_ranges(this, window, cx);
10845        });
10846    }
10847
10848    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10849        if self.read_only(cx) {
10850            return;
10851        }
10852        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10853        self.transact(window, cx, |this, window, cx| {
10854            this.change_selections(Default::default(), window, cx, |s| {
10855                s.move_with(&mut |map, selection| {
10856                    if selection.is_empty() {
10857                        let cursor = movement::right(map, selection.head());
10858                        selection.end = cursor;
10859                        selection.reversed = true;
10860                        selection.goal = SelectionGoal::None;
10861                    }
10862                })
10863            });
10864            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10865            this.insert("", window, cx);
10866            linked_edits.apply(cx);
10867            this.refresh_edit_prediction(true, false, window, cx);
10868            refresh_linked_ranges(this, window, cx);
10869        });
10870    }
10871
10872    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10873        if self.mode.is_single_line() {
10874            cx.propagate();
10875            return;
10876        }
10877
10878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10879        if self.move_to_prev_snippet_tabstop(window, cx) {
10880            return;
10881        }
10882        self.outdent(&Outdent, window, cx);
10883    }
10884
10885    pub fn next_snippet_tabstop(
10886        &mut self,
10887        _: &NextSnippetTabstop,
10888        window: &mut Window,
10889        cx: &mut Context<Self>,
10890    ) {
10891        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10892            cx.propagate();
10893            return;
10894        }
10895
10896        if self.move_to_next_snippet_tabstop(window, cx) {
10897            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10898            return;
10899        }
10900        cx.propagate();
10901    }
10902
10903    pub fn previous_snippet_tabstop(
10904        &mut self,
10905        _: &PreviousSnippetTabstop,
10906        window: &mut Window,
10907        cx: &mut Context<Self>,
10908    ) {
10909        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10910            cx.propagate();
10911            return;
10912        }
10913
10914        if self.move_to_prev_snippet_tabstop(window, cx) {
10915            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10916            return;
10917        }
10918        cx.propagate();
10919    }
10920
10921    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10922        if self.mode.is_single_line() {
10923            cx.propagate();
10924            return;
10925        }
10926
10927        if self.move_to_next_snippet_tabstop(window, cx) {
10928            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10929            return;
10930        }
10931        if self.read_only(cx) {
10932            return;
10933        }
10934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10935        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10936        let buffer = self.buffer.read(cx);
10937        let snapshot = buffer.snapshot(cx);
10938        let rows_iter = selections.iter().map(|s| s.head().row);
10939        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10940
10941        let has_some_cursor_in_whitespace = selections
10942            .iter()
10943            .filter(|selection| selection.is_empty())
10944            .any(|selection| {
10945                let cursor = selection.head();
10946                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10947                cursor.column < current_indent.len
10948            });
10949
10950        let mut edits = Vec::new();
10951        let mut prev_edited_row = 0;
10952        let mut row_delta = 0;
10953        for selection in &mut selections {
10954            if selection.start.row != prev_edited_row {
10955                row_delta = 0;
10956            }
10957            prev_edited_row = selection.end.row;
10958
10959            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10960            if selection.is_empty() {
10961                let cursor = selection.head();
10962                let settings = buffer.language_settings_at(cursor, cx);
10963                if settings.indent_list_on_tab {
10964                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10965                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10966                            row_delta = Self::indent_selection(
10967                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10968                            );
10969                            continue;
10970                        }
10971                    }
10972                }
10973            }
10974
10975            // If the selection is non-empty, then increase the indentation of the selected lines.
10976            if !selection.is_empty() {
10977                row_delta =
10978                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10979                continue;
10980            }
10981
10982            let cursor = selection.head();
10983            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10984            if let Some(suggested_indent) =
10985                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10986            {
10987                // Don't do anything if already at suggested indent
10988                // and there is any other cursor which is not
10989                if has_some_cursor_in_whitespace
10990                    && cursor.column == current_indent.len
10991                    && current_indent.len == suggested_indent.len
10992                {
10993                    continue;
10994                }
10995
10996                // Adjust line and move cursor to suggested indent
10997                // if cursor is not at suggested indent
10998                if cursor.column < suggested_indent.len
10999                    && cursor.column <= current_indent.len
11000                    && current_indent.len <= suggested_indent.len
11001                {
11002                    selection.start = Point::new(cursor.row, suggested_indent.len);
11003                    selection.end = selection.start;
11004                    if row_delta == 0 {
11005                        edits.extend(Buffer::edit_for_indent_size_adjustment(
11006                            cursor.row,
11007                            current_indent,
11008                            suggested_indent,
11009                        ));
11010                        row_delta = suggested_indent.len - current_indent.len;
11011                    }
11012                    continue;
11013                }
11014
11015                // If current indent is more than suggested indent
11016                // only move cursor to current indent and skip indent
11017                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11018                    selection.start = Point::new(cursor.row, current_indent.len);
11019                    selection.end = selection.start;
11020                    continue;
11021                }
11022            }
11023
11024            // Otherwise, insert a hard or soft tab.
11025            let settings = buffer.language_settings_at(cursor, cx);
11026            let tab_size = if settings.hard_tabs {
11027                IndentSize::tab()
11028            } else {
11029                let tab_size = settings.tab_size.get();
11030                let indent_remainder = snapshot
11031                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11032                    .flat_map(str::chars)
11033                    .fold(row_delta % tab_size, |counter: u32, c| {
11034                        if c == '\t' {
11035                            0
11036                        } else {
11037                            (counter + 1) % tab_size
11038                        }
11039                    });
11040
11041                let chars_to_next_tab_stop = tab_size - indent_remainder;
11042                IndentSize::spaces(chars_to_next_tab_stop)
11043            };
11044            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11045            selection.end = selection.start;
11046            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11047            row_delta += tab_size.len;
11048        }
11049
11050        self.transact(window, cx, |this, window, cx| {
11051            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11052            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11053            this.refresh_edit_prediction(true, false, window, cx);
11054        });
11055    }
11056
11057    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11058        if self.read_only(cx) {
11059            return;
11060        }
11061        if self.mode.is_single_line() {
11062            cx.propagate();
11063            return;
11064        }
11065
11066        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11067        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11068        let mut prev_edited_row = 0;
11069        let mut row_delta = 0;
11070        let mut edits = Vec::new();
11071        let buffer = self.buffer.read(cx);
11072        let snapshot = buffer.snapshot(cx);
11073        for selection in &mut selections {
11074            if selection.start.row != prev_edited_row {
11075                row_delta = 0;
11076            }
11077            prev_edited_row = selection.end.row;
11078
11079            row_delta =
11080                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11081        }
11082
11083        self.transact(window, cx, |this, window, cx| {
11084            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11085            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11086        });
11087    }
11088
11089    fn indent_selection(
11090        buffer: &MultiBuffer,
11091        snapshot: &MultiBufferSnapshot,
11092        selection: &mut Selection<Point>,
11093        edits: &mut Vec<(Range<Point>, String)>,
11094        delta_for_start_row: u32,
11095        cx: &App,
11096    ) -> u32 {
11097        let settings = buffer.language_settings_at(selection.start, cx);
11098        let tab_size = settings.tab_size.get();
11099        let indent_kind = if settings.hard_tabs {
11100            IndentKind::Tab
11101        } else {
11102            IndentKind::Space
11103        };
11104        let mut start_row = selection.start.row;
11105        let mut end_row = selection.end.row + 1;
11106
11107        // If a selection ends at the beginning of a line, don't indent
11108        // that last line.
11109        if selection.end.column == 0 && selection.end.row > selection.start.row {
11110            end_row -= 1;
11111        }
11112
11113        // Avoid re-indenting a row that has already been indented by a
11114        // previous selection, but still update this selection's column
11115        // to reflect that indentation.
11116        if delta_for_start_row > 0 {
11117            start_row += 1;
11118            selection.start.column += delta_for_start_row;
11119            if selection.end.row == selection.start.row {
11120                selection.end.column += delta_for_start_row;
11121            }
11122        }
11123
11124        let mut delta_for_end_row = 0;
11125        let has_multiple_rows = start_row + 1 != end_row;
11126        for row in start_row..end_row {
11127            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11128            let indent_delta = match (current_indent.kind, indent_kind) {
11129                (IndentKind::Space, IndentKind::Space) => {
11130                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11131                    IndentSize::spaces(columns_to_next_tab_stop)
11132                }
11133                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11134                (_, IndentKind::Tab) => IndentSize::tab(),
11135            };
11136
11137            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11138                0
11139            } else {
11140                selection.start.column
11141            };
11142            let row_start = Point::new(row, start);
11143            edits.push((
11144                row_start..row_start,
11145                indent_delta.chars().collect::<String>(),
11146            ));
11147
11148            // Update this selection's endpoints to reflect the indentation.
11149            if row == selection.start.row {
11150                selection.start.column += indent_delta.len;
11151            }
11152            if row == selection.end.row {
11153                selection.end.column += indent_delta.len;
11154                delta_for_end_row = indent_delta.len;
11155            }
11156        }
11157
11158        if selection.start.row == selection.end.row {
11159            delta_for_start_row + delta_for_end_row
11160        } else {
11161            delta_for_end_row
11162        }
11163    }
11164
11165    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11166        if self.read_only(cx) {
11167            return;
11168        }
11169        if self.mode.is_single_line() {
11170            cx.propagate();
11171            return;
11172        }
11173
11174        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11175        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11176        let selections = self.selections.all::<Point>(&display_map);
11177        let mut deletion_ranges = Vec::new();
11178        let mut last_outdent = None;
11179        {
11180            let buffer = self.buffer.read(cx);
11181            let snapshot = buffer.snapshot(cx);
11182            for selection in &selections {
11183                let settings = buffer.language_settings_at(selection.start, cx);
11184                let tab_size = settings.tab_size.get();
11185                let mut rows = selection.spanned_rows(false, &display_map);
11186
11187                // Avoid re-outdenting a row that has already been outdented by a
11188                // previous selection.
11189                if let Some(last_row) = last_outdent
11190                    && last_row == rows.start
11191                {
11192                    rows.start = rows.start.next_row();
11193                }
11194                let has_multiple_rows = rows.len() > 1;
11195                for row in rows.iter_rows() {
11196                    let indent_size = snapshot.indent_size_for_line(row);
11197                    if indent_size.len > 0 {
11198                        let deletion_len = match indent_size.kind {
11199                            IndentKind::Space => {
11200                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11201                                if columns_to_prev_tab_stop == 0 {
11202                                    tab_size
11203                                } else {
11204                                    columns_to_prev_tab_stop
11205                                }
11206                            }
11207                            IndentKind::Tab => 1,
11208                        };
11209                        let start = if has_multiple_rows
11210                            || deletion_len > selection.start.column
11211                            || indent_size.len < selection.start.column
11212                        {
11213                            0
11214                        } else {
11215                            selection.start.column - deletion_len
11216                        };
11217                        deletion_ranges.push(
11218                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11219                        );
11220                        last_outdent = Some(row);
11221                    }
11222                }
11223            }
11224        }
11225
11226        self.transact(window, cx, |this, window, cx| {
11227            this.buffer.update(cx, |buffer, cx| {
11228                let empty_str: Arc<str> = Arc::default();
11229                buffer.edit(
11230                    deletion_ranges
11231                        .into_iter()
11232                        .map(|range| (range, empty_str.clone())),
11233                    None,
11234                    cx,
11235                );
11236            });
11237            let selections = this
11238                .selections
11239                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11240            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11241        });
11242    }
11243
11244    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11245        if self.read_only(cx) {
11246            return;
11247        }
11248        if self.mode.is_single_line() {
11249            cx.propagate();
11250            return;
11251        }
11252
11253        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11254        let selections = self
11255            .selections
11256            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11257            .into_iter()
11258            .map(|s| s.range());
11259
11260        self.transact(window, cx, |this, window, cx| {
11261            this.buffer.update(cx, |buffer, cx| {
11262                buffer.autoindent_ranges(selections, cx);
11263            });
11264            let selections = this
11265                .selections
11266                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11267            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11268        });
11269    }
11270
11271    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11272        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11273        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11274        let selections = self.selections.all::<Point>(&display_map);
11275
11276        let mut new_cursors = Vec::new();
11277        let mut edit_ranges = Vec::new();
11278        let mut selections = selections.iter().peekable();
11279        while let Some(selection) = selections.next() {
11280            let mut rows = selection.spanned_rows(false, &display_map);
11281
11282            // Accumulate contiguous regions of rows that we want to delete.
11283            while let Some(next_selection) = selections.peek() {
11284                let next_rows = next_selection.spanned_rows(false, &display_map);
11285                if next_rows.start <= rows.end {
11286                    rows.end = next_rows.end;
11287                    selections.next().unwrap();
11288                } else {
11289                    break;
11290                }
11291            }
11292
11293            let buffer = display_map.buffer_snapshot();
11294            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11295            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11296                // If there's a line after the range, delete the \n from the end of the row range
11297                (
11298                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11299                    rows.end,
11300                )
11301            } else {
11302                // If there isn't a line after the range, delete the \n from the line before the
11303                // start of the row range
11304                edit_start = edit_start.saturating_sub_usize(1);
11305                (buffer.len(), rows.start.previous_row())
11306            };
11307
11308            let text_layout_details = self.text_layout_details(window, cx);
11309            let x = display_map.x_for_display_point(
11310                selection.head().to_display_point(&display_map),
11311                &text_layout_details,
11312            );
11313            let row = Point::new(target_row.0, 0)
11314                .to_display_point(&display_map)
11315                .row();
11316            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11317
11318            new_cursors.push((
11319                selection.id,
11320                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11321                SelectionGoal::None,
11322            ));
11323            edit_ranges.push(edit_start..edit_end);
11324        }
11325
11326        self.transact(window, cx, |this, window, cx| {
11327            let buffer = this.buffer.update(cx, |buffer, cx| {
11328                let empty_str: Arc<str> = Arc::default();
11329                buffer.edit(
11330                    edit_ranges
11331                        .into_iter()
11332                        .map(|range| (range, empty_str.clone())),
11333                    None,
11334                    cx,
11335                );
11336                buffer.snapshot(cx)
11337            });
11338            let new_selections = new_cursors
11339                .into_iter()
11340                .map(|(id, cursor, goal)| {
11341                    let cursor = cursor.to_point(&buffer);
11342                    Selection {
11343                        id,
11344                        start: cursor,
11345                        end: cursor,
11346                        reversed: false,
11347                        goal,
11348                    }
11349                })
11350                .collect();
11351
11352            this.change_selections(Default::default(), window, cx, |s| {
11353                s.select(new_selections);
11354            });
11355        });
11356    }
11357
11358    pub fn join_lines_impl(
11359        &mut self,
11360        insert_whitespace: bool,
11361        window: &mut Window,
11362        cx: &mut Context<Self>,
11363    ) {
11364        if self.read_only(cx) {
11365            return;
11366        }
11367        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11368        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11369            let start = MultiBufferRow(selection.start.row);
11370            // Treat single line selections as if they include the next line. Otherwise this action
11371            // would do nothing for single line selections individual cursors.
11372            let end = if selection.start.row == selection.end.row {
11373                MultiBufferRow(selection.start.row + 1)
11374            } else if selection.end.column == 0 {
11375                // If the selection ends at the start of a line, it's logically at the end of the
11376                // previous line (plus its newline).
11377                // Don't include the end line unless there's only one line selected.
11378                if selection.start.row + 1 == selection.end.row {
11379                    MultiBufferRow(selection.end.row)
11380                } else {
11381                    MultiBufferRow(selection.end.row - 1)
11382                }
11383            } else {
11384                MultiBufferRow(selection.end.row)
11385            };
11386
11387            if let Some(last_row_range) = row_ranges.last_mut()
11388                && start <= last_row_range.end
11389            {
11390                last_row_range.end = end;
11391                continue;
11392            }
11393            row_ranges.push(start..end);
11394        }
11395
11396        let snapshot = self.buffer.read(cx).snapshot(cx);
11397        let mut cursor_positions = Vec::new();
11398        for row_range in &row_ranges {
11399            let anchor = snapshot.anchor_before(Point::new(
11400                row_range.end.previous_row().0,
11401                snapshot.line_len(row_range.end.previous_row()),
11402            ));
11403            cursor_positions.push(anchor..anchor);
11404        }
11405
11406        self.transact(window, cx, |this, window, cx| {
11407            for row_range in row_ranges.into_iter().rev() {
11408                for row in row_range.iter_rows().rev() {
11409                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11410                    let next_line_row = row.next_row();
11411                    let indent = snapshot.indent_size_for_line(next_line_row);
11412                    let mut join_start_column = indent.len;
11413
11414                    if let Some(language_scope) =
11415                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11416                    {
11417                        let line_end =
11418                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11419                        let line_text_after_indent = snapshot
11420                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11421                            .collect::<String>();
11422
11423                        if !line_text_after_indent.is_empty() {
11424                            let block_prefix = language_scope
11425                                .block_comment()
11426                                .map(|c| c.prefix.as_ref())
11427                                .filter(|p| !p.is_empty());
11428                            let doc_prefix = language_scope
11429                                .documentation_comment()
11430                                .map(|c| c.prefix.as_ref())
11431                                .filter(|p| !p.is_empty());
11432                            let all_prefixes = language_scope
11433                                .line_comment_prefixes()
11434                                .iter()
11435                                .map(|p| p.as_ref())
11436                                .chain(block_prefix)
11437                                .chain(doc_prefix)
11438                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11439
11440                            let mut longest_prefix_len = None;
11441                            for prefix in all_prefixes {
11442                                let trimmed = prefix.trim_end();
11443                                if line_text_after_indent.starts_with(trimmed) {
11444                                    let candidate_len =
11445                                        if line_text_after_indent.starts_with(prefix) {
11446                                            prefix.len()
11447                                        } else {
11448                                            trimmed.len()
11449                                        };
11450                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11451                                        longest_prefix_len = Some(candidate_len);
11452                                    }
11453                                }
11454                            }
11455
11456                            if let Some(prefix_len) = longest_prefix_len {
11457                                join_start_column =
11458                                    join_start_column.saturating_add(prefix_len as u32);
11459                            }
11460                        }
11461                    }
11462
11463                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11464
11465                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11466                        && insert_whitespace
11467                    {
11468                        " "
11469                    } else {
11470                        ""
11471                    };
11472
11473                    this.buffer.update(cx, |buffer, cx| {
11474                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11475                    });
11476                }
11477            }
11478
11479            this.change_selections(Default::default(), window, cx, |s| {
11480                s.select_anchor_ranges(cursor_positions)
11481            });
11482        });
11483    }
11484
11485    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11487        self.join_lines_impl(true, window, cx);
11488    }
11489
11490    pub fn sort_lines_case_sensitive(
11491        &mut self,
11492        _: &SortLinesCaseSensitive,
11493        window: &mut Window,
11494        cx: &mut Context<Self>,
11495    ) {
11496        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11497    }
11498
11499    pub fn sort_lines_by_length(
11500        &mut self,
11501        _: &SortLinesByLength,
11502        window: &mut Window,
11503        cx: &mut Context<Self>,
11504    ) {
11505        self.manipulate_immutable_lines(window, cx, |lines| {
11506            lines.sort_by_key(|&line| line.chars().count())
11507        })
11508    }
11509
11510    pub fn sort_lines_case_insensitive(
11511        &mut self,
11512        _: &SortLinesCaseInsensitive,
11513        window: &mut Window,
11514        cx: &mut Context<Self>,
11515    ) {
11516        self.manipulate_immutable_lines(window, cx, |lines| {
11517            lines.sort_by_key(|line| line.to_lowercase())
11518        })
11519    }
11520
11521    pub fn unique_lines_case_insensitive(
11522        &mut self,
11523        _: &UniqueLinesCaseInsensitive,
11524        window: &mut Window,
11525        cx: &mut Context<Self>,
11526    ) {
11527        self.manipulate_immutable_lines(window, cx, |lines| {
11528            let mut seen = HashSet::default();
11529            lines.retain(|line| seen.insert(line.to_lowercase()));
11530        })
11531    }
11532
11533    pub fn unique_lines_case_sensitive(
11534        &mut self,
11535        _: &UniqueLinesCaseSensitive,
11536        window: &mut Window,
11537        cx: &mut Context<Self>,
11538    ) {
11539        self.manipulate_immutable_lines(window, cx, |lines| {
11540            let mut seen = HashSet::default();
11541            lines.retain(|line| seen.insert(*line));
11542        })
11543    }
11544
11545    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11546        let snapshot = self.buffer.read(cx).snapshot(cx);
11547        for selection in self.selections.disjoint_anchors_arc().iter() {
11548            if snapshot
11549                .language_at(selection.start)
11550                .and_then(|lang| lang.config().wrap_characters.as_ref())
11551                .is_some()
11552            {
11553                return true;
11554            }
11555        }
11556        false
11557    }
11558
11559    fn wrap_selections_in_tag(
11560        &mut self,
11561        _: &WrapSelectionsInTag,
11562        window: &mut Window,
11563        cx: &mut Context<Self>,
11564    ) {
11565        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11566
11567        let snapshot = self.buffer.read(cx).snapshot(cx);
11568
11569        let mut edits = Vec::new();
11570        let mut boundaries = Vec::new();
11571
11572        for selection in self
11573            .selections
11574            .all_adjusted(&self.display_snapshot(cx))
11575            .iter()
11576        {
11577            let Some(wrap_config) = snapshot
11578                .language_at(selection.start)
11579                .and_then(|lang| lang.config().wrap_characters.clone())
11580            else {
11581                continue;
11582            };
11583
11584            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11585            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11586
11587            let start_before = snapshot.anchor_before(selection.start);
11588            let end_after = snapshot.anchor_after(selection.end);
11589
11590            edits.push((start_before..start_before, open_tag));
11591            edits.push((end_after..end_after, close_tag));
11592
11593            boundaries.push((
11594                start_before,
11595                end_after,
11596                wrap_config.start_prefix.len(),
11597                wrap_config.end_suffix.len(),
11598            ));
11599        }
11600
11601        if edits.is_empty() {
11602            return;
11603        }
11604
11605        self.transact(window, cx, |this, window, cx| {
11606            let buffer = this.buffer.update(cx, |buffer, cx| {
11607                buffer.edit(edits, None, cx);
11608                buffer.snapshot(cx)
11609            });
11610
11611            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11612            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11613                boundaries.into_iter()
11614            {
11615                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11616                let close_offset = end_after
11617                    .to_offset(&buffer)
11618                    .saturating_sub_usize(end_suffix_len);
11619                new_selections.push(open_offset..open_offset);
11620                new_selections.push(close_offset..close_offset);
11621            }
11622
11623            this.change_selections(Default::default(), window, cx, |s| {
11624                s.select_ranges(new_selections);
11625            });
11626
11627            this.request_autoscroll(Autoscroll::fit(), cx);
11628        });
11629    }
11630
11631    pub fn toggle_read_only(
11632        &mut self,
11633        _: &workspace::ToggleReadOnlyFile,
11634        _: &mut Window,
11635        cx: &mut Context<Self>,
11636    ) {
11637        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11638            buffer.update(cx, |buffer, cx| {
11639                buffer.set_capability(
11640                    match buffer.capability() {
11641                        Capability::ReadWrite => Capability::Read,
11642                        Capability::Read => Capability::ReadWrite,
11643                        Capability::ReadOnly => Capability::ReadOnly,
11644                    },
11645                    cx,
11646                );
11647            })
11648        }
11649    }
11650
11651    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11652        let Some(project) = self.project.clone() else {
11653            return;
11654        };
11655        let task = self.reload(project, window, cx);
11656        self.detach_and_notify_err(task, window, cx);
11657    }
11658
11659    pub fn restore_file(
11660        &mut self,
11661        _: &::git::RestoreFile,
11662        window: &mut Window,
11663        cx: &mut Context<Self>,
11664    ) {
11665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11666        let mut buffer_ids = HashSet::default();
11667        let snapshot = self.buffer().read(cx).snapshot(cx);
11668        for selection in self
11669            .selections
11670            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11671        {
11672            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11673        }
11674
11675        let buffer = self.buffer().read(cx);
11676        let ranges = buffer_ids
11677            .into_iter()
11678            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11679            .collect::<Vec<_>>();
11680
11681        self.restore_hunks_in_ranges(ranges, window, cx);
11682    }
11683
11684    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11685        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11686        let selections = self
11687            .selections
11688            .all(&self.display_snapshot(cx))
11689            .into_iter()
11690            .map(|s| s.range())
11691            .collect();
11692        self.restore_hunks_in_ranges(selections, window, cx);
11693    }
11694
11695    /// Restores the diff hunks in the editor's selections and moves the cursor
11696    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11697    /// not all diff hunks are expanded.
11698    pub fn restore_and_next(
11699        &mut self,
11700        _: &::git::RestoreAndNext,
11701        window: &mut Window,
11702        cx: &mut Context<Self>,
11703    ) {
11704        let selections = self
11705            .selections
11706            .all(&self.display_snapshot(cx))
11707            .into_iter()
11708            .map(|selection| selection.range())
11709            .collect();
11710
11711        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11712        self.restore_hunks_in_ranges(selections, window, cx);
11713
11714        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11715        let wrap_around = !all_diff_hunks_expanded;
11716        let snapshot = self.snapshot(window, cx);
11717        let position = self
11718            .selections
11719            .newest::<Point>(&snapshot.display_snapshot)
11720            .head();
11721
11722        self.go_to_hunk_before_or_after_position(
11723            &snapshot,
11724            position,
11725            Direction::Next,
11726            wrap_around,
11727            window,
11728            cx,
11729        );
11730    }
11731
11732    pub fn restore_hunks_in_ranges(
11733        &mut self,
11734        ranges: Vec<Range<Point>>,
11735        window: &mut Window,
11736        cx: &mut Context<Editor>,
11737    ) {
11738        if self.delegate_stage_and_restore {
11739            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11740            if !hunks.is_empty() {
11741                cx.emit(EditorEvent::RestoreRequested { hunks });
11742            }
11743            return;
11744        }
11745        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11746        self.transact(window, cx, |editor, window, cx| {
11747            editor.restore_diff_hunks(hunks, cx);
11748            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
11749                selections.refresh()
11750            });
11751        });
11752    }
11753
11754    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11755        let mut revert_changes = HashMap::default();
11756        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11757        for (buffer_id, hunks) in &chunk_by {
11758            let hunks = hunks.collect::<Vec<_>>();
11759            for hunk in &hunks {
11760                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11761            }
11762            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11763        }
11764        if !revert_changes.is_empty() {
11765            self.buffer().update(cx, |multi_buffer, cx| {
11766                for (buffer_id, changes) in revert_changes {
11767                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11768                        buffer.update(cx, |buffer, cx| {
11769                            buffer.edit(
11770                                changes
11771                                    .into_iter()
11772                                    .map(|(range, text)| (range, text.to_string())),
11773                                None,
11774                                cx,
11775                            );
11776                        });
11777                    }
11778                }
11779            });
11780        }
11781    }
11782
11783    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11784        if let Some(status) = self
11785            .addons
11786            .iter()
11787            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11788        {
11789            return Some(status);
11790        }
11791        self.project
11792            .as_ref()?
11793            .read(cx)
11794            .status_for_buffer_id(buffer_id, cx)
11795    }
11796
11797    pub fn open_active_item_in_terminal(
11798        &mut self,
11799        _: &OpenInTerminal,
11800        window: &mut Window,
11801        cx: &mut Context<Self>,
11802    ) {
11803        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11804            let project_path = buffer.read(cx).project_path(cx)?;
11805            let project = self.project()?.read(cx);
11806            let entry = project.entry_for_path(&project_path, cx)?;
11807            let parent = match &entry.canonical_path {
11808                Some(canonical_path) => canonical_path.to_path_buf(),
11809                None => project.absolute_path(&project_path, cx)?,
11810            }
11811            .parent()?
11812            .to_path_buf();
11813            Some(parent)
11814        }) {
11815            window.dispatch_action(
11816                OpenTerminal {
11817                    working_directory,
11818                    local: false,
11819                }
11820                .boxed_clone(),
11821                cx,
11822            );
11823        }
11824    }
11825
11826    fn set_breakpoint_context_menu(
11827        &mut self,
11828        display_row: DisplayRow,
11829        position: Option<Anchor>,
11830        clicked_point: gpui::Point<Pixels>,
11831        window: &mut Window,
11832        cx: &mut Context<Self>,
11833    ) {
11834        let source = self
11835            .buffer
11836            .read(cx)
11837            .snapshot(cx)
11838            .anchor_before(Point::new(display_row.0, 0u32));
11839
11840        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11841
11842        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11843            self,
11844            source,
11845            clicked_point,
11846            context_menu,
11847            window,
11848            cx,
11849        );
11850    }
11851
11852    fn add_edit_breakpoint_block(
11853        &mut self,
11854        anchor: Anchor,
11855        breakpoint: &Breakpoint,
11856        edit_action: BreakpointPromptEditAction,
11857        window: &mut Window,
11858        cx: &mut Context<Self>,
11859    ) {
11860        let weak_editor = cx.weak_entity();
11861        let bp_prompt = cx.new(|cx| {
11862            BreakpointPromptEditor::new(
11863                weak_editor,
11864                anchor,
11865                breakpoint.clone(),
11866                edit_action,
11867                window,
11868                cx,
11869            )
11870        });
11871
11872        let height = bp_prompt.update(cx, |this, cx| {
11873            this.prompt
11874                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11875        });
11876        let cloned_prompt = bp_prompt.clone();
11877        let blocks = vec![BlockProperties {
11878            style: BlockStyle::Sticky,
11879            placement: BlockPlacement::Above(anchor),
11880            height: Some(height),
11881            render: Arc::new(move |cx| {
11882                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11883                cloned_prompt.clone().into_any_element()
11884            }),
11885            priority: 0,
11886        }];
11887
11888        let focus_handle = bp_prompt.focus_handle(cx);
11889        window.focus(&focus_handle, cx);
11890
11891        let block_ids = self.insert_blocks(blocks, None, cx);
11892        bp_prompt.update(cx, |prompt, _| {
11893            prompt.add_block_ids(block_ids);
11894        });
11895    }
11896
11897    pub(crate) fn breakpoint_at_row(
11898        &self,
11899        row: u32,
11900        window: &mut Window,
11901        cx: &mut Context<Self>,
11902    ) -> Option<(Anchor, Breakpoint)> {
11903        let snapshot = self.snapshot(window, cx);
11904        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11905
11906        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11907    }
11908
11909    pub(crate) fn breakpoint_at_anchor(
11910        &self,
11911        breakpoint_position: Anchor,
11912        snapshot: &EditorSnapshot,
11913        cx: &mut Context<Self>,
11914    ) -> Option<(Anchor, Breakpoint)> {
11915        let buffer = self
11916            .buffer
11917            .read(cx)
11918            .buffer_for_anchor(breakpoint_position, cx)?;
11919
11920        let enclosing_excerpt = breakpoint_position.excerpt_id;
11921        let buffer_snapshot = buffer.read(cx).snapshot();
11922
11923        let row = buffer_snapshot
11924            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11925            .row;
11926
11927        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11928        let anchor_end = snapshot
11929            .buffer_snapshot()
11930            .anchor_after(Point::new(row, line_len));
11931
11932        self.breakpoint_store
11933            .as_ref()?
11934            .read_with(cx, |breakpoint_store, cx| {
11935                breakpoint_store
11936                    .breakpoints(
11937                        &buffer,
11938                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11939                        &buffer_snapshot,
11940                        cx,
11941                    )
11942                    .next()
11943                    .and_then(|(bp, _)| {
11944                        let breakpoint_row = buffer_snapshot
11945                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11946                            .row;
11947
11948                        if breakpoint_row == row {
11949                            snapshot
11950                                .buffer_snapshot()
11951                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11952                                .map(|position| (position, bp.bp.clone()))
11953                        } else {
11954                            None
11955                        }
11956                    })
11957            })
11958    }
11959
11960    pub fn edit_log_breakpoint(
11961        &mut self,
11962        _: &EditLogBreakpoint,
11963        window: &mut Window,
11964        cx: &mut Context<Self>,
11965    ) {
11966        if self.breakpoint_store.is_none() {
11967            return;
11968        }
11969
11970        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11971            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11972                message: None,
11973                state: BreakpointState::Enabled,
11974                condition: None,
11975                hit_condition: None,
11976            });
11977
11978            self.add_edit_breakpoint_block(
11979                anchor,
11980                &breakpoint,
11981                BreakpointPromptEditAction::Log,
11982                window,
11983                cx,
11984            );
11985        }
11986    }
11987
11988    fn breakpoints_at_cursors(
11989        &self,
11990        window: &mut Window,
11991        cx: &mut Context<Self>,
11992    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11993        let snapshot = self.snapshot(window, cx);
11994        let cursors = self
11995            .selections
11996            .disjoint_anchors_arc()
11997            .iter()
11998            .map(|selection| {
11999                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12000
12001                let breakpoint_position = self
12002                    .breakpoint_at_row(cursor_position.row, window, cx)
12003                    .map(|bp| bp.0)
12004                    .unwrap_or_else(|| {
12005                        snapshot
12006                            .display_snapshot
12007                            .buffer_snapshot()
12008                            .anchor_after(Point::new(cursor_position.row, 0))
12009                    });
12010
12011                let breakpoint = self
12012                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12013                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12014
12015                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12016            })
12017            // 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.
12018            .collect::<HashMap<Anchor, _>>();
12019
12020        cursors.into_iter().collect()
12021    }
12022
12023    pub fn enable_breakpoint(
12024        &mut self,
12025        _: &crate::actions::EnableBreakpoint,
12026        window: &mut Window,
12027        cx: &mut Context<Self>,
12028    ) {
12029        if self.breakpoint_store.is_none() {
12030            return;
12031        }
12032
12033        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12034            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12035                continue;
12036            };
12037            self.edit_breakpoint_at_anchor(
12038                anchor,
12039                breakpoint,
12040                BreakpointEditAction::InvertState,
12041                cx,
12042            );
12043        }
12044    }
12045
12046    pub fn align_selections(
12047        &mut self,
12048        _: &crate::actions::AlignSelections,
12049        window: &mut Window,
12050        cx: &mut Context<Self>,
12051    ) {
12052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12053
12054        let display_snapshot = self.display_snapshot(cx);
12055
12056        struct CursorData {
12057            anchor: Anchor,
12058            point: Point,
12059        }
12060        let cursor_data: Vec<CursorData> = self
12061            .selections
12062            .disjoint_anchors()
12063            .iter()
12064            .map(|selection| {
12065                let anchor = if selection.reversed {
12066                    selection.head()
12067                } else {
12068                    selection.tail()
12069                };
12070                CursorData {
12071                    anchor: anchor,
12072                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12073                }
12074            })
12075            .collect();
12076
12077        let rows_anchors_count: Vec<usize> = cursor_data
12078            .iter()
12079            .map(|cursor| cursor.point.row)
12080            .chunk_by(|&row| row)
12081            .into_iter()
12082            .map(|(_, group)| group.count())
12083            .collect();
12084        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12085        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12086        let mut edits = Vec::new();
12087
12088        for column_idx in 0..max_columns {
12089            let mut cursor_index = 0;
12090
12091            // Calculate target_column => position that the selections will go
12092            let mut target_column = 0;
12093            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12094                // Skip rows that don't have this column
12095                if column_idx >= *cursor_count {
12096                    cursor_index += cursor_count;
12097                    continue;
12098                }
12099
12100                let point = &cursor_data[cursor_index + column_idx].point;
12101                let adjusted_column = point.column + rows_column_offset[row_idx];
12102                if adjusted_column > target_column {
12103                    target_column = adjusted_column;
12104                }
12105                cursor_index += cursor_count;
12106            }
12107
12108            // Collect edits for this column
12109            cursor_index = 0;
12110            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12111                // Skip rows that don't have this column
12112                if column_idx >= *cursor_count {
12113                    cursor_index += *cursor_count;
12114                    continue;
12115                }
12116
12117                let point = &cursor_data[cursor_index + column_idx].point;
12118                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12119                if spaces_needed > 0 {
12120                    let anchor = cursor_data[cursor_index + column_idx]
12121                        .anchor
12122                        .bias_left(&display_snapshot);
12123                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12124                }
12125                rows_column_offset[row_idx] += spaces_needed;
12126
12127                cursor_index += *cursor_count;
12128            }
12129        }
12130
12131        if !edits.is_empty() {
12132            self.transact(window, cx, |editor, _window, cx| {
12133                editor.edit(edits, cx);
12134            });
12135        }
12136    }
12137
12138    pub fn disable_breakpoint(
12139        &mut self,
12140        _: &crate::actions::DisableBreakpoint,
12141        window: &mut Window,
12142        cx: &mut Context<Self>,
12143    ) {
12144        if self.breakpoint_store.is_none() {
12145            return;
12146        }
12147
12148        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12149            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12150                continue;
12151            };
12152            self.edit_breakpoint_at_anchor(
12153                anchor,
12154                breakpoint,
12155                BreakpointEditAction::InvertState,
12156                cx,
12157            );
12158        }
12159    }
12160
12161    pub fn toggle_breakpoint(
12162        &mut self,
12163        _: &crate::actions::ToggleBreakpoint,
12164        window: &mut Window,
12165        cx: &mut Context<Self>,
12166    ) {
12167        if self.breakpoint_store.is_none() {
12168            return;
12169        }
12170
12171        let snapshot = self.snapshot(window, cx);
12172        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12173            if self.gutter_breakpoint_indicator.0.is_some() {
12174                let display_row = anchor
12175                    .to_point(snapshot.buffer_snapshot())
12176                    .to_display_point(&snapshot.display_snapshot)
12177                    .row();
12178                self.update_breakpoint_collision_on_toggle(
12179                    display_row,
12180                    &BreakpointEditAction::Toggle,
12181                );
12182            }
12183
12184            if let Some(breakpoint) = breakpoint {
12185                self.edit_breakpoint_at_anchor(
12186                    anchor,
12187                    breakpoint,
12188                    BreakpointEditAction::Toggle,
12189                    cx,
12190                );
12191            } else {
12192                self.edit_breakpoint_at_anchor(
12193                    anchor,
12194                    Breakpoint::new_standard(),
12195                    BreakpointEditAction::Toggle,
12196                    cx,
12197                );
12198            }
12199        }
12200    }
12201
12202    fn update_breakpoint_collision_on_toggle(
12203        &mut self,
12204        display_row: DisplayRow,
12205        edit_action: &BreakpointEditAction,
12206    ) {
12207        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12208            if breakpoint_indicator.display_row == display_row
12209                && matches!(edit_action, BreakpointEditAction::Toggle)
12210            {
12211                breakpoint_indicator.collides_with_existing_breakpoint =
12212                    !breakpoint_indicator.collides_with_existing_breakpoint;
12213            }
12214        }
12215    }
12216
12217    pub fn edit_breakpoint_at_anchor(
12218        &mut self,
12219        breakpoint_position: Anchor,
12220        breakpoint: Breakpoint,
12221        edit_action: BreakpointEditAction,
12222        cx: &mut Context<Self>,
12223    ) {
12224        let Some(breakpoint_store) = &self.breakpoint_store else {
12225            return;
12226        };
12227
12228        let Some(buffer) = self
12229            .buffer
12230            .read(cx)
12231            .buffer_for_anchor(breakpoint_position, cx)
12232        else {
12233            return;
12234        };
12235
12236        breakpoint_store.update(cx, |breakpoint_store, cx| {
12237            breakpoint_store.toggle_breakpoint(
12238                buffer,
12239                BreakpointWithPosition {
12240                    position: breakpoint_position.text_anchor,
12241                    bp: breakpoint,
12242                },
12243                edit_action,
12244                cx,
12245            );
12246        });
12247
12248        cx.notify();
12249    }
12250
12251    #[cfg(any(test, feature = "test-support"))]
12252    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12253        self.breakpoint_store.clone()
12254    }
12255
12256    pub fn prepare_restore_change(
12257        &self,
12258        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12259        hunk: &MultiBufferDiffHunk,
12260        cx: &mut App,
12261    ) -> Option<()> {
12262        if hunk.is_created_file() {
12263            return None;
12264        }
12265        let buffer = self.buffer.read(cx);
12266        let diff = buffer.diff_for(hunk.buffer_id)?;
12267        let buffer = buffer.buffer(hunk.buffer_id)?;
12268        let buffer = buffer.read(cx);
12269        let original_text = diff
12270            .read(cx)
12271            .base_text(cx)
12272            .as_rope()
12273            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12274        let buffer_snapshot = buffer.snapshot();
12275        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12276        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12277            probe
12278                .0
12279                .start
12280                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12281                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12282        }) {
12283            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12284            Some(())
12285        } else {
12286            None
12287        }
12288    }
12289
12290    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12291        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12292    }
12293
12294    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12295        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12296    }
12297
12298    pub fn rotate_selections_forward(
12299        &mut self,
12300        _: &RotateSelectionsForward,
12301        window: &mut Window,
12302        cx: &mut Context<Self>,
12303    ) {
12304        self.rotate_selections(window, cx, false)
12305    }
12306
12307    pub fn rotate_selections_backward(
12308        &mut self,
12309        _: &RotateSelectionsBackward,
12310        window: &mut Window,
12311        cx: &mut Context<Self>,
12312    ) {
12313        self.rotate_selections(window, cx, true)
12314    }
12315
12316    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12318        let display_snapshot = self.display_snapshot(cx);
12319        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12320
12321        if selections.len() < 2 {
12322            return;
12323        }
12324
12325        let (edits, new_selections) = {
12326            let buffer = self.buffer.read(cx).read(cx);
12327            let has_selections = selections.iter().any(|s| !s.is_empty());
12328            if has_selections {
12329                let mut selected_texts: Vec<String> = selections
12330                    .iter()
12331                    .map(|selection| {
12332                        buffer
12333                            .text_for_range(selection.start..selection.end)
12334                            .collect()
12335                    })
12336                    .collect();
12337
12338                if reverse {
12339                    selected_texts.rotate_left(1);
12340                } else {
12341                    selected_texts.rotate_right(1);
12342                }
12343
12344                let mut offset_delta: i64 = 0;
12345                let mut new_selections = Vec::new();
12346                let edits: Vec<_> = selections
12347                    .iter()
12348                    .zip(selected_texts.iter())
12349                    .map(|(selection, new_text)| {
12350                        let old_len = (selection.end.0 - selection.start.0) as i64;
12351                        let new_len = new_text.len() as i64;
12352                        let adjusted_start =
12353                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12354                        let adjusted_end =
12355                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12356
12357                        new_selections.push(Selection {
12358                            id: selection.id,
12359                            start: adjusted_start,
12360                            end: adjusted_end,
12361                            reversed: selection.reversed,
12362                            goal: selection.goal,
12363                        });
12364
12365                        offset_delta += new_len - old_len;
12366                        (selection.start..selection.end, new_text.clone())
12367                    })
12368                    .collect();
12369                (edits, new_selections)
12370            } else {
12371                let mut all_rows: Vec<u32> = selections
12372                    .iter()
12373                    .map(|selection| buffer.offset_to_point(selection.start).row)
12374                    .collect();
12375                all_rows.sort_unstable();
12376                all_rows.dedup();
12377
12378                if all_rows.len() < 2 {
12379                    return;
12380                }
12381
12382                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12383                    .iter()
12384                    .map(|&row| {
12385                        let start = Point::new(row, 0);
12386                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12387                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12388                    })
12389                    .collect();
12390
12391                let mut line_texts: Vec<String> = line_ranges
12392                    .iter()
12393                    .map(|range| buffer.text_for_range(range.clone()).collect())
12394                    .collect();
12395
12396                if reverse {
12397                    line_texts.rotate_left(1);
12398                } else {
12399                    line_texts.rotate_right(1);
12400                }
12401
12402                let edits = line_ranges
12403                    .iter()
12404                    .zip(line_texts.iter())
12405                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12406                    .collect();
12407
12408                let num_rows = all_rows.len();
12409                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12410                    .iter()
12411                    .enumerate()
12412                    .map(|(i, &row)| (row, i))
12413                    .collect();
12414
12415                // Compute new line start offsets after rotation (handles CRLF)
12416                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12417                let first_line_start = line_ranges[0].start.0;
12418                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12419                for text in line_texts.iter().take(num_rows - 1) {
12420                    let prev_start = *new_line_starts.last().unwrap();
12421                    new_line_starts.push(prev_start + text.len() + newline_len);
12422                }
12423
12424                let new_selections = selections
12425                    .iter()
12426                    .map(|selection| {
12427                        let point = buffer.offset_to_point(selection.start);
12428                        let old_index = row_to_index[&point.row];
12429                        let new_index = if reverse {
12430                            (old_index + num_rows - 1) % num_rows
12431                        } else {
12432                            (old_index + 1) % num_rows
12433                        };
12434                        let new_offset =
12435                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12436                        Selection {
12437                            id: selection.id,
12438                            start: new_offset,
12439                            end: new_offset,
12440                            reversed: selection.reversed,
12441                            goal: selection.goal,
12442                        }
12443                    })
12444                    .collect();
12445
12446                (edits, new_selections)
12447            }
12448        };
12449
12450        self.transact(window, cx, |this, window, cx| {
12451            this.buffer.update(cx, |buffer, cx| {
12452                buffer.edit(edits, None, cx);
12453            });
12454            this.change_selections(Default::default(), window, cx, |s| {
12455                s.select(new_selections);
12456            });
12457        });
12458    }
12459
12460    fn manipulate_lines<M>(
12461        &mut self,
12462        window: &mut Window,
12463        cx: &mut Context<Self>,
12464        mut manipulate: M,
12465    ) where
12466        M: FnMut(&str) -> LineManipulationResult,
12467    {
12468        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12469
12470        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12471        let buffer = self.buffer.read(cx).snapshot(cx);
12472
12473        let mut edits = Vec::new();
12474
12475        let selections = self.selections.all::<Point>(&display_map);
12476        let mut selections = selections.iter().peekable();
12477        let mut contiguous_row_selections = Vec::new();
12478        let mut new_selections = Vec::new();
12479        let mut added_lines = 0;
12480        let mut removed_lines = 0;
12481
12482        while let Some(selection) = selections.next() {
12483            let (start_row, end_row) = consume_contiguous_rows(
12484                &mut contiguous_row_selections,
12485                selection,
12486                &display_map,
12487                &mut selections,
12488            );
12489
12490            let start_point = Point::new(start_row.0, 0);
12491            let end_point = Point::new(
12492                end_row.previous_row().0,
12493                buffer.line_len(end_row.previous_row()),
12494            );
12495            let text = buffer
12496                .text_for_range(start_point..end_point)
12497                .collect::<String>();
12498
12499            let LineManipulationResult {
12500                new_text,
12501                line_count_before,
12502                line_count_after,
12503            } = manipulate(&text);
12504
12505            edits.push((start_point..end_point, new_text));
12506
12507            // Selections must change based on added and removed line count
12508            let start_row =
12509                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12510            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12511            new_selections.push(Selection {
12512                id: selection.id,
12513                start: start_row,
12514                end: end_row,
12515                goal: SelectionGoal::None,
12516                reversed: selection.reversed,
12517            });
12518
12519            if line_count_after > line_count_before {
12520                added_lines += line_count_after - line_count_before;
12521            } else if line_count_before > line_count_after {
12522                removed_lines += line_count_before - line_count_after;
12523            }
12524        }
12525
12526        self.transact(window, cx, |this, window, cx| {
12527            let buffer = this.buffer.update(cx, |buffer, cx| {
12528                buffer.edit(edits, None, cx);
12529                buffer.snapshot(cx)
12530            });
12531
12532            // Recalculate offsets on newly edited buffer
12533            let new_selections = new_selections
12534                .iter()
12535                .map(|s| {
12536                    let start_point = Point::new(s.start.0, 0);
12537                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12538                    Selection {
12539                        id: s.id,
12540                        start: buffer.point_to_offset(start_point),
12541                        end: buffer.point_to_offset(end_point),
12542                        goal: s.goal,
12543                        reversed: s.reversed,
12544                    }
12545                })
12546                .collect();
12547
12548            this.change_selections(Default::default(), window, cx, |s| {
12549                s.select(new_selections);
12550            });
12551
12552            this.request_autoscroll(Autoscroll::fit(), cx);
12553        });
12554    }
12555
12556    fn manipulate_immutable_lines<Fn>(
12557        &mut self,
12558        window: &mut Window,
12559        cx: &mut Context<Self>,
12560        mut callback: Fn,
12561    ) where
12562        Fn: FnMut(&mut Vec<&str>),
12563    {
12564        self.manipulate_lines(window, cx, |text| {
12565            let mut lines: Vec<&str> = text.split('\n').collect();
12566            let line_count_before = lines.len();
12567
12568            callback(&mut lines);
12569
12570            LineManipulationResult {
12571                new_text: lines.join("\n"),
12572                line_count_before,
12573                line_count_after: lines.len(),
12574            }
12575        });
12576    }
12577
12578    fn manipulate_mutable_lines<Fn>(
12579        &mut self,
12580        window: &mut Window,
12581        cx: &mut Context<Self>,
12582        mut callback: Fn,
12583    ) where
12584        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12585    {
12586        self.manipulate_lines(window, cx, |text| {
12587            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12588            let line_count_before = lines.len();
12589
12590            callback(&mut lines);
12591
12592            LineManipulationResult {
12593                new_text: lines.join("\n"),
12594                line_count_before,
12595                line_count_after: lines.len(),
12596            }
12597        });
12598    }
12599
12600    pub fn convert_indentation_to_spaces(
12601        &mut self,
12602        _: &ConvertIndentationToSpaces,
12603        window: &mut Window,
12604        cx: &mut Context<Self>,
12605    ) {
12606        let settings = self.buffer.read(cx).language_settings(cx);
12607        let tab_size = settings.tab_size.get() as usize;
12608
12609        self.manipulate_mutable_lines(window, cx, |lines| {
12610            // Allocates a reasonably sized scratch buffer once for the whole loop
12611            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12612            // Avoids recomputing spaces that could be inserted many times
12613            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12614                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12615                .collect();
12616
12617            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12618                let mut chars = line.as_ref().chars();
12619                let mut col = 0;
12620                let mut changed = false;
12621
12622                for ch in chars.by_ref() {
12623                    match ch {
12624                        ' ' => {
12625                            reindented_line.push(' ');
12626                            col += 1;
12627                        }
12628                        '\t' => {
12629                            // \t are converted to spaces depending on the current column
12630                            let spaces_len = tab_size - (col % tab_size);
12631                            reindented_line.extend(&space_cache[spaces_len - 1]);
12632                            col += spaces_len;
12633                            changed = true;
12634                        }
12635                        _ => {
12636                            // If we dont append before break, the character is consumed
12637                            reindented_line.push(ch);
12638                            break;
12639                        }
12640                    }
12641                }
12642
12643                if !changed {
12644                    reindented_line.clear();
12645                    continue;
12646                }
12647                // Append the rest of the line and replace old reference with new one
12648                reindented_line.extend(chars);
12649                *line = Cow::Owned(reindented_line.clone());
12650                reindented_line.clear();
12651            }
12652        });
12653    }
12654
12655    pub fn convert_indentation_to_tabs(
12656        &mut self,
12657        _: &ConvertIndentationToTabs,
12658        window: &mut Window,
12659        cx: &mut Context<Self>,
12660    ) {
12661        let settings = self.buffer.read(cx).language_settings(cx);
12662        let tab_size = settings.tab_size.get() as usize;
12663
12664        self.manipulate_mutable_lines(window, cx, |lines| {
12665            // Allocates a reasonably sized buffer once for the whole loop
12666            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12667            // Avoids recomputing spaces that could be inserted many times
12668            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12669                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12670                .collect();
12671
12672            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12673                let mut chars = line.chars();
12674                let mut spaces_count = 0;
12675                let mut first_non_indent_char = None;
12676                let mut changed = false;
12677
12678                for ch in chars.by_ref() {
12679                    match ch {
12680                        ' ' => {
12681                            // Keep track of spaces. Append \t when we reach tab_size
12682                            spaces_count += 1;
12683                            changed = true;
12684                            if spaces_count == tab_size {
12685                                reindented_line.push('\t');
12686                                spaces_count = 0;
12687                            }
12688                        }
12689                        '\t' => {
12690                            reindented_line.push('\t');
12691                            spaces_count = 0;
12692                        }
12693                        _ => {
12694                            // Dont append it yet, we might have remaining spaces
12695                            first_non_indent_char = Some(ch);
12696                            break;
12697                        }
12698                    }
12699                }
12700
12701                if !changed {
12702                    reindented_line.clear();
12703                    continue;
12704                }
12705                // Remaining spaces that didn't make a full tab stop
12706                if spaces_count > 0 {
12707                    reindented_line.extend(&space_cache[spaces_count - 1]);
12708                }
12709                // If we consume an extra character that was not indentation, add it back
12710                if let Some(extra_char) = first_non_indent_char {
12711                    reindented_line.push(extra_char);
12712                }
12713                // Append the rest of the line and replace old reference with new one
12714                reindented_line.extend(chars);
12715                *line = Cow::Owned(reindented_line.clone());
12716                reindented_line.clear();
12717            }
12718        });
12719    }
12720
12721    pub fn convert_to_upper_case(
12722        &mut self,
12723        _: &ConvertToUpperCase,
12724        window: &mut Window,
12725        cx: &mut Context<Self>,
12726    ) {
12727        self.manipulate_text(window, cx, |text| text.to_uppercase())
12728    }
12729
12730    pub fn convert_to_lower_case(
12731        &mut self,
12732        _: &ConvertToLowerCase,
12733        window: &mut Window,
12734        cx: &mut Context<Self>,
12735    ) {
12736        self.manipulate_text(window, cx, |text| text.to_lowercase())
12737    }
12738
12739    pub fn convert_to_title_case(
12740        &mut self,
12741        _: &ConvertToTitleCase,
12742        window: &mut Window,
12743        cx: &mut Context<Self>,
12744    ) {
12745        self.manipulate_text(window, cx, |text| {
12746            Self::convert_text_case(text, Case::Title)
12747        })
12748    }
12749
12750    pub fn convert_to_snake_case(
12751        &mut self,
12752        _: &ConvertToSnakeCase,
12753        window: &mut Window,
12754        cx: &mut Context<Self>,
12755    ) {
12756        self.manipulate_text(window, cx, |text| {
12757            Self::convert_text_case(text, Case::Snake)
12758        })
12759    }
12760
12761    pub fn convert_to_kebab_case(
12762        &mut self,
12763        _: &ConvertToKebabCase,
12764        window: &mut Window,
12765        cx: &mut Context<Self>,
12766    ) {
12767        self.manipulate_text(window, cx, |text| {
12768            Self::convert_text_case(text, Case::Kebab)
12769        })
12770    }
12771
12772    pub fn convert_to_upper_camel_case(
12773        &mut self,
12774        _: &ConvertToUpperCamelCase,
12775        window: &mut Window,
12776        cx: &mut Context<Self>,
12777    ) {
12778        self.manipulate_text(window, cx, |text| {
12779            Self::convert_text_case(text, Case::UpperCamel)
12780        })
12781    }
12782
12783    pub fn convert_to_lower_camel_case(
12784        &mut self,
12785        _: &ConvertToLowerCamelCase,
12786        window: &mut Window,
12787        cx: &mut Context<Self>,
12788    ) {
12789        self.manipulate_text(window, cx, |text| {
12790            Self::convert_text_case(text, Case::Camel)
12791        })
12792    }
12793
12794    pub fn convert_to_opposite_case(
12795        &mut self,
12796        _: &ConvertToOppositeCase,
12797        window: &mut Window,
12798        cx: &mut Context<Self>,
12799    ) {
12800        self.manipulate_text(window, cx, |text| {
12801            text.chars()
12802                .fold(String::with_capacity(text.len()), |mut t, c| {
12803                    if c.is_uppercase() {
12804                        t.extend(c.to_lowercase());
12805                    } else {
12806                        t.extend(c.to_uppercase());
12807                    }
12808                    t
12809                })
12810        })
12811    }
12812
12813    pub fn convert_to_sentence_case(
12814        &mut self,
12815        _: &ConvertToSentenceCase,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) {
12819        self.manipulate_text(window, cx, |text| {
12820            Self::convert_text_case(text, Case::Sentence)
12821        })
12822    }
12823
12824    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12825        self.manipulate_text(window, cx, |text| {
12826            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12827            if has_upper_case_characters {
12828                text.to_lowercase()
12829            } else {
12830                text.to_uppercase()
12831            }
12832        })
12833    }
12834
12835    pub fn convert_to_rot13(
12836        &mut self,
12837        _: &ConvertToRot13,
12838        window: &mut Window,
12839        cx: &mut Context<Self>,
12840    ) {
12841        self.manipulate_text(window, cx, |text| {
12842            text.chars()
12843                .map(|c| match c {
12844                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12845                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12846                    _ => c,
12847                })
12848                .collect()
12849        })
12850    }
12851
12852    fn convert_text_case(text: &str, case: Case) -> String {
12853        text.lines()
12854            .map(|line| {
12855                let trimmed_start = line.trim_start();
12856                let leading = &line[..line.len() - trimmed_start.len()];
12857                let trimmed = trimmed_start.trim_end();
12858                let trailing = &trimmed_start[trimmed.len()..];
12859                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12860            })
12861            .join("\n")
12862    }
12863
12864    pub fn convert_to_rot47(
12865        &mut self,
12866        _: &ConvertToRot47,
12867        window: &mut Window,
12868        cx: &mut Context<Self>,
12869    ) {
12870        self.manipulate_text(window, cx, |text| {
12871            text.chars()
12872                .map(|c| {
12873                    let code_point = c as u32;
12874                    if code_point >= 33 && code_point <= 126 {
12875                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12876                    }
12877                    c
12878                })
12879                .collect()
12880        })
12881    }
12882
12883    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12884    where
12885        Fn: FnMut(&str) -> String,
12886    {
12887        let buffer = self.buffer.read(cx).snapshot(cx);
12888
12889        let mut new_selections = Vec::new();
12890        let mut edits = Vec::new();
12891        let mut selection_adjustment = 0isize;
12892
12893        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12894            let selection_is_empty = selection.is_empty();
12895
12896            let (start, end) = if selection_is_empty {
12897                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12898                (word_range.start, word_range.end)
12899            } else {
12900                (
12901                    buffer.point_to_offset(selection.start),
12902                    buffer.point_to_offset(selection.end),
12903                )
12904            };
12905
12906            let text = buffer.text_for_range(start..end).collect::<String>();
12907            let old_length = text.len() as isize;
12908            let text = callback(&text);
12909
12910            new_selections.push(Selection {
12911                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12912                end: MultiBufferOffset(
12913                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12914                ),
12915                goal: SelectionGoal::None,
12916                id: selection.id,
12917                reversed: selection.reversed,
12918            });
12919
12920            selection_adjustment += old_length - text.len() as isize;
12921
12922            edits.push((start..end, text));
12923        }
12924
12925        self.transact(window, cx, |this, window, cx| {
12926            this.buffer.update(cx, |buffer, cx| {
12927                buffer.edit(edits, None, cx);
12928            });
12929
12930            this.change_selections(Default::default(), window, cx, |s| {
12931                s.select(new_selections);
12932            });
12933
12934            this.request_autoscroll(Autoscroll::fit(), cx);
12935        });
12936    }
12937
12938    pub fn move_selection_on_drop(
12939        &mut self,
12940        selection: &Selection<Anchor>,
12941        target: DisplayPoint,
12942        is_cut: bool,
12943        window: &mut Window,
12944        cx: &mut Context<Self>,
12945    ) {
12946        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12947        let buffer = display_map.buffer_snapshot();
12948        let mut edits = Vec::new();
12949        let insert_point = display_map
12950            .clip_point(target, Bias::Left)
12951            .to_point(&display_map);
12952        let text = buffer
12953            .text_for_range(selection.start..selection.end)
12954            .collect::<String>();
12955        if is_cut {
12956            edits.push(((selection.start..selection.end), String::new()));
12957        }
12958        let insert_anchor = buffer.anchor_before(insert_point);
12959        edits.push(((insert_anchor..insert_anchor), text));
12960        let last_edit_start = insert_anchor.bias_left(buffer);
12961        let last_edit_end = insert_anchor.bias_right(buffer);
12962        self.transact(window, cx, |this, window, cx| {
12963            this.buffer.update(cx, |buffer, cx| {
12964                buffer.edit(edits, None, cx);
12965            });
12966            this.change_selections(Default::default(), window, cx, |s| {
12967                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12968            });
12969        });
12970    }
12971
12972    pub fn clear_selection_drag_state(&mut self) {
12973        self.selection_drag_state = SelectionDragState::None;
12974    }
12975
12976    pub fn duplicate(
12977        &mut self,
12978        upwards: bool,
12979        whole_lines: bool,
12980        window: &mut Window,
12981        cx: &mut Context<Self>,
12982    ) {
12983        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12984
12985        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12986        let buffer = display_map.buffer_snapshot();
12987        let selections = self.selections.all::<Point>(&display_map);
12988
12989        let mut edits = Vec::new();
12990        let mut selections_iter = selections.iter().peekable();
12991        while let Some(selection) = selections_iter.next() {
12992            let mut rows = selection.spanned_rows(false, &display_map);
12993            // duplicate line-wise
12994            if whole_lines || selection.start == selection.end {
12995                // Avoid duplicating the same lines twice.
12996                while let Some(next_selection) = selections_iter.peek() {
12997                    let next_rows = next_selection.spanned_rows(false, &display_map);
12998                    if next_rows.start < rows.end {
12999                        rows.end = next_rows.end;
13000                        selections_iter.next().unwrap();
13001                    } else {
13002                        break;
13003                    }
13004                }
13005
13006                // Copy the text from the selected row region and splice it either at the start
13007                // or end of the region.
13008                let start = Point::new(rows.start.0, 0);
13009                let end = Point::new(
13010                    rows.end.previous_row().0,
13011                    buffer.line_len(rows.end.previous_row()),
13012                );
13013
13014                let mut text = buffer.text_for_range(start..end).collect::<String>();
13015
13016                let insert_location = if upwards {
13017                    // When duplicating upward, we need to insert before the current line.
13018                    // If we're on the last line and it doesn't end with a newline,
13019                    // we need to add a newline before the duplicated content.
13020                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13021                        && buffer.max_point().column > 0
13022                        && !text.ends_with('\n');
13023
13024                    if needs_leading_newline {
13025                        text.insert(0, '\n');
13026                        end
13027                    } else {
13028                        text.push('\n');
13029                        Point::new(rows.start.0, 0)
13030                    }
13031                } else {
13032                    text.push('\n');
13033                    start
13034                };
13035                edits.push((insert_location..insert_location, text));
13036            } else {
13037                // duplicate character-wise
13038                let start = selection.start;
13039                let end = selection.end;
13040                let text = buffer.text_for_range(start..end).collect::<String>();
13041                edits.push((selection.end..selection.end, text));
13042            }
13043        }
13044
13045        self.transact(window, cx, |this, window, cx| {
13046            this.buffer.update(cx, |buffer, cx| {
13047                buffer.edit(edits, None, cx);
13048            });
13049
13050            // When duplicating upward with whole lines, move the cursor to the duplicated line
13051            if upwards && whole_lines {
13052                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13053
13054                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13055                    let mut new_ranges = Vec::new();
13056                    let selections = s.all::<Point>(&display_map);
13057                    let mut selections_iter = selections.iter().peekable();
13058
13059                    while let Some(first_selection) = selections_iter.next() {
13060                        // Group contiguous selections together to find the total row span
13061                        let mut group_selections = vec![first_selection];
13062                        let mut rows = first_selection.spanned_rows(false, &display_map);
13063
13064                        while let Some(next_selection) = selections_iter.peek() {
13065                            let next_rows = next_selection.spanned_rows(false, &display_map);
13066                            if next_rows.start < rows.end {
13067                                rows.end = next_rows.end;
13068                                group_selections.push(selections_iter.next().unwrap());
13069                            } else {
13070                                break;
13071                            }
13072                        }
13073
13074                        let row_count = rows.end.0 - rows.start.0;
13075
13076                        // Move all selections in this group up by the total number of duplicated rows
13077                        for selection in group_selections {
13078                            let new_start = Point::new(
13079                                selection.start.row.saturating_sub(row_count),
13080                                selection.start.column,
13081                            );
13082
13083                            let new_end = Point::new(
13084                                selection.end.row.saturating_sub(row_count),
13085                                selection.end.column,
13086                            );
13087
13088                            new_ranges.push(new_start..new_end);
13089                        }
13090                    }
13091
13092                    s.select_ranges(new_ranges);
13093                });
13094            }
13095
13096            this.request_autoscroll(Autoscroll::fit(), cx);
13097        });
13098    }
13099
13100    pub fn duplicate_line_up(
13101        &mut self,
13102        _: &DuplicateLineUp,
13103        window: &mut Window,
13104        cx: &mut Context<Self>,
13105    ) {
13106        self.duplicate(true, true, window, cx);
13107    }
13108
13109    pub fn duplicate_line_down(
13110        &mut self,
13111        _: &DuplicateLineDown,
13112        window: &mut Window,
13113        cx: &mut Context<Self>,
13114    ) {
13115        self.duplicate(false, true, window, cx);
13116    }
13117
13118    pub fn duplicate_selection(
13119        &mut self,
13120        _: &DuplicateSelection,
13121        window: &mut Window,
13122        cx: &mut Context<Self>,
13123    ) {
13124        self.duplicate(false, false, window, cx);
13125    }
13126
13127    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13129        if self.mode.is_single_line() {
13130            cx.propagate();
13131            return;
13132        }
13133
13134        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13135        let buffer = self.buffer.read(cx).snapshot(cx);
13136
13137        let mut edits = Vec::new();
13138        let mut unfold_ranges = Vec::new();
13139        let mut refold_creases = Vec::new();
13140
13141        let selections = self.selections.all::<Point>(&display_map);
13142        let mut selections = selections.iter().peekable();
13143        let mut contiguous_row_selections = Vec::new();
13144        let mut new_selections = Vec::new();
13145
13146        while let Some(selection) = selections.next() {
13147            // Find all the selections that span a contiguous row range
13148            let (start_row, end_row) = consume_contiguous_rows(
13149                &mut contiguous_row_selections,
13150                selection,
13151                &display_map,
13152                &mut selections,
13153            );
13154
13155            // Move the text spanned by the row range to be before the line preceding the row range
13156            if start_row.0 > 0 {
13157                let range_to_move = Point::new(
13158                    start_row.previous_row().0,
13159                    buffer.line_len(start_row.previous_row()),
13160                )
13161                    ..Point::new(
13162                        end_row.previous_row().0,
13163                        buffer.line_len(end_row.previous_row()),
13164                    );
13165                let insertion_point = display_map
13166                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13167                    .0;
13168
13169                // Don't move lines across excerpts
13170                if buffer
13171                    .excerpt_containing(insertion_point..range_to_move.end)
13172                    .is_some()
13173                {
13174                    let text = buffer
13175                        .text_for_range(range_to_move.clone())
13176                        .flat_map(|s| s.chars())
13177                        .skip(1)
13178                        .chain(['\n'])
13179                        .collect::<String>();
13180
13181                    edits.push((
13182                        buffer.anchor_after(range_to_move.start)
13183                            ..buffer.anchor_before(range_to_move.end),
13184                        String::new(),
13185                    ));
13186                    let insertion_anchor = buffer.anchor_after(insertion_point);
13187                    edits.push((insertion_anchor..insertion_anchor, text));
13188
13189                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13190
13191                    // Move selections up
13192                    new_selections.extend(contiguous_row_selections.drain(..).map(
13193                        |mut selection| {
13194                            selection.start.row -= row_delta;
13195                            selection.end.row -= row_delta;
13196                            selection
13197                        },
13198                    ));
13199
13200                    // Move folds up
13201                    unfold_ranges.push(range_to_move.clone());
13202                    for fold in display_map.folds_in_range(
13203                        buffer.anchor_before(range_to_move.start)
13204                            ..buffer.anchor_after(range_to_move.end),
13205                    ) {
13206                        let mut start = fold.range.start.to_point(&buffer);
13207                        let mut end = fold.range.end.to_point(&buffer);
13208                        start.row -= row_delta;
13209                        end.row -= row_delta;
13210                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13211                    }
13212                }
13213            }
13214
13215            // If we didn't move line(s), preserve the existing selections
13216            new_selections.append(&mut contiguous_row_selections);
13217        }
13218
13219        self.transact(window, cx, |this, window, cx| {
13220            this.unfold_ranges(&unfold_ranges, true, true, cx);
13221            this.buffer.update(cx, |buffer, cx| {
13222                for (range, text) in edits {
13223                    buffer.edit([(range, text)], None, cx);
13224                }
13225            });
13226            this.fold_creases(refold_creases, true, window, cx);
13227            this.change_selections(Default::default(), window, cx, |s| {
13228                s.select(new_selections);
13229            })
13230        });
13231    }
13232
13233    pub fn move_line_down(
13234        &mut self,
13235        _: &MoveLineDown,
13236        window: &mut Window,
13237        cx: &mut Context<Self>,
13238    ) {
13239        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13240        if self.mode.is_single_line() {
13241            cx.propagate();
13242            return;
13243        }
13244
13245        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13246        let buffer = self.buffer.read(cx).snapshot(cx);
13247
13248        let mut edits = Vec::new();
13249        let mut unfold_ranges = Vec::new();
13250        let mut refold_creases = Vec::new();
13251
13252        let selections = self.selections.all::<Point>(&display_map);
13253        let mut selections = selections.iter().peekable();
13254        let mut contiguous_row_selections = Vec::new();
13255        let mut new_selections = Vec::new();
13256
13257        while let Some(selection) = selections.next() {
13258            // Find all the selections that span a contiguous row range
13259            let (start_row, end_row) = consume_contiguous_rows(
13260                &mut contiguous_row_selections,
13261                selection,
13262                &display_map,
13263                &mut selections,
13264            );
13265
13266            // Move the text spanned by the row range to be after the last line of the row range
13267            if end_row.0 <= buffer.max_point().row {
13268                let range_to_move =
13269                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13270                let insertion_point = display_map
13271                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13272                    .0;
13273
13274                // Don't move lines across excerpt boundaries
13275                if buffer
13276                    .excerpt_containing(range_to_move.start..insertion_point)
13277                    .is_some()
13278                {
13279                    let mut text = String::from("\n");
13280                    text.extend(buffer.text_for_range(range_to_move.clone()));
13281                    text.pop(); // Drop trailing newline
13282                    edits.push((
13283                        buffer.anchor_after(range_to_move.start)
13284                            ..buffer.anchor_before(range_to_move.end),
13285                        String::new(),
13286                    ));
13287                    let insertion_anchor = buffer.anchor_after(insertion_point);
13288                    edits.push((insertion_anchor..insertion_anchor, text));
13289
13290                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13291
13292                    // Move selections down
13293                    new_selections.extend(contiguous_row_selections.drain(..).map(
13294                        |mut selection| {
13295                            selection.start.row += row_delta;
13296                            selection.end.row += row_delta;
13297                            selection
13298                        },
13299                    ));
13300
13301                    // Move folds down
13302                    unfold_ranges.push(range_to_move.clone());
13303                    for fold in display_map.folds_in_range(
13304                        buffer.anchor_before(range_to_move.start)
13305                            ..buffer.anchor_after(range_to_move.end),
13306                    ) {
13307                        let mut start = fold.range.start.to_point(&buffer);
13308                        let mut end = fold.range.end.to_point(&buffer);
13309                        start.row += row_delta;
13310                        end.row += row_delta;
13311                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13312                    }
13313                }
13314            }
13315
13316            // If we didn't move line(s), preserve the existing selections
13317            new_selections.append(&mut contiguous_row_selections);
13318        }
13319
13320        self.transact(window, cx, |this, window, cx| {
13321            this.unfold_ranges(&unfold_ranges, true, true, cx);
13322            this.buffer.update(cx, |buffer, cx| {
13323                for (range, text) in edits {
13324                    buffer.edit([(range, text)], None, cx);
13325                }
13326            });
13327            this.fold_creases(refold_creases, true, window, cx);
13328            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13329        });
13330    }
13331
13332    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13333        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13334        let text_layout_details = &self.text_layout_details(window, cx);
13335        self.transact(window, cx, |this, window, cx| {
13336            let edits = this.change_selections(Default::default(), window, cx, |s| {
13337                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13338                s.move_with(&mut |display_map, selection| {
13339                    if !selection.is_empty() {
13340                        return;
13341                    }
13342
13343                    let mut head = selection.head();
13344                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13345                    if head.column() == display_map.line_len(head.row()) {
13346                        transpose_offset = display_map
13347                            .buffer_snapshot()
13348                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13349                    }
13350
13351                    if transpose_offset == MultiBufferOffset(0) {
13352                        return;
13353                    }
13354
13355                    *head.column_mut() += 1;
13356                    head = display_map.clip_point(head, Bias::Right);
13357                    let goal = SelectionGoal::HorizontalPosition(
13358                        display_map
13359                            .x_for_display_point(head, text_layout_details)
13360                            .into(),
13361                    );
13362                    selection.collapse_to(head, goal);
13363
13364                    let transpose_start = display_map
13365                        .buffer_snapshot()
13366                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13367                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13368                        let transpose_end = display_map
13369                            .buffer_snapshot()
13370                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13371                        if let Some(ch) = display_map
13372                            .buffer_snapshot()
13373                            .chars_at(transpose_start)
13374                            .next()
13375                        {
13376                            edits.push((transpose_start..transpose_offset, String::new()));
13377                            edits.push((transpose_end..transpose_end, ch.to_string()));
13378                        }
13379                    }
13380                });
13381                edits
13382            });
13383            this.buffer
13384                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13385            let selections = this
13386                .selections
13387                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13388            this.change_selections(Default::default(), window, cx, |s| {
13389                s.select(selections);
13390            });
13391        });
13392    }
13393
13394    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13395        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13396        if self.mode.is_single_line() {
13397            cx.propagate();
13398            return;
13399        }
13400
13401        self.rewrap_impl(RewrapOptions::default(), cx)
13402    }
13403
13404    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13405        let buffer = self.buffer.read(cx).snapshot(cx);
13406        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13407
13408        #[derive(Clone, Debug, PartialEq)]
13409        enum CommentFormat {
13410            /// single line comment, with prefix for line
13411            Line(String),
13412            /// single line within a block comment, with prefix for line
13413            BlockLine(String),
13414            /// a single line of a block comment that includes the initial delimiter
13415            BlockCommentWithStart(BlockCommentConfig),
13416            /// a single line of a block comment that includes the ending delimiter
13417            BlockCommentWithEnd(BlockCommentConfig),
13418        }
13419
13420        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13421        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13422            let language_settings = buffer.language_settings_at(selection.head(), cx);
13423            let language_scope = buffer.language_scope_at(selection.head());
13424
13425            let indent_and_prefix_for_row =
13426                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13427                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13428                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13429                        &language_scope
13430                    {
13431                        let indent_end = Point::new(row, indent.len);
13432                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13433                        let line_text_after_indent = buffer
13434                            .text_for_range(indent_end..line_end)
13435                            .collect::<String>();
13436
13437                        let is_within_comment_override = buffer
13438                            .language_scope_at(indent_end)
13439                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13440                        let comment_delimiters = if is_within_comment_override {
13441                            // we are within a comment syntax node, but we don't
13442                            // yet know what kind of comment: block, doc or line
13443                            match (
13444                                language_scope.documentation_comment(),
13445                                language_scope.block_comment(),
13446                            ) {
13447                                (Some(config), _) | (_, Some(config))
13448                                    if buffer.contains_str_at(indent_end, &config.start) =>
13449                                {
13450                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13451                                }
13452                                (Some(config), _) | (_, Some(config))
13453                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13454                                {
13455                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13456                                }
13457                                (Some(config), _) | (_, Some(config))
13458                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13459                                {
13460                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13461                                }
13462                                (_, _) => language_scope
13463                                    .line_comment_prefixes()
13464                                    .iter()
13465                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13466                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13467                            }
13468                        } else {
13469                            // we not in an overridden comment node, but we may
13470                            // be within a non-overridden line comment node
13471                            language_scope
13472                                .line_comment_prefixes()
13473                                .iter()
13474                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13475                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13476                        };
13477
13478                        let rewrap_prefix = language_scope
13479                            .rewrap_prefixes()
13480                            .iter()
13481                            .find_map(|prefix_regex| {
13482                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13483                                    if mat.start() == 0 {
13484                                        Some(mat.as_str().to_string())
13485                                    } else {
13486                                        None
13487                                    }
13488                                })
13489                            })
13490                            .flatten();
13491                        (comment_delimiters, rewrap_prefix)
13492                    } else {
13493                        (None, None)
13494                    };
13495                    (indent, comment_prefix, rewrap_prefix)
13496                };
13497
13498            let mut start_row = selection.start.row;
13499            let mut end_row = selection.end.row;
13500
13501            if selection.is_empty() {
13502                let cursor_row = selection.start.row;
13503
13504                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13505                let line_prefix = match &comment_prefix {
13506                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13507                        Some(prefix.as_str())
13508                    }
13509                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13510                        prefix, ..
13511                    })) => Some(prefix.as_ref()),
13512                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13513                        start: _,
13514                        end: _,
13515                        prefix,
13516                        tab_size,
13517                    })) => {
13518                        indent_size.len += tab_size;
13519                        Some(prefix.as_ref())
13520                    }
13521                    None => None,
13522                };
13523                let indent_prefix = indent_size.chars().collect::<String>();
13524                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13525
13526                'expand_upwards: while start_row > 0 {
13527                    let prev_row = start_row - 1;
13528                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13529                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13530                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13531                    {
13532                        start_row = prev_row;
13533                    } else {
13534                        break 'expand_upwards;
13535                    }
13536                }
13537
13538                'expand_downwards: while end_row < buffer.max_point().row {
13539                    let next_row = end_row + 1;
13540                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13541                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13542                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13543                    {
13544                        end_row = next_row;
13545                    } else {
13546                        break 'expand_downwards;
13547                    }
13548                }
13549            }
13550
13551            let mut non_blank_rows_iter = (start_row..=end_row)
13552                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13553                .peekable();
13554
13555            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13556                row
13557            } else {
13558                return Vec::new();
13559            };
13560
13561            let mut ranges = Vec::new();
13562
13563            let mut current_range_start = first_row;
13564            let mut prev_row = first_row;
13565            let (
13566                mut current_range_indent,
13567                mut current_range_comment_delimiters,
13568                mut current_range_rewrap_prefix,
13569            ) = indent_and_prefix_for_row(first_row);
13570
13571            for row in non_blank_rows_iter.skip(1) {
13572                let has_paragraph_break = row > prev_row + 1;
13573
13574                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13575                    indent_and_prefix_for_row(row);
13576
13577                let has_indent_change = row_indent != current_range_indent;
13578                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13579
13580                let has_boundary_change = has_comment_change
13581                    || row_rewrap_prefix.is_some()
13582                    || (has_indent_change && current_range_comment_delimiters.is_some());
13583
13584                if has_paragraph_break || has_boundary_change {
13585                    ranges.push((
13586                        language_settings.clone(),
13587                        Point::new(current_range_start, 0)
13588                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13589                        current_range_indent,
13590                        current_range_comment_delimiters.clone(),
13591                        current_range_rewrap_prefix.clone(),
13592                    ));
13593                    current_range_start = row;
13594                    current_range_indent = row_indent;
13595                    current_range_comment_delimiters = row_comment_delimiters;
13596                    current_range_rewrap_prefix = row_rewrap_prefix;
13597                }
13598                prev_row = row;
13599            }
13600
13601            ranges.push((
13602                language_settings.clone(),
13603                Point::new(current_range_start, 0)
13604                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13605                current_range_indent,
13606                current_range_comment_delimiters,
13607                current_range_rewrap_prefix,
13608            ));
13609
13610            ranges
13611        });
13612
13613        let mut edits = Vec::new();
13614        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13615
13616        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13617            wrap_ranges
13618        {
13619            let start_row = wrap_range.start.row;
13620            let end_row = wrap_range.end.row;
13621
13622            // Skip selections that overlap with a range that has already been rewrapped.
13623            let selection_range = start_row..end_row;
13624            if rewrapped_row_ranges
13625                .iter()
13626                .any(|range| range.overlaps(&selection_range))
13627            {
13628                continue;
13629            }
13630
13631            let tab_size = language_settings.tab_size;
13632
13633            let (line_prefix, inside_comment) = match &comment_prefix {
13634                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13635                    (Some(prefix.as_str()), true)
13636                }
13637                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13638                    (Some(prefix.as_ref()), true)
13639                }
13640                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13641                    start: _,
13642                    end: _,
13643                    prefix,
13644                    tab_size,
13645                })) => {
13646                    indent_size.len += tab_size;
13647                    (Some(prefix.as_ref()), true)
13648                }
13649                None => (None, false),
13650            };
13651            let indent_prefix = indent_size.chars().collect::<String>();
13652            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13653
13654            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13655                RewrapBehavior::InComments => inside_comment,
13656                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13657                RewrapBehavior::Anywhere => true,
13658            };
13659
13660            let should_rewrap = options.override_language_settings
13661                || allow_rewrap_based_on_language
13662                || self.hard_wrap.is_some();
13663            if !should_rewrap {
13664                continue;
13665            }
13666
13667            let start = Point::new(start_row, 0);
13668            let start_offset = ToOffset::to_offset(&start, &buffer);
13669            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13670            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13671            let mut first_line_delimiter = None;
13672            let mut last_line_delimiter = None;
13673            let Some(lines_without_prefixes) = selection_text
13674                .lines()
13675                .enumerate()
13676                .map(|(ix, line)| {
13677                    let line_trimmed = line.trim_start();
13678                    if rewrap_prefix.is_some() && ix > 0 {
13679                        Ok(line_trimmed)
13680                    } else if let Some(
13681                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13682                            start,
13683                            prefix,
13684                            end,
13685                            tab_size,
13686                        })
13687                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13688                            start,
13689                            prefix,
13690                            end,
13691                            tab_size,
13692                        }),
13693                    ) = &comment_prefix
13694                    {
13695                        let line_trimmed = line_trimmed
13696                            .strip_prefix(start.as_ref())
13697                            .map(|s| {
13698                                let mut indent_size = indent_size;
13699                                indent_size.len -= tab_size;
13700                                let indent_prefix: String = indent_size.chars().collect();
13701                                first_line_delimiter = Some((indent_prefix, start));
13702                                s.trim_start()
13703                            })
13704                            .unwrap_or(line_trimmed);
13705                        let line_trimmed = line_trimmed
13706                            .strip_suffix(end.as_ref())
13707                            .map(|s| {
13708                                last_line_delimiter = Some(end);
13709                                s.trim_end()
13710                            })
13711                            .unwrap_or(line_trimmed);
13712                        let line_trimmed = line_trimmed
13713                            .strip_prefix(prefix.as_ref())
13714                            .unwrap_or(line_trimmed);
13715                        Ok(line_trimmed)
13716                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13717                        line_trimmed.strip_prefix(prefix).with_context(|| {
13718                            format!("line did not start with prefix {prefix:?}: {line:?}")
13719                        })
13720                    } else {
13721                        line_trimmed
13722                            .strip_prefix(&line_prefix.trim_start())
13723                            .with_context(|| {
13724                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13725                            })
13726                    }
13727                })
13728                .collect::<Result<Vec<_>, _>>()
13729                .log_err()
13730            else {
13731                continue;
13732            };
13733
13734            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13735                buffer
13736                    .language_settings_at(Point::new(start_row, 0), cx)
13737                    .preferred_line_length as usize
13738            });
13739
13740            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13741                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13742            } else {
13743                line_prefix.clone()
13744            };
13745
13746            let wrapped_text = {
13747                let mut wrapped_text = wrap_with_prefix(
13748                    line_prefix,
13749                    subsequent_lines_prefix,
13750                    lines_without_prefixes.join("\n"),
13751                    wrap_column,
13752                    tab_size,
13753                    options.preserve_existing_whitespace,
13754                );
13755
13756                if let Some((indent, delimiter)) = first_line_delimiter {
13757                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13758                }
13759                if let Some(last_line) = last_line_delimiter {
13760                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13761                }
13762
13763                wrapped_text
13764            };
13765
13766            // TODO: should always use char-based diff while still supporting cursor behavior that
13767            // matches vim.
13768            let mut diff_options = DiffOptions::default();
13769            if options.override_language_settings {
13770                diff_options.max_word_diff_len = 0;
13771                diff_options.max_word_diff_line_count = 0;
13772            } else {
13773                diff_options.max_word_diff_len = usize::MAX;
13774                diff_options.max_word_diff_line_count = usize::MAX;
13775            }
13776
13777            for (old_range, new_text) in
13778                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13779            {
13780                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13781                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13782                edits.push((edit_start..edit_end, new_text));
13783            }
13784
13785            rewrapped_row_ranges.push(start_row..=end_row);
13786        }
13787
13788        self.buffer
13789            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13790    }
13791
13792    pub fn cut_common(
13793        &mut self,
13794        cut_no_selection_line: bool,
13795        window: &mut Window,
13796        cx: &mut Context<Self>,
13797    ) -> ClipboardItem {
13798        let mut text = String::new();
13799        let buffer = self.buffer.read(cx).snapshot(cx);
13800        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13801        let mut clipboard_selections = Vec::with_capacity(selections.len());
13802        {
13803            let max_point = buffer.max_point();
13804            let mut is_first = true;
13805            let mut prev_selection_was_entire_line = false;
13806            for selection in &mut selections {
13807                let is_entire_line =
13808                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13809                if is_entire_line {
13810                    selection.start = Point::new(selection.start.row, 0);
13811                    if !selection.is_empty() && selection.end.column == 0 {
13812                        selection.end = cmp::min(max_point, selection.end);
13813                    } else {
13814                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13815                    }
13816                    selection.goal = SelectionGoal::None;
13817                }
13818                if is_first {
13819                    is_first = false;
13820                } else if !prev_selection_was_entire_line {
13821                    text += "\n";
13822                }
13823                prev_selection_was_entire_line = is_entire_line;
13824                let mut len = 0;
13825                for chunk in buffer.text_for_range(selection.start..selection.end) {
13826                    text.push_str(chunk);
13827                    len += chunk.len();
13828                }
13829
13830                clipboard_selections.push(ClipboardSelection::for_buffer(
13831                    len,
13832                    is_entire_line,
13833                    selection.range(),
13834                    &buffer,
13835                    self.project.as_ref(),
13836                    cx,
13837                ));
13838            }
13839        }
13840
13841        self.transact(window, cx, |this, window, cx| {
13842            this.change_selections(Default::default(), window, cx, |s| {
13843                s.select(selections);
13844            });
13845            this.insert("", window, cx);
13846        });
13847        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13848    }
13849
13850    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13851        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13852        let item = self.cut_common(true, window, cx);
13853        cx.write_to_clipboard(item);
13854    }
13855
13856    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13857        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13858        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13859            s.move_with(&mut |snapshot, sel| {
13860                if sel.is_empty() {
13861                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13862                }
13863                if sel.is_empty() {
13864                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13865                }
13866            });
13867        });
13868        let item = self.cut_common(false, window, cx);
13869        cx.set_global(KillRing(item))
13870    }
13871
13872    pub fn kill_ring_yank(
13873        &mut self,
13874        _: &KillRingYank,
13875        window: &mut Window,
13876        cx: &mut Context<Self>,
13877    ) {
13878        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13879        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13880            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13881                (kill_ring.text().to_string(), kill_ring.metadata_json())
13882            } else {
13883                return;
13884            }
13885        } else {
13886            return;
13887        };
13888        self.do_paste(&text, metadata, false, window, cx);
13889    }
13890
13891    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13892        self.do_copy(true, cx);
13893    }
13894
13895    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13896        self.do_copy(false, cx);
13897    }
13898
13899    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13900        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13901        let buffer = self.buffer.read(cx).read(cx);
13902        let mut text = String::new();
13903        let mut clipboard_selections = Vec::with_capacity(selections.len());
13904
13905        let max_point = buffer.max_point();
13906        let mut is_first = true;
13907        for selection in &selections {
13908            let mut start = selection.start;
13909            let mut end = selection.end;
13910            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13911            let mut add_trailing_newline = false;
13912            if is_entire_line {
13913                start = Point::new(start.row, 0);
13914                let next_line_start = Point::new(end.row + 1, 0);
13915                if next_line_start <= max_point {
13916                    end = next_line_start;
13917                } else {
13918                    // We're on the last line without a trailing newline.
13919                    // Copy to the end of the line and add a newline afterwards.
13920                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13921                    add_trailing_newline = true;
13922                }
13923            }
13924
13925            let mut trimmed_selections = Vec::new();
13926            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13927                let row = MultiBufferRow(start.row);
13928                let first_indent = buffer.indent_size_for_line(row);
13929                if first_indent.len == 0 || start.column > first_indent.len {
13930                    trimmed_selections.push(start..end);
13931                } else {
13932                    trimmed_selections.push(
13933                        Point::new(row.0, first_indent.len)
13934                            ..Point::new(row.0, buffer.line_len(row)),
13935                    );
13936                    for row in start.row + 1..=end.row {
13937                        let mut line_len = buffer.line_len(MultiBufferRow(row));
13938                        if row == end.row {
13939                            line_len = end.column;
13940                        }
13941                        if line_len == 0 {
13942                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
13943                            continue;
13944                        }
13945                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13946                        if row_indent_size.len >= first_indent.len {
13947                            trimmed_selections
13948                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
13949                        } else {
13950                            trimmed_selections.clear();
13951                            trimmed_selections.push(start..end);
13952                            break;
13953                        }
13954                    }
13955                }
13956            } else {
13957                trimmed_selections.push(start..end);
13958            }
13959
13960            let is_multiline_trim = trimmed_selections.len() > 1;
13961            let mut selection_len: usize = 0;
13962            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13963
13964            for trimmed_range in trimmed_selections {
13965                if is_first {
13966                    is_first = false;
13967                } else if is_multiline_trim || !prev_selection_was_entire_line {
13968                    text.push('\n');
13969                    if is_multiline_trim {
13970                        selection_len += 1;
13971                    }
13972                }
13973                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13974                    text.push_str(chunk);
13975                    selection_len += chunk.len();
13976                }
13977                if add_trailing_newline {
13978                    text.push('\n');
13979                    selection_len += 1;
13980                }
13981            }
13982
13983            clipboard_selections.push(ClipboardSelection::for_buffer(
13984                selection_len,
13985                is_entire_line,
13986                start..end,
13987                &buffer,
13988                self.project.as_ref(),
13989                cx,
13990            ));
13991        }
13992
13993        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13994            text,
13995            clipboard_selections,
13996        ));
13997    }
13998
13999    pub fn do_paste(
14000        &mut self,
14001        text: &String,
14002        clipboard_selections: Option<Vec<ClipboardSelection>>,
14003        handle_entire_lines: bool,
14004        window: &mut Window,
14005        cx: &mut Context<Self>,
14006    ) {
14007        if self.read_only(cx) {
14008            return;
14009        }
14010
14011        let clipboard_text = Cow::Borrowed(text.as_str());
14012
14013        self.transact(window, cx, |this, window, cx| {
14014            let had_active_edit_prediction = this.has_active_edit_prediction();
14015            let display_map = this.display_snapshot(cx);
14016            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14017            let cursor_offset = this
14018                .selections
14019                .last::<MultiBufferOffset>(&display_map)
14020                .head();
14021
14022            if let Some(mut clipboard_selections) = clipboard_selections {
14023                let all_selections_were_entire_line =
14024                    clipboard_selections.iter().all(|s| s.is_entire_line);
14025                let first_selection_indent_column =
14026                    clipboard_selections.first().map(|s| s.first_line_indent);
14027                if clipboard_selections.len() != old_selections.len() {
14028                    clipboard_selections.drain(..);
14029                }
14030                let mut auto_indent_on_paste = true;
14031
14032                this.buffer.update(cx, |buffer, cx| {
14033                    let snapshot = buffer.read(cx);
14034                    auto_indent_on_paste = snapshot
14035                        .language_settings_at(cursor_offset, cx)
14036                        .auto_indent_on_paste;
14037
14038                    let mut start_offset = 0;
14039                    let mut edits = Vec::new();
14040                    let mut original_indent_columns = Vec::new();
14041                    for (ix, selection) in old_selections.iter().enumerate() {
14042                        let to_insert;
14043                        let entire_line;
14044                        let original_indent_column;
14045                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14046                            let end_offset = start_offset + clipboard_selection.len;
14047                            to_insert = &clipboard_text[start_offset..end_offset];
14048                            entire_line = clipboard_selection.is_entire_line;
14049                            start_offset = if entire_line {
14050                                end_offset
14051                            } else {
14052                                end_offset + 1
14053                            };
14054                            original_indent_column = Some(clipboard_selection.first_line_indent);
14055                        } else {
14056                            to_insert = &*clipboard_text;
14057                            entire_line = all_selections_were_entire_line;
14058                            original_indent_column = first_selection_indent_column
14059                        }
14060
14061                        let (range, to_insert) =
14062                            if selection.is_empty() && handle_entire_lines && entire_line {
14063                                // If the corresponding selection was empty when this slice of the
14064                                // clipboard text was written, then the entire line containing the
14065                                // selection was copied. If this selection is also currently empty,
14066                                // then paste the line before the current line of the buffer.
14067                                let column = selection.start.to_point(&snapshot).column as usize;
14068                                let line_start = selection.start - column;
14069                                (line_start..line_start, Cow::Borrowed(to_insert))
14070                            } else {
14071                                let language = snapshot.language_at(selection.head());
14072                                let range = selection.range();
14073                                if let Some(language) = language
14074                                    && language.name() == "Markdown"
14075                                {
14076                                    edit_for_markdown_paste(
14077                                        &snapshot,
14078                                        range,
14079                                        to_insert,
14080                                        url::Url::parse(to_insert).ok(),
14081                                    )
14082                                } else {
14083                                    (range, Cow::Borrowed(to_insert))
14084                                }
14085                            };
14086
14087                        edits.push((range, to_insert));
14088                        original_indent_columns.push(original_indent_column);
14089                    }
14090                    drop(snapshot);
14091
14092                    buffer.edit(
14093                        edits,
14094                        if auto_indent_on_paste {
14095                            Some(AutoindentMode::Block {
14096                                original_indent_columns,
14097                            })
14098                        } else {
14099                            None
14100                        },
14101                        cx,
14102                    );
14103                });
14104
14105                let selections = this
14106                    .selections
14107                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14108                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14109            } else {
14110                let url = url::Url::parse(&clipboard_text).ok();
14111
14112                let auto_indent_mode = if !clipboard_text.is_empty() {
14113                    Some(AutoindentMode::Block {
14114                        original_indent_columns: Vec::new(),
14115                    })
14116                } else {
14117                    None
14118                };
14119
14120                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14121                    let snapshot = buffer.snapshot(cx);
14122
14123                    let anchors = old_selections
14124                        .iter()
14125                        .map(|s| {
14126                            let anchor = snapshot.anchor_after(s.head());
14127                            s.map(|_| anchor)
14128                        })
14129                        .collect::<Vec<_>>();
14130
14131                    let mut edits = Vec::new();
14132
14133                    // When pasting text without metadata (e.g. copied from an
14134                    // external editor using multiple cursors) and the number of
14135                    // lines matches the number of selections, distribute one
14136                    // line per cursor instead of pasting the whole text at each.
14137                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14138                    let distribute_lines =
14139                        old_selections.len() > 1 && lines.len() == old_selections.len();
14140
14141                    for (ix, selection) in old_selections.iter().enumerate() {
14142                        let language = snapshot.language_at(selection.head());
14143                        let range = selection.range();
14144
14145                        let text_for_cursor: &str = if distribute_lines {
14146                            lines[ix]
14147                        } else {
14148                            &clipboard_text
14149                        };
14150
14151                        let (edit_range, edit_text) = if let Some(language) = language
14152                            && language.name() == "Markdown"
14153                        {
14154                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14155                        } else {
14156                            (range, Cow::Borrowed(text_for_cursor))
14157                        };
14158
14159                        edits.push((edit_range, edit_text));
14160                    }
14161
14162                    drop(snapshot);
14163                    buffer.edit(edits, auto_indent_mode, cx);
14164
14165                    anchors
14166                });
14167
14168                this.change_selections(Default::default(), window, cx, |s| {
14169                    s.select_anchors(selection_anchors);
14170                });
14171            }
14172
14173            //   🤔                 |    ..     | show_in_menu |
14174            // | ..                  |   true        true
14175            // | had_edit_prediction |   false       true
14176
14177            let trigger_in_words =
14178                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14179
14180            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14181        });
14182    }
14183
14184    pub fn diff_clipboard_with_selection(
14185        &mut self,
14186        _: &DiffClipboardWithSelection,
14187        window: &mut Window,
14188        cx: &mut Context<Self>,
14189    ) {
14190        let selections = self
14191            .selections
14192            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14193
14194        if selections.is_empty() {
14195            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14196            return;
14197        };
14198
14199        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14200            item.entries().iter().find_map(|entry| match entry {
14201                ClipboardEntry::String(text) => Some(text.text().to_string()),
14202                _ => None,
14203            })
14204        });
14205
14206        let Some(clipboard_text) = clipboard_text else {
14207            log::warn!("Clipboard doesn't contain text.");
14208            return;
14209        };
14210
14211        window.dispatch_action(
14212            Box::new(DiffClipboardWithSelectionData {
14213                clipboard_text,
14214                editor: cx.entity(),
14215            }),
14216            cx,
14217        );
14218    }
14219
14220    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14221        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14222        if let Some(item) = cx.read_from_clipboard() {
14223            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14224                ClipboardEntry::String(s) => Some(s),
14225                _ => None,
14226            });
14227            match clipboard_string {
14228                Some(clipboard_string) => self.do_paste(
14229                    clipboard_string.text(),
14230                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14231                    true,
14232                    window,
14233                    cx,
14234                ),
14235                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14236            }
14237        }
14238    }
14239
14240    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14241        if self.read_only(cx) {
14242            return;
14243        }
14244
14245        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14246
14247        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14248            if let Some((selections, _)) =
14249                self.selection_history.transaction(transaction_id).cloned()
14250            {
14251                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14252                    s.select_anchors(selections.to_vec());
14253                });
14254            } else {
14255                log::error!(
14256                    "No entry in selection_history found for undo. \
14257                     This may correspond to a bug where undo does not update the selection. \
14258                     If this is occurring, please add details to \
14259                     https://github.com/zed-industries/zed/issues/22692"
14260                );
14261            }
14262            self.request_autoscroll(Autoscroll::fit(), cx);
14263            self.unmark_text(window, cx);
14264            self.refresh_edit_prediction(true, false, window, cx);
14265            cx.emit(EditorEvent::Edited { transaction_id });
14266            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14267        }
14268    }
14269
14270    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14271        if self.read_only(cx) {
14272            return;
14273        }
14274
14275        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14276
14277        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14278            if let Some((_, Some(selections))) =
14279                self.selection_history.transaction(transaction_id).cloned()
14280            {
14281                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14282                    s.select_anchors(selections.to_vec());
14283                });
14284            } else {
14285                log::error!(
14286                    "No entry in selection_history found for redo. \
14287                     This may correspond to a bug where undo does not update the selection. \
14288                     If this is occurring, please add details to \
14289                     https://github.com/zed-industries/zed/issues/22692"
14290                );
14291            }
14292            self.request_autoscroll(Autoscroll::fit(), cx);
14293            self.unmark_text(window, cx);
14294            self.refresh_edit_prediction(true, false, window, cx);
14295            cx.emit(EditorEvent::Edited { transaction_id });
14296        }
14297    }
14298
14299    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14300        self.buffer
14301            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14302    }
14303
14304    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14305        self.buffer
14306            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14307    }
14308
14309    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14310        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14311        self.change_selections(Default::default(), window, cx, |s| {
14312            s.move_with(&mut |map, selection| {
14313                let cursor = if selection.is_empty() {
14314                    movement::left(map, selection.start)
14315                } else {
14316                    selection.start
14317                };
14318                selection.collapse_to(cursor, SelectionGoal::None);
14319            });
14320        })
14321    }
14322
14323    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14324        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14325        self.change_selections(Default::default(), window, cx, |s| {
14326            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14327        })
14328    }
14329
14330    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14331        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14332        self.change_selections(Default::default(), window, cx, |s| {
14333            s.move_with(&mut |map, selection| {
14334                let cursor = if selection.is_empty() {
14335                    movement::right(map, selection.end)
14336                } else {
14337                    selection.end
14338                };
14339                selection.collapse_to(cursor, SelectionGoal::None)
14340            });
14341        })
14342    }
14343
14344    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14345        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14346        self.change_selections(Default::default(), window, cx, |s| {
14347            s.move_heads_with(&mut |map, head, _| {
14348                (movement::right(map, head), SelectionGoal::None)
14349            });
14350        });
14351    }
14352
14353    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14354        if self.take_rename(true, window, cx).is_some() {
14355            return;
14356        }
14357
14358        if self.mode.is_single_line() {
14359            cx.propagate();
14360            return;
14361        }
14362
14363        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14364
14365        let text_layout_details = &self.text_layout_details(window, cx);
14366        let selection_count = self.selections.count();
14367        let first_selection = self.selections.first_anchor();
14368
14369        self.change_selections(Default::default(), window, cx, |s| {
14370            s.move_with(&mut |map, selection| {
14371                if !selection.is_empty() {
14372                    selection.goal = SelectionGoal::None;
14373                }
14374                let (cursor, goal) = movement::up(
14375                    map,
14376                    selection.start,
14377                    selection.goal,
14378                    false,
14379                    text_layout_details,
14380                );
14381                selection.collapse_to(cursor, goal);
14382            });
14383        });
14384
14385        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14386        {
14387            cx.propagate();
14388        }
14389    }
14390
14391    pub fn move_up_by_lines(
14392        &mut self,
14393        action: &MoveUpByLines,
14394        window: &mut Window,
14395        cx: &mut Context<Self>,
14396    ) {
14397        if self.take_rename(true, window, cx).is_some() {
14398            return;
14399        }
14400
14401        if self.mode.is_single_line() {
14402            cx.propagate();
14403            return;
14404        }
14405
14406        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14407
14408        let text_layout_details = &self.text_layout_details(window, cx);
14409
14410        self.change_selections(Default::default(), window, cx, |s| {
14411            s.move_with(&mut |map, selection| {
14412                if !selection.is_empty() {
14413                    selection.goal = SelectionGoal::None;
14414                }
14415                let (cursor, goal) = movement::up_by_rows(
14416                    map,
14417                    selection.start,
14418                    action.lines,
14419                    selection.goal,
14420                    false,
14421                    text_layout_details,
14422                );
14423                selection.collapse_to(cursor, goal);
14424            });
14425        })
14426    }
14427
14428    pub fn move_down_by_lines(
14429        &mut self,
14430        action: &MoveDownByLines,
14431        window: &mut Window,
14432        cx: &mut Context<Self>,
14433    ) {
14434        if self.take_rename(true, window, cx).is_some() {
14435            return;
14436        }
14437
14438        if self.mode.is_single_line() {
14439            cx.propagate();
14440            return;
14441        }
14442
14443        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14444
14445        let text_layout_details = &self.text_layout_details(window, cx);
14446
14447        self.change_selections(Default::default(), window, cx, |s| {
14448            s.move_with(&mut |map, selection| {
14449                if !selection.is_empty() {
14450                    selection.goal = SelectionGoal::None;
14451                }
14452                let (cursor, goal) = movement::down_by_rows(
14453                    map,
14454                    selection.start,
14455                    action.lines,
14456                    selection.goal,
14457                    false,
14458                    text_layout_details,
14459                );
14460                selection.collapse_to(cursor, goal);
14461            });
14462        })
14463    }
14464
14465    pub fn select_down_by_lines(
14466        &mut self,
14467        action: &SelectDownByLines,
14468        window: &mut Window,
14469        cx: &mut Context<Self>,
14470    ) {
14471        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14472        let text_layout_details = &self.text_layout_details(window, cx);
14473        self.change_selections(Default::default(), window, cx, |s| {
14474            s.move_heads_with(&mut |map, head, goal| {
14475                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14476            })
14477        })
14478    }
14479
14480    pub fn select_up_by_lines(
14481        &mut self,
14482        action: &SelectUpByLines,
14483        window: &mut Window,
14484        cx: &mut Context<Self>,
14485    ) {
14486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14487        let text_layout_details = &self.text_layout_details(window, cx);
14488        self.change_selections(Default::default(), window, cx, |s| {
14489            s.move_heads_with(&mut |map, head, goal| {
14490                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14491            })
14492        })
14493    }
14494
14495    pub fn select_page_up(
14496        &mut self,
14497        _: &SelectPageUp,
14498        window: &mut Window,
14499        cx: &mut Context<Self>,
14500    ) {
14501        let Some(row_count) = self.visible_row_count() else {
14502            return;
14503        };
14504
14505        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14506
14507        let text_layout_details = &self.text_layout_details(window, cx);
14508
14509        self.change_selections(Default::default(), window, cx, |s| {
14510            s.move_heads_with(&mut |map, head, goal| {
14511                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14512            })
14513        })
14514    }
14515
14516    pub fn move_page_up(
14517        &mut self,
14518        action: &MovePageUp,
14519        window: &mut Window,
14520        cx: &mut Context<Self>,
14521    ) {
14522        if self.take_rename(true, window, cx).is_some() {
14523            return;
14524        }
14525
14526        if self
14527            .context_menu
14528            .borrow_mut()
14529            .as_mut()
14530            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14531            .unwrap_or(false)
14532        {
14533            return;
14534        }
14535
14536        if matches!(self.mode, EditorMode::SingleLine) {
14537            cx.propagate();
14538            return;
14539        }
14540
14541        let Some(row_count) = self.visible_row_count() else {
14542            return;
14543        };
14544
14545        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14546
14547        let effects = if action.center_cursor {
14548            SelectionEffects::scroll(Autoscroll::center())
14549        } else {
14550            SelectionEffects::default()
14551        };
14552
14553        let text_layout_details = &self.text_layout_details(window, cx);
14554
14555        self.change_selections(effects, window, cx, |s| {
14556            s.move_with(&mut |map, selection| {
14557                if !selection.is_empty() {
14558                    selection.goal = SelectionGoal::None;
14559                }
14560                let (cursor, goal) = movement::up_by_rows(
14561                    map,
14562                    selection.end,
14563                    row_count,
14564                    selection.goal,
14565                    false,
14566                    text_layout_details,
14567                );
14568                selection.collapse_to(cursor, goal);
14569            });
14570        });
14571    }
14572
14573    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14574        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14575        let text_layout_details = &self.text_layout_details(window, cx);
14576        self.change_selections(Default::default(), window, cx, |s| {
14577            s.move_heads_with(&mut |map, head, goal| {
14578                movement::up(map, head, goal, false, text_layout_details)
14579            })
14580        })
14581    }
14582
14583    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14584        self.take_rename(true, window, cx);
14585
14586        if self.mode.is_single_line() {
14587            cx.propagate();
14588            return;
14589        }
14590
14591        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14592
14593        let text_layout_details = &self.text_layout_details(window, cx);
14594        let selection_count = self.selections.count();
14595        let first_selection = self.selections.first_anchor();
14596
14597        self.change_selections(Default::default(), window, cx, |s| {
14598            s.move_with(&mut |map, selection| {
14599                if !selection.is_empty() {
14600                    selection.goal = SelectionGoal::None;
14601                }
14602                let (cursor, goal) = movement::down(
14603                    map,
14604                    selection.end,
14605                    selection.goal,
14606                    false,
14607                    text_layout_details,
14608                );
14609                selection.collapse_to(cursor, goal);
14610            });
14611        });
14612
14613        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14614        {
14615            cx.propagate();
14616        }
14617    }
14618
14619    pub fn select_page_down(
14620        &mut self,
14621        _: &SelectPageDown,
14622        window: &mut Window,
14623        cx: &mut Context<Self>,
14624    ) {
14625        let Some(row_count) = self.visible_row_count() else {
14626            return;
14627        };
14628
14629        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14630
14631        let text_layout_details = &self.text_layout_details(window, cx);
14632
14633        self.change_selections(Default::default(), window, cx, |s| {
14634            s.move_heads_with(&mut |map, head, goal| {
14635                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14636            })
14637        })
14638    }
14639
14640    pub fn move_page_down(
14641        &mut self,
14642        action: &MovePageDown,
14643        window: &mut Window,
14644        cx: &mut Context<Self>,
14645    ) {
14646        if self.take_rename(true, window, cx).is_some() {
14647            return;
14648        }
14649
14650        if self
14651            .context_menu
14652            .borrow_mut()
14653            .as_mut()
14654            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14655            .unwrap_or(false)
14656        {
14657            return;
14658        }
14659
14660        if matches!(self.mode, EditorMode::SingleLine) {
14661            cx.propagate();
14662            return;
14663        }
14664
14665        let Some(row_count) = self.visible_row_count() else {
14666            return;
14667        };
14668
14669        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14670
14671        let effects = if action.center_cursor {
14672            SelectionEffects::scroll(Autoscroll::center())
14673        } else {
14674            SelectionEffects::default()
14675        };
14676
14677        let text_layout_details = &self.text_layout_details(window, cx);
14678        self.change_selections(effects, window, cx, |s| {
14679            s.move_with(&mut |map, selection| {
14680                if !selection.is_empty() {
14681                    selection.goal = SelectionGoal::None;
14682                }
14683                let (cursor, goal) = movement::down_by_rows(
14684                    map,
14685                    selection.end,
14686                    row_count,
14687                    selection.goal,
14688                    false,
14689                    text_layout_details,
14690                );
14691                selection.collapse_to(cursor, goal);
14692            });
14693        });
14694    }
14695
14696    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14697        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14698        let text_layout_details = &self.text_layout_details(window, cx);
14699        self.change_selections(Default::default(), window, cx, |s| {
14700            s.move_heads_with(&mut |map, head, goal| {
14701                movement::down(map, head, goal, false, text_layout_details)
14702            })
14703        });
14704    }
14705
14706    pub fn context_menu_first(
14707        &mut self,
14708        _: &ContextMenuFirst,
14709        window: &mut Window,
14710        cx: &mut Context<Self>,
14711    ) {
14712        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14713            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14714        }
14715    }
14716
14717    pub fn context_menu_prev(
14718        &mut self,
14719        _: &ContextMenuPrevious,
14720        window: &mut Window,
14721        cx: &mut Context<Self>,
14722    ) {
14723        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14724            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14725        }
14726    }
14727
14728    pub fn context_menu_next(
14729        &mut self,
14730        _: &ContextMenuNext,
14731        window: &mut Window,
14732        cx: &mut Context<Self>,
14733    ) {
14734        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14735            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14736        }
14737    }
14738
14739    pub fn context_menu_last(
14740        &mut self,
14741        _: &ContextMenuLast,
14742        window: &mut Window,
14743        cx: &mut Context<Self>,
14744    ) {
14745        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14746            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14747        }
14748    }
14749
14750    pub fn signature_help_prev(
14751        &mut self,
14752        _: &SignatureHelpPrevious,
14753        _: &mut Window,
14754        cx: &mut Context<Self>,
14755    ) {
14756        if let Some(popover) = self.signature_help_state.popover_mut() {
14757            if popover.current_signature == 0 {
14758                popover.current_signature = popover.signatures.len() - 1;
14759            } else {
14760                popover.current_signature -= 1;
14761            }
14762            cx.notify();
14763        }
14764    }
14765
14766    pub fn signature_help_next(
14767        &mut self,
14768        _: &SignatureHelpNext,
14769        _: &mut Window,
14770        cx: &mut Context<Self>,
14771    ) {
14772        if let Some(popover) = self.signature_help_state.popover_mut() {
14773            if popover.current_signature + 1 == popover.signatures.len() {
14774                popover.current_signature = 0;
14775            } else {
14776                popover.current_signature += 1;
14777            }
14778            cx.notify();
14779        }
14780    }
14781
14782    pub fn move_to_previous_word_start(
14783        &mut self,
14784        _: &MoveToPreviousWordStart,
14785        window: &mut Window,
14786        cx: &mut Context<Self>,
14787    ) {
14788        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14789        self.change_selections(Default::default(), window, cx, |s| {
14790            s.move_cursors_with(&mut |map, head, _| {
14791                (
14792                    movement::previous_word_start(map, head),
14793                    SelectionGoal::None,
14794                )
14795            });
14796        })
14797    }
14798
14799    pub fn move_to_previous_subword_start(
14800        &mut self,
14801        _: &MoveToPreviousSubwordStart,
14802        window: &mut Window,
14803        cx: &mut Context<Self>,
14804    ) {
14805        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14806        self.change_selections(Default::default(), window, cx, |s| {
14807            s.move_cursors_with(&mut |map, head, _| {
14808                (
14809                    movement::previous_subword_start(map, head),
14810                    SelectionGoal::None,
14811                )
14812            });
14813        })
14814    }
14815
14816    pub fn select_to_previous_word_start(
14817        &mut self,
14818        _: &SelectToPreviousWordStart,
14819        window: &mut Window,
14820        cx: &mut Context<Self>,
14821    ) {
14822        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14823        self.change_selections(Default::default(), window, cx, |s| {
14824            s.move_heads_with(&mut |map, head, _| {
14825                (
14826                    movement::previous_word_start(map, head),
14827                    SelectionGoal::None,
14828                )
14829            });
14830        })
14831    }
14832
14833    pub fn select_to_previous_subword_start(
14834        &mut self,
14835        _: &SelectToPreviousSubwordStart,
14836        window: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) {
14839        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14840        self.change_selections(Default::default(), window, cx, |s| {
14841            s.move_heads_with(&mut |map, head, _| {
14842                (
14843                    movement::previous_subword_start(map, head),
14844                    SelectionGoal::None,
14845                )
14846            });
14847        })
14848    }
14849
14850    pub fn delete_to_previous_word_start(
14851        &mut self,
14852        action: &DeleteToPreviousWordStart,
14853        window: &mut Window,
14854        cx: &mut Context<Self>,
14855    ) {
14856        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14857        self.transact(window, cx, |this, window, cx| {
14858            this.select_autoclose_pair(window, cx);
14859            this.change_selections(Default::default(), window, cx, |s| {
14860                s.move_with(&mut |map, selection| {
14861                    if selection.is_empty() {
14862                        let mut cursor = if action.ignore_newlines {
14863                            movement::previous_word_start(map, selection.head())
14864                        } else {
14865                            movement::previous_word_start_or_newline(map, selection.head())
14866                        };
14867                        cursor = movement::adjust_greedy_deletion(
14868                            map,
14869                            selection.head(),
14870                            cursor,
14871                            action.ignore_brackets,
14872                        );
14873                        selection.set_head(cursor, SelectionGoal::None);
14874                    }
14875                });
14876            });
14877            this.insert("", window, cx);
14878        });
14879    }
14880
14881    pub fn delete_to_previous_subword_start(
14882        &mut self,
14883        action: &DeleteToPreviousSubwordStart,
14884        window: &mut Window,
14885        cx: &mut Context<Self>,
14886    ) {
14887        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14888        self.transact(window, cx, |this, window, cx| {
14889            this.select_autoclose_pair(window, cx);
14890            this.change_selections(Default::default(), window, cx, |s| {
14891                s.move_with(&mut |map, selection| {
14892                    if selection.is_empty() {
14893                        let mut cursor = if action.ignore_newlines {
14894                            movement::previous_subword_start(map, selection.head())
14895                        } else {
14896                            movement::previous_subword_start_or_newline(map, selection.head())
14897                        };
14898                        cursor = movement::adjust_greedy_deletion(
14899                            map,
14900                            selection.head(),
14901                            cursor,
14902                            action.ignore_brackets,
14903                        );
14904                        selection.set_head(cursor, SelectionGoal::None);
14905                    }
14906                });
14907            });
14908            this.insert("", window, cx);
14909        });
14910    }
14911
14912    pub fn move_to_next_word_end(
14913        &mut self,
14914        _: &MoveToNextWordEnd,
14915        window: &mut Window,
14916        cx: &mut Context<Self>,
14917    ) {
14918        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14919        self.change_selections(Default::default(), window, cx, |s| {
14920            s.move_cursors_with(&mut |map, head, _| {
14921                (movement::next_word_end(map, head), SelectionGoal::None)
14922            });
14923        })
14924    }
14925
14926    pub fn move_to_next_subword_end(
14927        &mut self,
14928        _: &MoveToNextSubwordEnd,
14929        window: &mut Window,
14930        cx: &mut Context<Self>,
14931    ) {
14932        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14933        self.change_selections(Default::default(), window, cx, |s| {
14934            s.move_cursors_with(&mut |map, head, _| {
14935                (movement::next_subword_end(map, head), SelectionGoal::None)
14936            });
14937        })
14938    }
14939
14940    pub fn select_to_next_word_end(
14941        &mut self,
14942        _: &SelectToNextWordEnd,
14943        window: &mut Window,
14944        cx: &mut Context<Self>,
14945    ) {
14946        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14947        self.change_selections(Default::default(), window, cx, |s| {
14948            s.move_heads_with(&mut |map, head, _| {
14949                (movement::next_word_end(map, head), SelectionGoal::None)
14950            });
14951        })
14952    }
14953
14954    pub fn select_to_next_subword_end(
14955        &mut self,
14956        _: &SelectToNextSubwordEnd,
14957        window: &mut Window,
14958        cx: &mut Context<Self>,
14959    ) {
14960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14961        self.change_selections(Default::default(), window, cx, |s| {
14962            s.move_heads_with(&mut |map, head, _| {
14963                (movement::next_subword_end(map, head), SelectionGoal::None)
14964            });
14965        })
14966    }
14967
14968    pub fn delete_to_next_word_end(
14969        &mut self,
14970        action: &DeleteToNextWordEnd,
14971        window: &mut Window,
14972        cx: &mut Context<Self>,
14973    ) {
14974        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14975        self.transact(window, cx, |this, window, cx| {
14976            this.change_selections(Default::default(), window, cx, |s| {
14977                s.move_with(&mut |map, selection| {
14978                    if selection.is_empty() {
14979                        let mut cursor = if action.ignore_newlines {
14980                            movement::next_word_end(map, selection.head())
14981                        } else {
14982                            movement::next_word_end_or_newline(map, selection.head())
14983                        };
14984                        cursor = movement::adjust_greedy_deletion(
14985                            map,
14986                            selection.head(),
14987                            cursor,
14988                            action.ignore_brackets,
14989                        );
14990                        selection.set_head(cursor, SelectionGoal::None);
14991                    }
14992                });
14993            });
14994            this.insert("", window, cx);
14995        });
14996    }
14997
14998    pub fn delete_to_next_subword_end(
14999        &mut self,
15000        action: &DeleteToNextSubwordEnd,
15001        window: &mut Window,
15002        cx: &mut Context<Self>,
15003    ) {
15004        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15005        self.transact(window, cx, |this, window, cx| {
15006            this.change_selections(Default::default(), window, cx, |s| {
15007                s.move_with(&mut |map, selection| {
15008                    if selection.is_empty() {
15009                        let mut cursor = if action.ignore_newlines {
15010                            movement::next_subword_end(map, selection.head())
15011                        } else {
15012                            movement::next_subword_end_or_newline(map, selection.head())
15013                        };
15014                        cursor = movement::adjust_greedy_deletion(
15015                            map,
15016                            selection.head(),
15017                            cursor,
15018                            action.ignore_brackets,
15019                        );
15020                        selection.set_head(cursor, SelectionGoal::None);
15021                    }
15022                });
15023            });
15024            this.insert("", window, cx);
15025        });
15026    }
15027
15028    pub fn move_to_beginning_of_line(
15029        &mut self,
15030        action: &MoveToBeginningOfLine,
15031        window: &mut Window,
15032        cx: &mut Context<Self>,
15033    ) {
15034        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15035        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15036        self.change_selections(Default::default(), window, cx, |s| {
15037            s.move_cursors_with(&mut |map, head, _| {
15038                (
15039                    movement::indented_line_beginning(
15040                        map,
15041                        head,
15042                        action.stop_at_soft_wraps,
15043                        stop_at_indent,
15044                    ),
15045                    SelectionGoal::None,
15046                )
15047            });
15048        })
15049    }
15050
15051    pub fn select_to_beginning_of_line(
15052        &mut self,
15053        action: &SelectToBeginningOfLine,
15054        window: &mut Window,
15055        cx: &mut Context<Self>,
15056    ) {
15057        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15058        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15059        self.change_selections(Default::default(), window, cx, |s| {
15060            s.move_heads_with(&mut |map, head, _| {
15061                (
15062                    movement::indented_line_beginning(
15063                        map,
15064                        head,
15065                        action.stop_at_soft_wraps,
15066                        stop_at_indent,
15067                    ),
15068                    SelectionGoal::None,
15069                )
15070            });
15071        });
15072    }
15073
15074    pub fn delete_to_beginning_of_line(
15075        &mut self,
15076        action: &DeleteToBeginningOfLine,
15077        window: &mut Window,
15078        cx: &mut Context<Self>,
15079    ) {
15080        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15081        self.transact(window, cx, |this, window, cx| {
15082            this.change_selections(Default::default(), window, cx, |s| {
15083                s.move_with(&mut |_, selection| {
15084                    selection.reversed = true;
15085                });
15086            });
15087
15088            this.select_to_beginning_of_line(
15089                &SelectToBeginningOfLine {
15090                    stop_at_soft_wraps: false,
15091                    stop_at_indent: action.stop_at_indent,
15092                },
15093                window,
15094                cx,
15095            );
15096            this.backspace(&Backspace, window, cx);
15097        });
15098    }
15099
15100    pub fn move_to_end_of_line(
15101        &mut self,
15102        action: &MoveToEndOfLine,
15103        window: &mut Window,
15104        cx: &mut Context<Self>,
15105    ) {
15106        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15107        self.change_selections(Default::default(), window, cx, |s| {
15108            s.move_cursors_with(&mut |map, head, _| {
15109                (
15110                    movement::line_end(map, head, action.stop_at_soft_wraps),
15111                    SelectionGoal::None,
15112                )
15113            });
15114        })
15115    }
15116
15117    pub fn select_to_end_of_line(
15118        &mut self,
15119        action: &SelectToEndOfLine,
15120        window: &mut Window,
15121        cx: &mut Context<Self>,
15122    ) {
15123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15124        self.change_selections(Default::default(), window, cx, |s| {
15125            s.move_heads_with(&mut |map, head, _| {
15126                (
15127                    movement::line_end(map, head, action.stop_at_soft_wraps),
15128                    SelectionGoal::None,
15129                )
15130            });
15131        })
15132    }
15133
15134    pub fn delete_to_end_of_line(
15135        &mut self,
15136        _: &DeleteToEndOfLine,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) {
15140        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15141        self.transact(window, cx, |this, window, cx| {
15142            this.select_to_end_of_line(
15143                &SelectToEndOfLine {
15144                    stop_at_soft_wraps: false,
15145                },
15146                window,
15147                cx,
15148            );
15149            this.delete(&Delete, window, cx);
15150        });
15151    }
15152
15153    pub fn cut_to_end_of_line(
15154        &mut self,
15155        action: &CutToEndOfLine,
15156        window: &mut Window,
15157        cx: &mut Context<Self>,
15158    ) {
15159        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15160        self.transact(window, cx, |this, window, cx| {
15161            this.select_to_end_of_line(
15162                &SelectToEndOfLine {
15163                    stop_at_soft_wraps: false,
15164                },
15165                window,
15166                cx,
15167            );
15168            if !action.stop_at_newlines {
15169                this.change_selections(Default::default(), window, cx, |s| {
15170                    s.move_with(&mut |_, sel| {
15171                        if sel.is_empty() {
15172                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15173                        }
15174                    });
15175                });
15176            }
15177            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15178            let item = this.cut_common(false, window, cx);
15179            cx.write_to_clipboard(item);
15180        });
15181    }
15182
15183    pub fn move_to_start_of_paragraph(
15184        &mut self,
15185        _: &MoveToStartOfParagraph,
15186        window: &mut Window,
15187        cx: &mut Context<Self>,
15188    ) {
15189        if matches!(self.mode, EditorMode::SingleLine) {
15190            cx.propagate();
15191            return;
15192        }
15193        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15194        self.change_selections(Default::default(), window, cx, |s| {
15195            s.move_with(&mut |map, selection| {
15196                selection.collapse_to(
15197                    movement::start_of_paragraph(map, selection.head(), 1),
15198                    SelectionGoal::None,
15199                )
15200            });
15201        })
15202    }
15203
15204    pub fn move_to_end_of_paragraph(
15205        &mut self,
15206        _: &MoveToEndOfParagraph,
15207        window: &mut Window,
15208        cx: &mut Context<Self>,
15209    ) {
15210        if matches!(self.mode, EditorMode::SingleLine) {
15211            cx.propagate();
15212            return;
15213        }
15214        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15215        self.change_selections(Default::default(), window, cx, |s| {
15216            s.move_with(&mut |map, selection| {
15217                selection.collapse_to(
15218                    movement::end_of_paragraph(map, selection.head(), 1),
15219                    SelectionGoal::None,
15220                )
15221            });
15222        })
15223    }
15224
15225    pub fn select_to_start_of_paragraph(
15226        &mut self,
15227        _: &SelectToStartOfParagraph,
15228        window: &mut Window,
15229        cx: &mut Context<Self>,
15230    ) {
15231        if matches!(self.mode, EditorMode::SingleLine) {
15232            cx.propagate();
15233            return;
15234        }
15235        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15236        self.change_selections(Default::default(), window, cx, |s| {
15237            s.move_heads_with(&mut |map, head, _| {
15238                (
15239                    movement::start_of_paragraph(map, head, 1),
15240                    SelectionGoal::None,
15241                )
15242            });
15243        })
15244    }
15245
15246    pub fn select_to_end_of_paragraph(
15247        &mut self,
15248        _: &SelectToEndOfParagraph,
15249        window: &mut Window,
15250        cx: &mut Context<Self>,
15251    ) {
15252        if matches!(self.mode, EditorMode::SingleLine) {
15253            cx.propagate();
15254            return;
15255        }
15256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15257        self.change_selections(Default::default(), window, cx, |s| {
15258            s.move_heads_with(&mut |map, head, _| {
15259                (
15260                    movement::end_of_paragraph(map, head, 1),
15261                    SelectionGoal::None,
15262                )
15263            });
15264        })
15265    }
15266
15267    pub fn move_to_start_of_excerpt(
15268        &mut self,
15269        _: &MoveToStartOfExcerpt,
15270        window: &mut Window,
15271        cx: &mut Context<Self>,
15272    ) {
15273        if matches!(self.mode, EditorMode::SingleLine) {
15274            cx.propagate();
15275            return;
15276        }
15277        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15278        self.change_selections(Default::default(), window, cx, |s| {
15279            s.move_with(&mut |map, selection| {
15280                selection.collapse_to(
15281                    movement::start_of_excerpt(
15282                        map,
15283                        selection.head(),
15284                        workspace::searchable::Direction::Prev,
15285                    ),
15286                    SelectionGoal::None,
15287                )
15288            });
15289        })
15290    }
15291
15292    pub fn move_to_start_of_next_excerpt(
15293        &mut self,
15294        _: &MoveToStartOfNextExcerpt,
15295        window: &mut Window,
15296        cx: &mut Context<Self>,
15297    ) {
15298        if matches!(self.mode, EditorMode::SingleLine) {
15299            cx.propagate();
15300            return;
15301        }
15302
15303        self.change_selections(Default::default(), window, cx, |s| {
15304            s.move_with(&mut |map, selection| {
15305                selection.collapse_to(
15306                    movement::start_of_excerpt(
15307                        map,
15308                        selection.head(),
15309                        workspace::searchable::Direction::Next,
15310                    ),
15311                    SelectionGoal::None,
15312                )
15313            });
15314        })
15315    }
15316
15317    pub fn move_to_end_of_excerpt(
15318        &mut self,
15319        _: &MoveToEndOfExcerpt,
15320        window: &mut Window,
15321        cx: &mut Context<Self>,
15322    ) {
15323        if matches!(self.mode, EditorMode::SingleLine) {
15324            cx.propagate();
15325            return;
15326        }
15327        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15328        self.change_selections(Default::default(), window, cx, |s| {
15329            s.move_with(&mut |map, selection| {
15330                selection.collapse_to(
15331                    movement::end_of_excerpt(
15332                        map,
15333                        selection.head(),
15334                        workspace::searchable::Direction::Next,
15335                    ),
15336                    SelectionGoal::None,
15337                )
15338            });
15339        })
15340    }
15341
15342    pub fn move_to_end_of_previous_excerpt(
15343        &mut self,
15344        _: &MoveToEndOfPreviousExcerpt,
15345        window: &mut Window,
15346        cx: &mut Context<Self>,
15347    ) {
15348        if matches!(self.mode, EditorMode::SingleLine) {
15349            cx.propagate();
15350            return;
15351        }
15352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15353        self.change_selections(Default::default(), window, cx, |s| {
15354            s.move_with(&mut |map, selection| {
15355                selection.collapse_to(
15356                    movement::end_of_excerpt(
15357                        map,
15358                        selection.head(),
15359                        workspace::searchable::Direction::Prev,
15360                    ),
15361                    SelectionGoal::None,
15362                )
15363            });
15364        })
15365    }
15366
15367    pub fn select_to_start_of_excerpt(
15368        &mut self,
15369        _: &SelectToStartOfExcerpt,
15370        window: &mut Window,
15371        cx: &mut Context<Self>,
15372    ) {
15373        if matches!(self.mode, EditorMode::SingleLine) {
15374            cx.propagate();
15375            return;
15376        }
15377        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15378        self.change_selections(Default::default(), window, cx, |s| {
15379            s.move_heads_with(&mut |map, head, _| {
15380                (
15381                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15382                    SelectionGoal::None,
15383                )
15384            });
15385        })
15386    }
15387
15388    pub fn select_to_start_of_next_excerpt(
15389        &mut self,
15390        _: &SelectToStartOfNextExcerpt,
15391        window: &mut Window,
15392        cx: &mut Context<Self>,
15393    ) {
15394        if matches!(self.mode, EditorMode::SingleLine) {
15395            cx.propagate();
15396            return;
15397        }
15398        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15399        self.change_selections(Default::default(), window, cx, |s| {
15400            s.move_heads_with(&mut |map, head, _| {
15401                (
15402                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15403                    SelectionGoal::None,
15404                )
15405            });
15406        })
15407    }
15408
15409    pub fn select_to_end_of_excerpt(
15410        &mut self,
15411        _: &SelectToEndOfExcerpt,
15412        window: &mut Window,
15413        cx: &mut Context<Self>,
15414    ) {
15415        if matches!(self.mode, EditorMode::SingleLine) {
15416            cx.propagate();
15417            return;
15418        }
15419        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15420        self.change_selections(Default::default(), window, cx, |s| {
15421            s.move_heads_with(&mut |map, head, _| {
15422                (
15423                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15424                    SelectionGoal::None,
15425                )
15426            });
15427        })
15428    }
15429
15430    pub fn select_to_end_of_previous_excerpt(
15431        &mut self,
15432        _: &SelectToEndOfPreviousExcerpt,
15433        window: &mut Window,
15434        cx: &mut Context<Self>,
15435    ) {
15436        if matches!(self.mode, EditorMode::SingleLine) {
15437            cx.propagate();
15438            return;
15439        }
15440        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15441        self.change_selections(Default::default(), window, cx, |s| {
15442            s.move_heads_with(&mut |map, head, _| {
15443                (
15444                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15445                    SelectionGoal::None,
15446                )
15447            });
15448        })
15449    }
15450
15451    pub fn move_to_beginning(
15452        &mut self,
15453        _: &MoveToBeginning,
15454        window: &mut Window,
15455        cx: &mut Context<Self>,
15456    ) {
15457        if matches!(self.mode, EditorMode::SingleLine) {
15458            cx.propagate();
15459            return;
15460        }
15461        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15462        self.change_selections(Default::default(), window, cx, |s| {
15463            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
15464        });
15465    }
15466
15467    pub fn select_to_beginning(
15468        &mut self,
15469        _: &SelectToBeginning,
15470        window: &mut Window,
15471        cx: &mut Context<Self>,
15472    ) {
15473        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15474        selection.set_head(Point::zero(), SelectionGoal::None);
15475        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15476        self.change_selections(Default::default(), window, cx, |s| {
15477            s.select(vec![selection]);
15478        });
15479    }
15480
15481    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15482        if matches!(self.mode, EditorMode::SingleLine) {
15483            cx.propagate();
15484            return;
15485        }
15486        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15487        let cursor = self.buffer.read(cx).read(cx).len();
15488        self.change_selections(Default::default(), window, cx, |s| {
15489            s.select_ranges(vec![cursor..cursor])
15490        });
15491    }
15492
15493    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15494        self.nav_history = nav_history;
15495    }
15496
15497    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15498        self.nav_history.as_ref()
15499    }
15500
15501    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15502        self.push_to_nav_history(
15503            self.selections.newest_anchor().head(),
15504            None,
15505            false,
15506            true,
15507            cx,
15508        );
15509    }
15510
15511    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15512        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15513        let buffer = self.buffer.read(cx).read(cx);
15514        let cursor_position = cursor_anchor.to_point(&buffer);
15515        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15516        let scroll_top_row = scroll_anchor.top_row(&buffer);
15517        drop(buffer);
15518
15519        NavigationData {
15520            cursor_anchor,
15521            cursor_position,
15522            scroll_anchor,
15523            scroll_top_row,
15524        }
15525    }
15526
15527    fn navigation_entry(
15528        &self,
15529        cursor_anchor: Anchor,
15530        cx: &mut Context<Self>,
15531    ) -> Option<NavigationEntry> {
15532        let Some(history) = self.nav_history.clone() else {
15533            return None;
15534        };
15535        let data = self.navigation_data(cursor_anchor, cx);
15536        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15537    }
15538
15539    fn push_to_nav_history(
15540        &mut self,
15541        cursor_anchor: Anchor,
15542        new_position: Option<Point>,
15543        is_deactivate: bool,
15544        always: bool,
15545        cx: &mut Context<Self>,
15546    ) {
15547        let data = self.navigation_data(cursor_anchor, cx);
15548        if let Some(nav_history) = self.nav_history.as_mut() {
15549            if let Some(new_position) = new_position {
15550                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15551                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15552                    return;
15553                }
15554            }
15555
15556            let cursor_row = data.cursor_position.row;
15557            nav_history.push(Some(data), Some(cursor_row), cx);
15558            cx.emit(EditorEvent::PushedToNavHistory {
15559                anchor: cursor_anchor,
15560                is_deactivate,
15561            })
15562        }
15563    }
15564
15565    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15566        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15567        let buffer = self.buffer.read(cx).snapshot(cx);
15568        let mut selection = self
15569            .selections
15570            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15571        selection.set_head(buffer.len(), SelectionGoal::None);
15572        self.change_selections(Default::default(), window, cx, |s| {
15573            s.select(vec![selection]);
15574        });
15575    }
15576
15577    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15578        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15579        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15580            s.select_ranges([Anchor::min()..Anchor::max()]);
15581        });
15582    }
15583
15584    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15585        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15586        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15587        let mut selections = self.selections.all::<Point>(&display_map);
15588        let max_point = display_map.buffer_snapshot().max_point();
15589        for selection in &mut selections {
15590            let rows = selection.spanned_rows(true, &display_map);
15591            selection.start = Point::new(rows.start.0, 0);
15592            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15593            selection.reversed = false;
15594        }
15595        self.change_selections(Default::default(), window, cx, |s| {
15596            s.select(selections);
15597        });
15598    }
15599
15600    pub fn split_selection_into_lines(
15601        &mut self,
15602        action: &SplitSelectionIntoLines,
15603        window: &mut Window,
15604        cx: &mut Context<Self>,
15605    ) {
15606        let selections = self
15607            .selections
15608            .all::<Point>(&self.display_snapshot(cx))
15609            .into_iter()
15610            .map(|selection| selection.start..selection.end)
15611            .collect::<Vec<_>>();
15612        self.unfold_ranges(&selections, true, false, cx);
15613
15614        let mut new_selection_ranges = Vec::new();
15615        {
15616            let buffer = self.buffer.read(cx).read(cx);
15617            for selection in selections {
15618                for row in selection.start.row..selection.end.row {
15619                    let line_start = Point::new(row, 0);
15620                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15621
15622                    if action.keep_selections {
15623                        // Keep the selection range for each line
15624                        let selection_start = if row == selection.start.row {
15625                            selection.start
15626                        } else {
15627                            line_start
15628                        };
15629                        new_selection_ranges.push(selection_start..line_end);
15630                    } else {
15631                        // Collapse to cursor at end of line
15632                        new_selection_ranges.push(line_end..line_end);
15633                    }
15634                }
15635
15636                let is_multiline_selection = selection.start.row != selection.end.row;
15637                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15638                // so this action feels more ergonomic when paired with other selection operations
15639                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15640                if !should_skip_last {
15641                    if action.keep_selections {
15642                        if is_multiline_selection {
15643                            let line_start = Point::new(selection.end.row, 0);
15644                            new_selection_ranges.push(line_start..selection.end);
15645                        } else {
15646                            new_selection_ranges.push(selection.start..selection.end);
15647                        }
15648                    } else {
15649                        new_selection_ranges.push(selection.end..selection.end);
15650                    }
15651                }
15652            }
15653        }
15654        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15655            s.select_ranges(new_selection_ranges);
15656        });
15657    }
15658
15659    pub fn add_selection_above(
15660        &mut self,
15661        action: &AddSelectionAbove,
15662        window: &mut Window,
15663        cx: &mut Context<Self>,
15664    ) {
15665        self.add_selection(true, action.skip_soft_wrap, window, cx);
15666    }
15667
15668    pub fn add_selection_below(
15669        &mut self,
15670        action: &AddSelectionBelow,
15671        window: &mut Window,
15672        cx: &mut Context<Self>,
15673    ) {
15674        self.add_selection(false, action.skip_soft_wrap, window, cx);
15675    }
15676
15677    fn add_selection(
15678        &mut self,
15679        above: bool,
15680        skip_soft_wrap: bool,
15681        window: &mut Window,
15682        cx: &mut Context<Self>,
15683    ) {
15684        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15685
15686        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15687        let all_selections = self.selections.all::<Point>(&display_map);
15688        let text_layout_details = self.text_layout_details(window, cx);
15689
15690        let (mut columnar_selections, new_selections_to_columnarize) = {
15691            if let Some(state) = self.add_selections_state.as_ref() {
15692                let columnar_selection_ids: HashSet<_> = state
15693                    .groups
15694                    .iter()
15695                    .flat_map(|group| group.stack.iter())
15696                    .copied()
15697                    .collect();
15698
15699                all_selections
15700                    .into_iter()
15701                    .partition(|s| columnar_selection_ids.contains(&s.id))
15702            } else {
15703                (Vec::new(), all_selections)
15704            }
15705        };
15706
15707        let mut state = self
15708            .add_selections_state
15709            .take()
15710            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15711
15712        for selection in new_selections_to_columnarize {
15713            let range = selection.display_range(&display_map).sorted();
15714            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15715            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15716            let positions = start_x.min(end_x)..start_x.max(end_x);
15717            let mut stack = Vec::new();
15718            for row in range.start.row().0..=range.end.row().0 {
15719                if let Some(selection) = self.selections.build_columnar_selection(
15720                    &display_map,
15721                    DisplayRow(row),
15722                    &positions,
15723                    selection.reversed,
15724                    &text_layout_details,
15725                ) {
15726                    stack.push(selection.id);
15727                    columnar_selections.push(selection);
15728                }
15729            }
15730            if !stack.is_empty() {
15731                if above {
15732                    stack.reverse();
15733                }
15734                state.groups.push(AddSelectionsGroup { above, stack });
15735            }
15736        }
15737
15738        let mut final_selections = Vec::new();
15739        let end_row = if above {
15740            DisplayRow(0)
15741        } else {
15742            display_map.max_point().row()
15743        };
15744
15745        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15746        // positions to place new selections, so we need to keep track of the
15747        // column range of the oldest selection in each group, because
15748        // intermediate selections may have been clamped to shorter lines.
15749        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15750            let mut map = HashMap::default();
15751            for group in state.groups.iter() {
15752                if let Some(oldest_id) = group.stack.first() {
15753                    if let Some(oldest_selection) =
15754                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15755                    {
15756                        let snapshot = display_map.buffer_snapshot();
15757                        let start_col =
15758                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15759                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15760                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15761                        for id in &group.stack {
15762                            map.insert(*id, goal_columns.clone());
15763                        }
15764                    }
15765                }
15766            }
15767            map
15768        } else {
15769            HashMap::default()
15770        };
15771
15772        let mut last_added_item_per_group = HashMap::default();
15773        for group in state.groups.iter_mut() {
15774            if let Some(last_id) = group.stack.last() {
15775                last_added_item_per_group.insert(*last_id, group);
15776            }
15777        }
15778
15779        for selection in columnar_selections {
15780            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15781                if above == group.above {
15782                    let range = selection.display_range(&display_map).sorted();
15783                    debug_assert_eq!(range.start.row(), range.end.row());
15784                    let row = range.start.row();
15785                    let positions =
15786                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15787                            Pixels::from(start)..Pixels::from(end)
15788                        } else {
15789                            let start_x =
15790                                display_map.x_for_display_point(range.start, &text_layout_details);
15791                            let end_x =
15792                                display_map.x_for_display_point(range.end, &text_layout_details);
15793                            start_x.min(end_x)..start_x.max(end_x)
15794                        };
15795
15796                    let maybe_new_selection = if skip_soft_wrap {
15797                        let goal_columns = goal_columns_by_selection_id
15798                            .remove(&selection.id)
15799                            .unwrap_or_else(|| {
15800                                let snapshot = display_map.buffer_snapshot();
15801                                let start_col =
15802                                    snapshot.point_to_point_utf16(selection.start).column;
15803                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15804                                start_col.min(end_col)..start_col.max(end_col)
15805                            });
15806                        self.selections.find_next_columnar_selection_by_buffer_row(
15807                            &display_map,
15808                            row,
15809                            end_row,
15810                            above,
15811                            &goal_columns,
15812                            selection.reversed,
15813                            &text_layout_details,
15814                        )
15815                    } else {
15816                        self.selections.find_next_columnar_selection_by_display_row(
15817                            &display_map,
15818                            row,
15819                            end_row,
15820                            above,
15821                            &positions,
15822                            selection.reversed,
15823                            &text_layout_details,
15824                        )
15825                    };
15826
15827                    if let Some(new_selection) = maybe_new_selection {
15828                        group.stack.push(new_selection.id);
15829                        if above {
15830                            final_selections.push(new_selection);
15831                            final_selections.push(selection);
15832                        } else {
15833                            final_selections.push(selection);
15834                            final_selections.push(new_selection);
15835                        }
15836                    } else {
15837                        final_selections.push(selection);
15838                    }
15839                } else {
15840                    group.stack.pop();
15841                }
15842            } else {
15843                final_selections.push(selection);
15844            }
15845        }
15846
15847        self.change_selections(Default::default(), window, cx, |s| {
15848            s.select(final_selections);
15849        });
15850
15851        let final_selection_ids: HashSet<_> = self
15852            .selections
15853            .all::<Point>(&display_map)
15854            .iter()
15855            .map(|s| s.id)
15856            .collect();
15857        state.groups.retain_mut(|group| {
15858            // selections might get merged above so we remove invalid items from stacks
15859            group.stack.retain(|id| final_selection_ids.contains(id));
15860
15861            // single selection in stack can be treated as initial state
15862            group.stack.len() > 1
15863        });
15864
15865        if !state.groups.is_empty() {
15866            self.add_selections_state = Some(state);
15867        }
15868    }
15869
15870    pub fn insert_snippet_at_selections(
15871        &mut self,
15872        action: &InsertSnippet,
15873        window: &mut Window,
15874        cx: &mut Context<Self>,
15875    ) {
15876        self.try_insert_snippet_at_selections(action, window, cx)
15877            .log_err();
15878    }
15879
15880    fn try_insert_snippet_at_selections(
15881        &mut self,
15882        action: &InsertSnippet,
15883        window: &mut Window,
15884        cx: &mut Context<Self>,
15885    ) -> Result<()> {
15886        let insertion_ranges = self
15887            .selections
15888            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15889            .into_iter()
15890            .map(|selection| selection.range())
15891            .collect_vec();
15892
15893        let snippet = if let Some(snippet_body) = &action.snippet {
15894            if action.language.is_none() && action.name.is_none() {
15895                Snippet::parse(snippet_body)?
15896            } else {
15897                bail!("`snippet` is mutually exclusive with `language` and `name`")
15898            }
15899        } else if let Some(name) = &action.name {
15900            let project = self.project().context("no project")?;
15901            let snippet_store = project.read(cx).snippets().read(cx);
15902            let snippet = snippet_store
15903                .snippets_for(action.language.clone(), cx)
15904                .into_iter()
15905                .find(|snippet| snippet.name == *name)
15906                .context("snippet not found")?;
15907            Snippet::parse(&snippet.body)?
15908        } else {
15909            // todo(andrew): open modal to select snippet
15910            bail!("`name` or `snippet` is required")
15911        };
15912
15913        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15914    }
15915
15916    fn select_match_ranges(
15917        &mut self,
15918        range: Range<MultiBufferOffset>,
15919        reversed: bool,
15920        replace_newest: bool,
15921        auto_scroll: Option<Autoscroll>,
15922        window: &mut Window,
15923        cx: &mut Context<Editor>,
15924    ) {
15925        self.unfold_ranges(
15926            std::slice::from_ref(&range),
15927            false,
15928            auto_scroll.is_some(),
15929            cx,
15930        );
15931        let effects = if let Some(scroll) = auto_scroll {
15932            SelectionEffects::scroll(scroll)
15933        } else {
15934            SelectionEffects::no_scroll()
15935        };
15936        self.change_selections(effects, window, cx, |s| {
15937            if replace_newest {
15938                s.delete(s.newest_anchor().id);
15939            }
15940            if reversed {
15941                s.insert_range(range.end..range.start);
15942            } else {
15943                s.insert_range(range);
15944            }
15945        });
15946    }
15947
15948    pub fn select_next_match_internal(
15949        &mut self,
15950        display_map: &DisplaySnapshot,
15951        replace_newest: bool,
15952        autoscroll: Option<Autoscroll>,
15953        window: &mut Window,
15954        cx: &mut Context<Self>,
15955    ) -> Result<()> {
15956        let buffer = display_map.buffer_snapshot();
15957        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15958        if let Some(mut select_next_state) = self.select_next_state.take() {
15959            let query = &select_next_state.query;
15960            if !select_next_state.done {
15961                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15962                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15963                let mut next_selected_range = None;
15964
15965                let bytes_after_last_selection =
15966                    buffer.bytes_in_range(last_selection.end..buffer.len());
15967                let bytes_before_first_selection =
15968                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15969                let query_matches = query
15970                    .stream_find_iter(bytes_after_last_selection)
15971                    .map(|result| (last_selection.end, result))
15972                    .chain(
15973                        query
15974                            .stream_find_iter(bytes_before_first_selection)
15975                            .map(|result| (MultiBufferOffset(0), result)),
15976                    );
15977
15978                for (start_offset, query_match) in query_matches {
15979                    let query_match = query_match.unwrap(); // can only fail due to I/O
15980                    let offset_range =
15981                        start_offset + query_match.start()..start_offset + query_match.end();
15982
15983                    if !select_next_state.wordwise
15984                        || (!buffer.is_inside_word(offset_range.start, None)
15985                            && !buffer.is_inside_word(offset_range.end, None))
15986                    {
15987                        let idx = selections
15988                            .partition_point(|selection| selection.end <= offset_range.start);
15989                        let overlaps = selections
15990                            .get(idx)
15991                            .map_or(false, |selection| selection.start < offset_range.end);
15992
15993                        if !overlaps {
15994                            next_selected_range = Some(offset_range);
15995                            break;
15996                        }
15997                    }
15998                }
15999
16000                if let Some(next_selected_range) = next_selected_range {
16001                    self.select_match_ranges(
16002                        next_selected_range,
16003                        last_selection.reversed,
16004                        replace_newest,
16005                        autoscroll,
16006                        window,
16007                        cx,
16008                    );
16009                } else {
16010                    select_next_state.done = true;
16011                }
16012            }
16013
16014            self.select_next_state = Some(select_next_state);
16015        } else {
16016            let mut only_carets = true;
16017            let mut same_text_selected = true;
16018            let mut selected_text = None;
16019
16020            let mut selections_iter = selections.iter().peekable();
16021            while let Some(selection) = selections_iter.next() {
16022                if selection.start != selection.end {
16023                    only_carets = false;
16024                }
16025
16026                if same_text_selected {
16027                    if selected_text.is_none() {
16028                        selected_text =
16029                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16030                    }
16031
16032                    if let Some(next_selection) = selections_iter.peek() {
16033                        if next_selection.len() == selection.len() {
16034                            let next_selected_text = buffer
16035                                .text_for_range(next_selection.range())
16036                                .collect::<String>();
16037                            if Some(next_selected_text) != selected_text {
16038                                same_text_selected = false;
16039                                selected_text = None;
16040                            }
16041                        } else {
16042                            same_text_selected = false;
16043                            selected_text = None;
16044                        }
16045                    }
16046                }
16047            }
16048
16049            if only_carets {
16050                for selection in &mut selections {
16051                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16052                    selection.start = word_range.start;
16053                    selection.end = word_range.end;
16054                    selection.goal = SelectionGoal::None;
16055                    selection.reversed = false;
16056                    self.select_match_ranges(
16057                        selection.start..selection.end,
16058                        selection.reversed,
16059                        replace_newest,
16060                        autoscroll,
16061                        window,
16062                        cx,
16063                    );
16064                }
16065
16066                if selections.len() == 1 {
16067                    let selection = selections
16068                        .last()
16069                        .expect("ensured that there's only one selection");
16070                    let query = buffer
16071                        .text_for_range(selection.start..selection.end)
16072                        .collect::<String>();
16073                    let is_empty = query.is_empty();
16074                    let select_state = SelectNextState {
16075                        query: self.build_query(&[query], cx)?,
16076                        wordwise: true,
16077                        done: is_empty,
16078                    };
16079                    self.select_next_state = Some(select_state);
16080                } else {
16081                    self.select_next_state = None;
16082                }
16083            } else if let Some(selected_text) = selected_text {
16084                self.select_next_state = Some(SelectNextState {
16085                    query: self.build_query(&[selected_text], cx)?,
16086                    wordwise: false,
16087                    done: false,
16088                });
16089                self.select_next_match_internal(
16090                    display_map,
16091                    replace_newest,
16092                    autoscroll,
16093                    window,
16094                    cx,
16095                )?;
16096            }
16097        }
16098        Ok(())
16099    }
16100
16101    pub fn select_all_matches(
16102        &mut self,
16103        _action: &SelectAllMatches,
16104        window: &mut Window,
16105        cx: &mut Context<Self>,
16106    ) -> Result<()> {
16107        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16108
16109        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16110
16111        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16112        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16113        else {
16114            return Ok(());
16115        };
16116
16117        let mut new_selections = Vec::new();
16118
16119        let reversed = self
16120            .selections
16121            .oldest::<MultiBufferOffset>(&display_map)
16122            .reversed;
16123        let buffer = display_map.buffer_snapshot();
16124        let query_matches = select_next_state
16125            .query
16126            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16127
16128        for query_match in query_matches.into_iter() {
16129            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16130            let offset_range = if reversed {
16131                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16132            } else {
16133                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16134            };
16135
16136            if !select_next_state.wordwise
16137                || (!buffer.is_inside_word(offset_range.start, None)
16138                    && !buffer.is_inside_word(offset_range.end, None))
16139            {
16140                new_selections.push(offset_range.start..offset_range.end);
16141            }
16142        }
16143
16144        select_next_state.done = true;
16145
16146        if new_selections.is_empty() {
16147            log::error!("bug: new_selections is empty in select_all_matches");
16148            return Ok(());
16149        }
16150
16151        self.unfold_ranges(&new_selections, false, false, cx);
16152        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16153            selections.select_ranges(new_selections)
16154        });
16155
16156        Ok(())
16157    }
16158
16159    pub fn select_next(
16160        &mut self,
16161        action: &SelectNext,
16162        window: &mut Window,
16163        cx: &mut Context<Self>,
16164    ) -> Result<()> {
16165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16166        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16167        self.select_next_match_internal(
16168            &display_map,
16169            action.replace_newest,
16170            Some(Autoscroll::newest()),
16171            window,
16172            cx,
16173        )
16174    }
16175
16176    pub fn select_previous(
16177        &mut self,
16178        action: &SelectPrevious,
16179        window: &mut Window,
16180        cx: &mut Context<Self>,
16181    ) -> Result<()> {
16182        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16183        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16184        let buffer = display_map.buffer_snapshot();
16185        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16186        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16187            let query = &select_prev_state.query;
16188            if !select_prev_state.done {
16189                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16190                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16191                let mut next_selected_range = None;
16192                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16193                let bytes_before_last_selection =
16194                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16195                let bytes_after_first_selection =
16196                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16197                let query_matches = query
16198                    .stream_find_iter(bytes_before_last_selection)
16199                    .map(|result| (last_selection.start, result))
16200                    .chain(
16201                        query
16202                            .stream_find_iter(bytes_after_first_selection)
16203                            .map(|result| (buffer.len(), result)),
16204                    );
16205                for (end_offset, query_match) in query_matches {
16206                    let query_match = query_match.unwrap(); // can only fail due to I/O
16207                    let offset_range =
16208                        end_offset - query_match.end()..end_offset - query_match.start();
16209
16210                    if !select_prev_state.wordwise
16211                        || (!buffer.is_inside_word(offset_range.start, None)
16212                            && !buffer.is_inside_word(offset_range.end, None))
16213                    {
16214                        next_selected_range = Some(offset_range);
16215                        break;
16216                    }
16217                }
16218
16219                if let Some(next_selected_range) = next_selected_range {
16220                    self.select_match_ranges(
16221                        next_selected_range,
16222                        last_selection.reversed,
16223                        action.replace_newest,
16224                        Some(Autoscroll::newest()),
16225                        window,
16226                        cx,
16227                    );
16228                } else {
16229                    select_prev_state.done = true;
16230                }
16231            }
16232
16233            self.select_prev_state = Some(select_prev_state);
16234        } else {
16235            let mut only_carets = true;
16236            let mut same_text_selected = true;
16237            let mut selected_text = None;
16238
16239            let mut selections_iter = selections.iter().peekable();
16240            while let Some(selection) = selections_iter.next() {
16241                if selection.start != selection.end {
16242                    only_carets = false;
16243                }
16244
16245                if same_text_selected {
16246                    if selected_text.is_none() {
16247                        selected_text =
16248                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16249                    }
16250
16251                    if let Some(next_selection) = selections_iter.peek() {
16252                        if next_selection.len() == selection.len() {
16253                            let next_selected_text = buffer
16254                                .text_for_range(next_selection.range())
16255                                .collect::<String>();
16256                            if Some(next_selected_text) != selected_text {
16257                                same_text_selected = false;
16258                                selected_text = None;
16259                            }
16260                        } else {
16261                            same_text_selected = false;
16262                            selected_text = None;
16263                        }
16264                    }
16265                }
16266            }
16267
16268            if only_carets {
16269                for selection in &mut selections {
16270                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16271                    selection.start = word_range.start;
16272                    selection.end = word_range.end;
16273                    selection.goal = SelectionGoal::None;
16274                    selection.reversed = false;
16275                    self.select_match_ranges(
16276                        selection.start..selection.end,
16277                        selection.reversed,
16278                        action.replace_newest,
16279                        Some(Autoscroll::newest()),
16280                        window,
16281                        cx,
16282                    );
16283                }
16284                if selections.len() == 1 {
16285                    let selection = selections
16286                        .last()
16287                        .expect("ensured that there's only one selection");
16288                    let query = buffer
16289                        .text_for_range(selection.start..selection.end)
16290                        .collect::<String>();
16291                    let is_empty = query.is_empty();
16292                    let select_state = SelectNextState {
16293                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16294                        wordwise: true,
16295                        done: is_empty,
16296                    };
16297                    self.select_prev_state = Some(select_state);
16298                } else {
16299                    self.select_prev_state = None;
16300                }
16301            } else if let Some(selected_text) = selected_text {
16302                self.select_prev_state = Some(SelectNextState {
16303                    query: self
16304                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16305                    wordwise: false,
16306                    done: false,
16307                });
16308                self.select_previous(action, window, cx)?;
16309            }
16310        }
16311        Ok(())
16312    }
16313
16314    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16315    /// setting the case sensitivity based on the global
16316    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16317    /// editor's settings.
16318    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16319    where
16320        I: IntoIterator<Item = P>,
16321        P: AsRef<[u8]>,
16322    {
16323        let case_sensitive = self
16324            .select_next_is_case_sensitive
16325            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16326
16327        let mut builder = AhoCorasickBuilder::new();
16328        builder.ascii_case_insensitive(!case_sensitive);
16329        builder.build(patterns)
16330    }
16331
16332    pub fn find_next_match(
16333        &mut self,
16334        _: &FindNextMatch,
16335        window: &mut Window,
16336        cx: &mut Context<Self>,
16337    ) -> Result<()> {
16338        let selections = self.selections.disjoint_anchors_arc();
16339        match selections.first() {
16340            Some(first) if selections.len() >= 2 => {
16341                self.change_selections(Default::default(), window, cx, |s| {
16342                    s.select_ranges([first.range()]);
16343                });
16344            }
16345            _ => self.select_next(
16346                &SelectNext {
16347                    replace_newest: true,
16348                },
16349                window,
16350                cx,
16351            )?,
16352        }
16353        Ok(())
16354    }
16355
16356    pub fn find_previous_match(
16357        &mut self,
16358        _: &FindPreviousMatch,
16359        window: &mut Window,
16360        cx: &mut Context<Self>,
16361    ) -> Result<()> {
16362        let selections = self.selections.disjoint_anchors_arc();
16363        match selections.last() {
16364            Some(last) if selections.len() >= 2 => {
16365                self.change_selections(Default::default(), window, cx, |s| {
16366                    s.select_ranges([last.range()]);
16367                });
16368            }
16369            _ => self.select_previous(
16370                &SelectPrevious {
16371                    replace_newest: true,
16372                },
16373                window,
16374                cx,
16375            )?,
16376        }
16377        Ok(())
16378    }
16379
16380    pub fn toggle_comments(
16381        &mut self,
16382        action: &ToggleComments,
16383        window: &mut Window,
16384        cx: &mut Context<Self>,
16385    ) {
16386        if self.read_only(cx) {
16387            return;
16388        }
16389        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16390        let text_layout_details = &self.text_layout_details(window, cx);
16391        self.transact(window, cx, |this, window, cx| {
16392            let mut selections = this
16393                .selections
16394                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16395            let mut edits = Vec::new();
16396            let mut selection_edit_ranges = Vec::new();
16397            let mut last_toggled_row = None;
16398            let snapshot = this.buffer.read(cx).read(cx);
16399            let empty_str: Arc<str> = Arc::default();
16400            let mut suffixes_inserted = Vec::new();
16401            let ignore_indent = action.ignore_indent;
16402
16403            fn comment_prefix_range(
16404                snapshot: &MultiBufferSnapshot,
16405                row: MultiBufferRow,
16406                comment_prefix: &str,
16407                comment_prefix_whitespace: &str,
16408                ignore_indent: bool,
16409            ) -> Range<Point> {
16410                let indent_size = if ignore_indent {
16411                    0
16412                } else {
16413                    snapshot.indent_size_for_line(row).len
16414                };
16415
16416                let start = Point::new(row.0, indent_size);
16417
16418                let mut line_bytes = snapshot
16419                    .bytes_in_range(start..snapshot.max_point())
16420                    .flatten()
16421                    .copied();
16422
16423                // If this line currently begins with the line comment prefix, then record
16424                // the range containing the prefix.
16425                if line_bytes
16426                    .by_ref()
16427                    .take(comment_prefix.len())
16428                    .eq(comment_prefix.bytes())
16429                {
16430                    // Include any whitespace that matches the comment prefix.
16431                    let matching_whitespace_len = line_bytes
16432                        .zip(comment_prefix_whitespace.bytes())
16433                        .take_while(|(a, b)| a == b)
16434                        .count() as u32;
16435                    let end = Point::new(
16436                        start.row,
16437                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16438                    );
16439                    start..end
16440                } else {
16441                    start..start
16442                }
16443            }
16444
16445            fn comment_suffix_range(
16446                snapshot: &MultiBufferSnapshot,
16447                row: MultiBufferRow,
16448                comment_suffix: &str,
16449                comment_suffix_has_leading_space: bool,
16450            ) -> Range<Point> {
16451                let end = Point::new(row.0, snapshot.line_len(row));
16452                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16453
16454                let mut line_end_bytes = snapshot
16455                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16456                    .flatten()
16457                    .copied();
16458
16459                let leading_space_len = if suffix_start_column > 0
16460                    && line_end_bytes.next() == Some(b' ')
16461                    && comment_suffix_has_leading_space
16462                {
16463                    1
16464                } else {
16465                    0
16466                };
16467
16468                // If this line currently begins with the line comment prefix, then record
16469                // the range containing the prefix.
16470                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16471                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16472                    start..end
16473                } else {
16474                    end..end
16475                }
16476            }
16477
16478            // TODO: Handle selections that cross excerpts
16479            for selection in &mut selections {
16480                let start_column = snapshot
16481                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16482                    .len;
16483                let language = if let Some(language) =
16484                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16485                {
16486                    language
16487                } else {
16488                    continue;
16489                };
16490
16491                selection_edit_ranges.clear();
16492
16493                // If multiple selections contain a given row, avoid processing that
16494                // row more than once.
16495                let mut start_row = MultiBufferRow(selection.start.row);
16496                if last_toggled_row == Some(start_row) {
16497                    start_row = start_row.next_row();
16498                }
16499                let end_row =
16500                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16501                        MultiBufferRow(selection.end.row - 1)
16502                    } else {
16503                        MultiBufferRow(selection.end.row)
16504                    };
16505                last_toggled_row = Some(end_row);
16506
16507                if start_row > end_row {
16508                    continue;
16509                }
16510
16511                // If the language has line comments, toggle those.
16512                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16513
16514                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16515                if ignore_indent {
16516                    full_comment_prefixes = full_comment_prefixes
16517                        .into_iter()
16518                        .map(|s| Arc::from(s.trim_end()))
16519                        .collect();
16520                }
16521
16522                if !full_comment_prefixes.is_empty() {
16523                    let first_prefix = full_comment_prefixes
16524                        .first()
16525                        .expect("prefixes is non-empty");
16526                    let prefix_trimmed_lengths = full_comment_prefixes
16527                        .iter()
16528                        .map(|p| p.trim_end_matches(' ').len())
16529                        .collect::<SmallVec<[usize; 4]>>();
16530
16531                    let mut all_selection_lines_are_comments = true;
16532
16533                    for row in start_row.0..=end_row.0 {
16534                        let row = MultiBufferRow(row);
16535                        if start_row < end_row && snapshot.is_line_blank(row) {
16536                            continue;
16537                        }
16538
16539                        let prefix_range = full_comment_prefixes
16540                            .iter()
16541                            .zip(prefix_trimmed_lengths.iter().copied())
16542                            .map(|(prefix, trimmed_prefix_len)| {
16543                                comment_prefix_range(
16544                                    snapshot.deref(),
16545                                    row,
16546                                    &prefix[..trimmed_prefix_len],
16547                                    &prefix[trimmed_prefix_len..],
16548                                    ignore_indent,
16549                                )
16550                            })
16551                            .max_by_key(|range| range.end.column - range.start.column)
16552                            .expect("prefixes is non-empty");
16553
16554                        if prefix_range.is_empty() {
16555                            all_selection_lines_are_comments = false;
16556                        }
16557
16558                        selection_edit_ranges.push(prefix_range);
16559                    }
16560
16561                    if all_selection_lines_are_comments {
16562                        edits.extend(
16563                            selection_edit_ranges
16564                                .iter()
16565                                .cloned()
16566                                .map(|range| (range, empty_str.clone())),
16567                        );
16568                    } else {
16569                        let min_column = selection_edit_ranges
16570                            .iter()
16571                            .map(|range| range.start.column)
16572                            .min()
16573                            .unwrap_or(0);
16574                        edits.extend(selection_edit_ranges.iter().map(|range| {
16575                            let position = Point::new(range.start.row, min_column);
16576                            (position..position, first_prefix.clone())
16577                        }));
16578                    }
16579                } else if let Some(BlockCommentConfig {
16580                    start: full_comment_prefix,
16581                    end: comment_suffix,
16582                    ..
16583                }) = language.block_comment()
16584                {
16585                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16586                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16587                    let prefix_range = comment_prefix_range(
16588                        snapshot.deref(),
16589                        start_row,
16590                        comment_prefix,
16591                        comment_prefix_whitespace,
16592                        ignore_indent,
16593                    );
16594                    let suffix_range = comment_suffix_range(
16595                        snapshot.deref(),
16596                        end_row,
16597                        comment_suffix.trim_start_matches(' '),
16598                        comment_suffix.starts_with(' '),
16599                    );
16600
16601                    if prefix_range.is_empty() || suffix_range.is_empty() {
16602                        edits.push((
16603                            prefix_range.start..prefix_range.start,
16604                            full_comment_prefix.clone(),
16605                        ));
16606                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16607                        suffixes_inserted.push((end_row, comment_suffix.len()));
16608                    } else {
16609                        edits.push((prefix_range, empty_str.clone()));
16610                        edits.push((suffix_range, empty_str.clone()));
16611                    }
16612                } else {
16613                    continue;
16614                }
16615            }
16616
16617            drop(snapshot);
16618            this.buffer.update(cx, |buffer, cx| {
16619                buffer.edit(edits, None, cx);
16620            });
16621
16622            // Adjust selections so that they end before any comment suffixes that
16623            // were inserted.
16624            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16625            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16626            let snapshot = this.buffer.read(cx).read(cx);
16627            for selection in &mut selections {
16628                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16629                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16630                        Ordering::Less => {
16631                            suffixes_inserted.next();
16632                            continue;
16633                        }
16634                        Ordering::Greater => break,
16635                        Ordering::Equal => {
16636                            if selection.end.column == snapshot.line_len(row) {
16637                                if selection.is_empty() {
16638                                    selection.start.column -= suffix_len as u32;
16639                                }
16640                                selection.end.column -= suffix_len as u32;
16641                            }
16642                            break;
16643                        }
16644                    }
16645                }
16646            }
16647
16648            drop(snapshot);
16649            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16650
16651            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16652            let selections_on_single_row = selections.windows(2).all(|selections| {
16653                selections[0].start.row == selections[1].start.row
16654                    && selections[0].end.row == selections[1].end.row
16655                    && selections[0].start.row == selections[0].end.row
16656            });
16657            let selections_selecting = selections
16658                .iter()
16659                .any(|selection| selection.start != selection.end);
16660            let advance_downwards = action.advance_downwards
16661                && selections_on_single_row
16662                && !selections_selecting
16663                && !matches!(this.mode, EditorMode::SingleLine);
16664
16665            if advance_downwards {
16666                let snapshot = this.buffer.read(cx).snapshot(cx);
16667
16668                this.change_selections(Default::default(), window, cx, |s| {
16669                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16670                        let mut point = display_point.to_point(display_snapshot);
16671                        point.row += 1;
16672                        point = snapshot.clip_point(point, Bias::Left);
16673                        let display_point = point.to_display_point(display_snapshot);
16674                        let goal = SelectionGoal::HorizontalPosition(
16675                            display_snapshot
16676                                .x_for_display_point(display_point, text_layout_details)
16677                                .into(),
16678                        );
16679                        (display_point, goal)
16680                    })
16681                });
16682            }
16683        });
16684    }
16685
16686    pub fn select_enclosing_symbol(
16687        &mut self,
16688        _: &SelectEnclosingSymbol,
16689        window: &mut Window,
16690        cx: &mut Context<Self>,
16691    ) {
16692        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16693
16694        let buffer = self.buffer.read(cx).snapshot(cx);
16695        let old_selections = self
16696            .selections
16697            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16698            .into_boxed_slice();
16699
16700        fn update_selection(
16701            selection: &Selection<MultiBufferOffset>,
16702            buffer_snap: &MultiBufferSnapshot,
16703        ) -> Option<Selection<MultiBufferOffset>> {
16704            let cursor = selection.head();
16705            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16706            for symbol in symbols.iter().rev() {
16707                let start = symbol.range.start.to_offset(buffer_snap);
16708                let end = symbol.range.end.to_offset(buffer_snap);
16709                let new_range = start..end;
16710                if start < selection.start || end > selection.end {
16711                    return Some(Selection {
16712                        id: selection.id,
16713                        start: new_range.start,
16714                        end: new_range.end,
16715                        goal: SelectionGoal::None,
16716                        reversed: selection.reversed,
16717                    });
16718                }
16719            }
16720            None
16721        }
16722
16723        let mut selected_larger_symbol = false;
16724        let new_selections = old_selections
16725            .iter()
16726            .map(|selection| match update_selection(selection, &buffer) {
16727                Some(new_selection) => {
16728                    if new_selection.range() != selection.range() {
16729                        selected_larger_symbol = true;
16730                    }
16731                    new_selection
16732                }
16733                None => selection.clone(),
16734            })
16735            .collect::<Vec<_>>();
16736
16737        if selected_larger_symbol {
16738            self.change_selections(Default::default(), window, cx, |s| {
16739                s.select(new_selections);
16740            });
16741        }
16742    }
16743
16744    pub fn select_larger_syntax_node(
16745        &mut self,
16746        _: &SelectLargerSyntaxNode,
16747        window: &mut Window,
16748        cx: &mut Context<Self>,
16749    ) {
16750        let Some(visible_row_count) = self.visible_row_count() else {
16751            return;
16752        };
16753        let old_selections: Box<[_]> = self
16754            .selections
16755            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16756            .into();
16757        if old_selections.is_empty() {
16758            return;
16759        }
16760
16761        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16762
16763        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16764        let buffer = self.buffer.read(cx).snapshot(cx);
16765
16766        let mut selected_larger_node = false;
16767        let mut new_selections = old_selections
16768            .iter()
16769            .map(|selection| {
16770                let old_range = selection.start..selection.end;
16771
16772                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16773                    // manually select word at selection
16774                    if ["string_content", "inline"].contains(&node.kind()) {
16775                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16776                        // ignore if word is already selected
16777                        if !word_range.is_empty() && old_range != word_range {
16778                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16779                            // only select word if start and end point belongs to same word
16780                            if word_range == last_word_range {
16781                                selected_larger_node = true;
16782                                return Selection {
16783                                    id: selection.id,
16784                                    start: word_range.start,
16785                                    end: word_range.end,
16786                                    goal: SelectionGoal::None,
16787                                    reversed: selection.reversed,
16788                                };
16789                            }
16790                        }
16791                    }
16792                }
16793
16794                let mut new_range = old_range.clone();
16795                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16796                    new_range = range;
16797                    if !node.is_named() {
16798                        continue;
16799                    }
16800                    if !display_map.intersects_fold(new_range.start)
16801                        && !display_map.intersects_fold(new_range.end)
16802                    {
16803                        break;
16804                    }
16805                }
16806
16807                selected_larger_node |= new_range != old_range;
16808                Selection {
16809                    id: selection.id,
16810                    start: new_range.start,
16811                    end: new_range.end,
16812                    goal: SelectionGoal::None,
16813                    reversed: selection.reversed,
16814                }
16815            })
16816            .collect::<Vec<_>>();
16817
16818        if !selected_larger_node {
16819            return; // don't put this call in the history
16820        }
16821
16822        // scroll based on transformation done to the last selection created by the user
16823        let (last_old, last_new) = old_selections
16824            .last()
16825            .zip(new_selections.last().cloned())
16826            .expect("old_selections isn't empty");
16827
16828        let is_selection_reversed = if new_selections.len() == 1 {
16829            let should_be_reversed = last_old.start != last_new.start;
16830            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
16831            should_be_reversed
16832        } else {
16833            last_new.reversed
16834        };
16835
16836        if selected_larger_node {
16837            self.select_syntax_node_history.disable_clearing = true;
16838            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16839                s.select(new_selections.clone());
16840            });
16841            self.select_syntax_node_history.disable_clearing = false;
16842        }
16843
16844        let start_row = last_new.start.to_display_point(&display_map).row().0;
16845        let end_row = last_new.end.to_display_point(&display_map).row().0;
16846        let selection_height = end_row - start_row + 1;
16847        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16848
16849        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16850        let scroll_behavior = if fits_on_the_screen {
16851            self.request_autoscroll(Autoscroll::fit(), cx);
16852            SelectSyntaxNodeScrollBehavior::FitSelection
16853        } else if is_selection_reversed {
16854            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16855            SelectSyntaxNodeScrollBehavior::CursorTop
16856        } else {
16857            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16858            SelectSyntaxNodeScrollBehavior::CursorBottom
16859        };
16860
16861        let old_selections: Box<[Selection<Anchor>]> = old_selections
16862            .iter()
16863            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16864            .collect();
16865        self.select_syntax_node_history.push((
16866            old_selections,
16867            scroll_behavior,
16868            is_selection_reversed,
16869        ));
16870    }
16871
16872    pub fn select_smaller_syntax_node(
16873        &mut self,
16874        _: &SelectSmallerSyntaxNode,
16875        window: &mut Window,
16876        cx: &mut Context<Self>,
16877    ) {
16878        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16879
16880        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16881            self.select_syntax_node_history.pop()
16882        {
16883            if let Some(selection) = selections.last_mut() {
16884                selection.reversed = is_selection_reversed;
16885            }
16886
16887            let snapshot = self.buffer.read(cx).snapshot(cx);
16888            let selections: Vec<Selection<MultiBufferOffset>> = selections
16889                .iter()
16890                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16891                .collect();
16892
16893            self.select_syntax_node_history.disable_clearing = true;
16894            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16895                s.select(selections);
16896            });
16897            self.select_syntax_node_history.disable_clearing = false;
16898
16899            match scroll_behavior {
16900                SelectSyntaxNodeScrollBehavior::CursorTop => {
16901                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16902                }
16903                SelectSyntaxNodeScrollBehavior::FitSelection => {
16904                    self.request_autoscroll(Autoscroll::fit(), cx);
16905                }
16906                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16907                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16908                }
16909            }
16910        }
16911    }
16912
16913    pub fn unwrap_syntax_node(
16914        &mut self,
16915        _: &UnwrapSyntaxNode,
16916        window: &mut Window,
16917        cx: &mut Context<Self>,
16918    ) {
16919        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16920
16921        let buffer = self.buffer.read(cx).snapshot(cx);
16922        let selections = self
16923            .selections
16924            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16925            .into_iter()
16926            // subtracting the offset requires sorting
16927            .sorted_by_key(|i| i.start);
16928
16929        let full_edits = selections
16930            .into_iter()
16931            .filter_map(|selection| {
16932                let child = if selection.is_empty()
16933                    && let Some((_, ancestor_range)) =
16934                        buffer.syntax_ancestor(selection.start..selection.end)
16935                {
16936                    ancestor_range
16937                } else {
16938                    selection.range()
16939                };
16940
16941                let mut parent = child.clone();
16942                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16943                    parent = ancestor_range;
16944                    if parent.start < child.start || parent.end > child.end {
16945                        break;
16946                    }
16947                }
16948
16949                if parent == child {
16950                    return None;
16951                }
16952                let text = buffer.text_for_range(child).collect::<String>();
16953                Some((selection.id, parent, text))
16954            })
16955            .collect::<Vec<_>>();
16956        if full_edits.is_empty() {
16957            return;
16958        }
16959
16960        self.transact(window, cx, |this, window, cx| {
16961            this.buffer.update(cx, |buffer, cx| {
16962                buffer.edit(
16963                    full_edits
16964                        .iter()
16965                        .map(|(_, p, t)| (p.clone(), t.clone()))
16966                        .collect::<Vec<_>>(),
16967                    None,
16968                    cx,
16969                );
16970            });
16971            this.change_selections(Default::default(), window, cx, |s| {
16972                let mut offset = 0;
16973                let mut selections = vec![];
16974                for (id, parent, text) in full_edits {
16975                    let start = parent.start - offset;
16976                    offset += (parent.end - parent.start) - text.len();
16977                    selections.push(Selection {
16978                        id,
16979                        start,
16980                        end: start + text.len(),
16981                        reversed: false,
16982                        goal: Default::default(),
16983                    });
16984                }
16985                s.select(selections);
16986            });
16987        });
16988    }
16989
16990    pub fn select_next_syntax_node(
16991        &mut self,
16992        _: &SelectNextSyntaxNode,
16993        window: &mut Window,
16994        cx: &mut Context<Self>,
16995    ) {
16996        let old_selections: Box<[_]> = self
16997            .selections
16998            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16999            .into();
17000        if old_selections.is_empty() {
17001            return;
17002        }
17003
17004        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17005
17006        let buffer = self.buffer.read(cx).snapshot(cx);
17007        let mut selected_sibling = false;
17008
17009        let new_selections = old_selections
17010            .iter()
17011            .map(|selection| {
17012                let old_range = selection.start..selection.end;
17013
17014                let old_range =
17015                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
17016                let excerpt = buffer.excerpt_containing(old_range.clone());
17017
17018                if let Some(mut excerpt) = excerpt
17019                    && let Some(node) = excerpt
17020                        .buffer()
17021                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
17022                {
17023                    let new_range = excerpt.map_range_from_buffer(
17024                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
17025                    );
17026                    selected_sibling = true;
17027                    Selection {
17028                        id: selection.id,
17029                        start: new_range.start,
17030                        end: new_range.end,
17031                        goal: SelectionGoal::None,
17032                        reversed: selection.reversed,
17033                    }
17034                } else {
17035                    selection.clone()
17036                }
17037            })
17038            .collect::<Vec<_>>();
17039
17040        if selected_sibling {
17041            self.change_selections(
17042                SelectionEffects::scroll(Autoscroll::fit()),
17043                window,
17044                cx,
17045                |s| {
17046                    s.select(new_selections);
17047                },
17048            );
17049        }
17050    }
17051
17052    pub fn select_prev_syntax_node(
17053        &mut self,
17054        _: &SelectPreviousSyntaxNode,
17055        window: &mut Window,
17056        cx: &mut Context<Self>,
17057    ) {
17058        let old_selections: Box<[_]> = self
17059            .selections
17060            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17061            .into();
17062        if old_selections.is_empty() {
17063            return;
17064        }
17065
17066        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17067
17068        let buffer = self.buffer.read(cx).snapshot(cx);
17069        let mut selected_sibling = false;
17070
17071        let new_selections = old_selections
17072            .iter()
17073            .map(|selection| {
17074                let old_range = selection.start..selection.end;
17075                let old_range =
17076                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
17077                let excerpt = buffer.excerpt_containing(old_range.clone());
17078
17079                if let Some(mut excerpt) = excerpt
17080                    && let Some(node) = excerpt
17081                        .buffer()
17082                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
17083                {
17084                    let new_range = excerpt.map_range_from_buffer(
17085                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
17086                    );
17087                    selected_sibling = true;
17088                    Selection {
17089                        id: selection.id,
17090                        start: new_range.start,
17091                        end: new_range.end,
17092                        goal: SelectionGoal::None,
17093                        reversed: selection.reversed,
17094                    }
17095                } else {
17096                    selection.clone()
17097                }
17098            })
17099            .collect::<Vec<_>>();
17100
17101        if selected_sibling {
17102            self.change_selections(
17103                SelectionEffects::scroll(Autoscroll::fit()),
17104                window,
17105                cx,
17106                |s| {
17107                    s.select(new_selections);
17108                },
17109            );
17110        }
17111    }
17112
17113    pub fn move_to_start_of_larger_syntax_node(
17114        &mut self,
17115        _: &MoveToStartOfLargerSyntaxNode,
17116        window: &mut Window,
17117        cx: &mut Context<Self>,
17118    ) {
17119        self.move_cursors_to_syntax_nodes(window, cx, false);
17120    }
17121
17122    pub fn move_to_end_of_larger_syntax_node(
17123        &mut self,
17124        _: &MoveToEndOfLargerSyntaxNode,
17125        window: &mut Window,
17126        cx: &mut Context<Self>,
17127    ) {
17128        self.move_cursors_to_syntax_nodes(window, cx, true);
17129    }
17130
17131    fn find_syntax_node_boundary(
17132        &self,
17133        selection_pos: MultiBufferOffset,
17134        move_to_end: bool,
17135        display_map: &DisplaySnapshot,
17136        buffer: &MultiBufferSnapshot,
17137    ) -> MultiBufferOffset {
17138        let old_range = selection_pos..selection_pos;
17139        let mut new_pos = selection_pos;
17140        let mut search_range = old_range;
17141        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17142            search_range = range.clone();
17143            if !node.is_named()
17144                || display_map.intersects_fold(range.start)
17145                || display_map.intersects_fold(range.end)
17146                // If cursor is already at the end of the syntax node, continue searching
17147                || (move_to_end && range.end == selection_pos)
17148                // If cursor is already at the start of the syntax node, continue searching
17149                || (!move_to_end && range.start == selection_pos)
17150            {
17151                continue;
17152            }
17153
17154            // If we found a string_content node, find the largest parent that is still string_content
17155            // Enables us to skip to the end of strings without taking multiple steps inside the string
17156            let (_, final_range) = if node.kind() == "string_content" {
17157                let mut current_node = node;
17158                let mut current_range = range;
17159                while let Some((parent, parent_range)) =
17160                    buffer.syntax_ancestor(current_range.clone())
17161                {
17162                    if parent.kind() == "string_content" {
17163                        current_node = parent;
17164                        current_range = parent_range;
17165                    } else {
17166                        break;
17167                    }
17168                }
17169
17170                (current_node, current_range)
17171            } else {
17172                (node, range)
17173            };
17174
17175            new_pos = if move_to_end {
17176                final_range.end
17177            } else {
17178                final_range.start
17179            };
17180
17181            break;
17182        }
17183
17184        new_pos
17185    }
17186
17187    fn move_cursors_to_syntax_nodes(
17188        &mut self,
17189        window: &mut Window,
17190        cx: &mut Context<Self>,
17191        move_to_end: bool,
17192    ) -> bool {
17193        let old_selections: Box<[_]> = self
17194            .selections
17195            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17196            .into();
17197        if old_selections.is_empty() {
17198            return false;
17199        }
17200
17201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17202
17203        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17204        let buffer = self.buffer.read(cx).snapshot(cx);
17205
17206        let mut any_cursor_moved = false;
17207        let new_selections = old_selections
17208            .iter()
17209            .map(|selection| {
17210                if !selection.is_empty() {
17211                    return selection.clone();
17212                }
17213
17214                let selection_pos = selection.head();
17215                let new_pos = self.find_syntax_node_boundary(
17216                    selection_pos,
17217                    move_to_end,
17218                    &display_map,
17219                    &buffer,
17220                );
17221
17222                any_cursor_moved |= new_pos != selection_pos;
17223
17224                Selection {
17225                    id: selection.id,
17226                    start: new_pos,
17227                    end: new_pos,
17228                    goal: SelectionGoal::None,
17229                    reversed: false,
17230                }
17231            })
17232            .collect::<Vec<_>>();
17233
17234        self.change_selections(Default::default(), window, cx, |s| {
17235            s.select(new_selections);
17236        });
17237        self.request_autoscroll(Autoscroll::newest(), cx);
17238
17239        any_cursor_moved
17240    }
17241
17242    pub fn select_to_start_of_larger_syntax_node(
17243        &mut self,
17244        _: &SelectToStartOfLargerSyntaxNode,
17245        window: &mut Window,
17246        cx: &mut Context<Self>,
17247    ) {
17248        self.select_to_syntax_nodes(window, cx, false);
17249    }
17250
17251    pub fn select_to_end_of_larger_syntax_node(
17252        &mut self,
17253        _: &SelectToEndOfLargerSyntaxNode,
17254        window: &mut Window,
17255        cx: &mut Context<Self>,
17256    ) {
17257        self.select_to_syntax_nodes(window, cx, true);
17258    }
17259
17260    fn select_to_syntax_nodes(
17261        &mut self,
17262        window: &mut Window,
17263        cx: &mut Context<Self>,
17264        move_to_end: bool,
17265    ) {
17266        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17267
17268        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17269        let buffer = self.buffer.read(cx).snapshot(cx);
17270        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17271
17272        let new_selections = old_selections
17273            .iter()
17274            .map(|selection| {
17275                let new_pos = self.find_syntax_node_boundary(
17276                    selection.head(),
17277                    move_to_end,
17278                    &display_map,
17279                    &buffer,
17280                );
17281
17282                let mut new_selection = selection.clone();
17283                new_selection.set_head(new_pos, SelectionGoal::None);
17284                new_selection
17285            })
17286            .collect::<Vec<_>>();
17287
17288        self.change_selections(Default::default(), window, cx, |s| {
17289            s.select(new_selections);
17290        });
17291    }
17292
17293    pub fn move_to_enclosing_bracket(
17294        &mut self,
17295        _: &MoveToEnclosingBracket,
17296        window: &mut Window,
17297        cx: &mut Context<Self>,
17298    ) {
17299        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17300        self.change_selections(Default::default(), window, cx, |s| {
17301            s.move_offsets_with(&mut |snapshot, selection| {
17302                let Some(enclosing_bracket_ranges) =
17303                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17304                else {
17305                    return;
17306                };
17307
17308                let mut best_length = usize::MAX;
17309                let mut best_inside = false;
17310                let mut best_in_bracket_range = false;
17311                let mut best_destination = None;
17312                for (open, close) in enclosing_bracket_ranges {
17313                    let close = close.to_inclusive();
17314                    let length = *close.end() - open.start;
17315                    let inside = selection.start >= open.end && selection.end <= *close.start();
17316                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17317                        || close.contains(&selection.head());
17318
17319                    // If best is next to a bracket and current isn't, skip
17320                    if !in_bracket_range && best_in_bracket_range {
17321                        continue;
17322                    }
17323
17324                    // Prefer smaller lengths unless best is inside and current isn't
17325                    if length > best_length && (best_inside || !inside) {
17326                        continue;
17327                    }
17328
17329                    best_length = length;
17330                    best_inside = inside;
17331                    best_in_bracket_range = in_bracket_range;
17332                    best_destination = Some(
17333                        if close.contains(&selection.start) && close.contains(&selection.end) {
17334                            if inside { open.end } else { open.start }
17335                        } else if inside {
17336                            *close.start()
17337                        } else {
17338                            *close.end()
17339                        },
17340                    );
17341                }
17342
17343                if let Some(destination) = best_destination {
17344                    selection.collapse_to(destination, SelectionGoal::None);
17345                }
17346            })
17347        });
17348    }
17349
17350    pub fn undo_selection(
17351        &mut self,
17352        _: &UndoSelection,
17353        window: &mut Window,
17354        cx: &mut Context<Self>,
17355    ) {
17356        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17357        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17358            self.selection_history.mode = SelectionHistoryMode::Undoing;
17359            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17360                this.end_selection(window, cx);
17361                this.change_selections(
17362                    SelectionEffects::scroll(Autoscroll::newest()),
17363                    window,
17364                    cx,
17365                    |s| s.select_anchors(entry.selections.to_vec()),
17366                );
17367            });
17368            self.selection_history.mode = SelectionHistoryMode::Normal;
17369
17370            self.select_next_state = entry.select_next_state;
17371            self.select_prev_state = entry.select_prev_state;
17372            self.add_selections_state = entry.add_selections_state;
17373        }
17374    }
17375
17376    pub fn redo_selection(
17377        &mut self,
17378        _: &RedoSelection,
17379        window: &mut Window,
17380        cx: &mut Context<Self>,
17381    ) {
17382        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17383        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17384            self.selection_history.mode = SelectionHistoryMode::Redoing;
17385            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17386                this.end_selection(window, cx);
17387                this.change_selections(
17388                    SelectionEffects::scroll(Autoscroll::newest()),
17389                    window,
17390                    cx,
17391                    |s| s.select_anchors(entry.selections.to_vec()),
17392                );
17393            });
17394            self.selection_history.mode = SelectionHistoryMode::Normal;
17395
17396            self.select_next_state = entry.select_next_state;
17397            self.select_prev_state = entry.select_prev_state;
17398            self.add_selections_state = entry.add_selections_state;
17399        }
17400    }
17401
17402    pub fn expand_excerpts(
17403        &mut self,
17404        action: &ExpandExcerpts,
17405        _: &mut Window,
17406        cx: &mut Context<Self>,
17407    ) {
17408        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17409    }
17410
17411    pub fn expand_excerpts_down(
17412        &mut self,
17413        action: &ExpandExcerptsDown,
17414        _: &mut Window,
17415        cx: &mut Context<Self>,
17416    ) {
17417        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17418    }
17419
17420    pub fn expand_excerpts_up(
17421        &mut self,
17422        action: &ExpandExcerptsUp,
17423        _: &mut Window,
17424        cx: &mut Context<Self>,
17425    ) {
17426        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17427    }
17428
17429    pub fn expand_excerpts_for_direction(
17430        &mut self,
17431        lines: u32,
17432        direction: ExpandExcerptDirection,
17433        cx: &mut Context<Self>,
17434    ) {
17435        let selections = self.selections.disjoint_anchors_arc();
17436
17437        let lines = if lines == 0 {
17438            EditorSettings::get_global(cx).expand_excerpt_lines
17439        } else {
17440            lines
17441        };
17442
17443        let snapshot = self.buffer.read(cx).snapshot(cx);
17444        let excerpt_ids = selections
17445            .iter()
17446            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17447            .unique()
17448            .sorted()
17449            .collect::<Vec<_>>();
17450
17451        if self.delegate_expand_excerpts {
17452            cx.emit(EditorEvent::ExpandExcerptsRequested {
17453                excerpt_ids,
17454                lines,
17455                direction,
17456            });
17457            return;
17458        }
17459
17460        self.buffer.update(cx, |buffer, cx| {
17461            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17462        })
17463    }
17464
17465    pub fn expand_excerpt(
17466        &mut self,
17467        excerpt: ExcerptId,
17468        direction: ExpandExcerptDirection,
17469        window: &mut Window,
17470        cx: &mut Context<Self>,
17471    ) {
17472        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17473
17474        if self.delegate_expand_excerpts {
17475            cx.emit(EditorEvent::ExpandExcerptsRequested {
17476                excerpt_ids: vec![excerpt],
17477                lines: lines_to_expand,
17478                direction,
17479            });
17480            return;
17481        }
17482
17483        let current_scroll_position = self.scroll_position(cx);
17484        let mut scroll = None;
17485
17486        if direction == ExpandExcerptDirection::Down {
17487            let multi_buffer = self.buffer.read(cx);
17488            let snapshot = multi_buffer.snapshot(cx);
17489            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17490                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17491                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17492            {
17493                let buffer_snapshot = buffer.read(cx).snapshot();
17494                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17495                let last_row = buffer_snapshot.max_point().row;
17496                let lines_below = last_row.saturating_sub(excerpt_end_row);
17497                if lines_below >= lines_to_expand {
17498                    scroll = Some(
17499                        current_scroll_position
17500                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17501                    );
17502                }
17503            }
17504        }
17505        if direction == ExpandExcerptDirection::Up
17506            && self
17507                .buffer
17508                .read(cx)
17509                .snapshot(cx)
17510                .excerpt_before(excerpt)
17511                .is_none()
17512        {
17513            scroll = Some(current_scroll_position);
17514        }
17515
17516        self.buffer.update(cx, |buffer, cx| {
17517            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17518        });
17519
17520        if let Some(new_scroll_position) = scroll {
17521            self.set_scroll_position(new_scroll_position, window, cx);
17522        }
17523    }
17524
17525    pub fn go_to_singleton_buffer_point(
17526        &mut self,
17527        point: Point,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        self.go_to_singleton_buffer_range(point..point, window, cx);
17532    }
17533
17534    pub fn go_to_singleton_buffer_range(
17535        &mut self,
17536        range: Range<Point>,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        let multibuffer = self.buffer().read(cx);
17541        let Some(buffer) = multibuffer.as_singleton() else {
17542            return;
17543        };
17544        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17545            return;
17546        };
17547        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17548            return;
17549        };
17550        self.change_selections(
17551            SelectionEffects::default().nav_history(true),
17552            window,
17553            cx,
17554            |s| s.select_anchor_ranges([start..end]),
17555        );
17556    }
17557
17558    pub fn go_to_diagnostic(
17559        &mut self,
17560        action: &GoToDiagnostic,
17561        window: &mut Window,
17562        cx: &mut Context<Self>,
17563    ) {
17564        if !self.diagnostics_enabled() {
17565            return;
17566        }
17567        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17568        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17569    }
17570
17571    pub fn go_to_prev_diagnostic(
17572        &mut self,
17573        action: &GoToPreviousDiagnostic,
17574        window: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        if !self.diagnostics_enabled() {
17578            return;
17579        }
17580        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17581        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17582    }
17583
17584    pub fn go_to_diagnostic_impl(
17585        &mut self,
17586        direction: Direction,
17587        severity: GoToDiagnosticSeverityFilter,
17588        window: &mut Window,
17589        cx: &mut Context<Self>,
17590    ) {
17591        let buffer = self.buffer.read(cx).snapshot(cx);
17592        let selection = self
17593            .selections
17594            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17595
17596        let mut active_group_id = None;
17597        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17598            && active_group.active_range.start.to_offset(&buffer) == selection.start
17599        {
17600            active_group_id = Some(active_group.group_id);
17601        }
17602
17603        fn filtered<'a>(
17604            severity: GoToDiagnosticSeverityFilter,
17605            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17606        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17607            diagnostics
17608                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17609                .filter(|entry| entry.range.start != entry.range.end)
17610                .filter(|entry| !entry.diagnostic.is_unnecessary)
17611        }
17612
17613        let before = filtered(
17614            severity,
17615            buffer
17616                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17617                .filter(|entry| entry.range.start <= selection.start),
17618        );
17619        let after = filtered(
17620            severity,
17621            buffer
17622                .diagnostics_in_range(selection.start..buffer.len())
17623                .filter(|entry| entry.range.start >= selection.start),
17624        );
17625
17626        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17627        if direction == Direction::Prev {
17628            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17629            {
17630                for diagnostic in prev_diagnostics.into_iter().rev() {
17631                    if diagnostic.range.start != selection.start
17632                        || active_group_id
17633                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17634                    {
17635                        found = Some(diagnostic);
17636                        break 'outer;
17637                    }
17638                }
17639            }
17640        } else {
17641            for diagnostic in after.chain(before) {
17642                if diagnostic.range.start != selection.start
17643                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17644                {
17645                    found = Some(diagnostic);
17646                    break;
17647                }
17648            }
17649        }
17650        let Some(next_diagnostic) = found else {
17651            return;
17652        };
17653
17654        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17655        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17656            return;
17657        };
17658        let snapshot = self.snapshot(window, cx);
17659        if snapshot.intersects_fold(next_diagnostic.range.start) {
17660            self.unfold_ranges(
17661                std::slice::from_ref(&next_diagnostic.range),
17662                true,
17663                false,
17664                cx,
17665            );
17666        }
17667        self.change_selections(Default::default(), window, cx, |s| {
17668            s.select_ranges(vec![
17669                next_diagnostic.range.start..next_diagnostic.range.start,
17670            ])
17671        });
17672        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17673        self.refresh_edit_prediction(false, true, window, cx);
17674    }
17675
17676    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17677        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17678        let snapshot = self.snapshot(window, cx);
17679        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17680        self.go_to_hunk_before_or_after_position(
17681            &snapshot,
17682            selection.head(),
17683            Direction::Next,
17684            true,
17685            window,
17686            cx,
17687        );
17688    }
17689
17690    pub fn go_to_hunk_before_or_after_position(
17691        &mut self,
17692        snapshot: &EditorSnapshot,
17693        position: Point,
17694        direction: Direction,
17695        wrap_around: bool,
17696        window: &mut Window,
17697        cx: &mut Context<Editor>,
17698    ) {
17699        let row = if direction == Direction::Next {
17700            self.hunk_after_position(snapshot, position, wrap_around)
17701                .map(|hunk| hunk.row_range.start)
17702        } else {
17703            self.hunk_before_position(snapshot, position, wrap_around)
17704        };
17705
17706        if let Some(row) = row {
17707            let destination = Point::new(row.0, 0);
17708            let autoscroll = Autoscroll::center();
17709
17710            self.unfold_ranges(&[destination..destination], false, false, cx);
17711            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17712                s.select_ranges([destination..destination]);
17713            });
17714        }
17715    }
17716
17717    fn hunk_after_position(
17718        &mut self,
17719        snapshot: &EditorSnapshot,
17720        position: Point,
17721        wrap_around: bool,
17722    ) -> Option<MultiBufferDiffHunk> {
17723        let result = snapshot
17724            .buffer_snapshot()
17725            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17726            .find(|hunk| hunk.row_range.start.0 > position.row);
17727
17728        if wrap_around {
17729            result.or_else(|| {
17730                snapshot
17731                    .buffer_snapshot()
17732                    .diff_hunks_in_range(Point::zero()..position)
17733                    .find(|hunk| hunk.row_range.end.0 < position.row)
17734            })
17735        } else {
17736            result
17737        }
17738    }
17739
17740    fn go_to_prev_hunk(
17741        &mut self,
17742        _: &GoToPreviousHunk,
17743        window: &mut Window,
17744        cx: &mut Context<Self>,
17745    ) {
17746        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17747        let snapshot = self.snapshot(window, cx);
17748        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17749        self.go_to_hunk_before_or_after_position(
17750            &snapshot,
17751            selection.head(),
17752            Direction::Prev,
17753            true,
17754            window,
17755            cx,
17756        );
17757    }
17758
17759    fn hunk_before_position(
17760        &mut self,
17761        snapshot: &EditorSnapshot,
17762        position: Point,
17763        wrap_around: bool,
17764    ) -> Option<MultiBufferRow> {
17765        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17766
17767        if wrap_around {
17768            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17769        } else {
17770            result
17771        }
17772    }
17773
17774    fn go_to_next_change(
17775        &mut self,
17776        _: &GoToNextChange,
17777        window: &mut Window,
17778        cx: &mut Context<Self>,
17779    ) {
17780        if let Some(selections) = self
17781            .change_list
17782            .next_change(1, Direction::Next)
17783            .map(|s| s.to_vec())
17784        {
17785            self.change_selections(Default::default(), window, cx, |s| {
17786                let map = s.display_snapshot();
17787                s.select_display_ranges(selections.iter().map(|a| {
17788                    let point = a.to_display_point(&map);
17789                    point..point
17790                }))
17791            })
17792        }
17793    }
17794
17795    fn go_to_previous_change(
17796        &mut self,
17797        _: &GoToPreviousChange,
17798        window: &mut Window,
17799        cx: &mut Context<Self>,
17800    ) {
17801        if let Some(selections) = self
17802            .change_list
17803            .next_change(1, Direction::Prev)
17804            .map(|s| s.to_vec())
17805        {
17806            self.change_selections(Default::default(), window, cx, |s| {
17807                let map = s.display_snapshot();
17808                s.select_display_ranges(selections.iter().map(|a| {
17809                    let point = a.to_display_point(&map);
17810                    point..point
17811                }))
17812            })
17813        }
17814    }
17815
17816    pub fn go_to_next_document_highlight(
17817        &mut self,
17818        _: &GoToNextDocumentHighlight,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17823    }
17824
17825    pub fn go_to_prev_document_highlight(
17826        &mut self,
17827        _: &GoToPreviousDocumentHighlight,
17828        window: &mut Window,
17829        cx: &mut Context<Self>,
17830    ) {
17831        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17832    }
17833
17834    pub fn go_to_document_highlight_before_or_after_position(
17835        &mut self,
17836        direction: Direction,
17837        window: &mut Window,
17838        cx: &mut Context<Editor>,
17839    ) {
17840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17841        let snapshot = self.snapshot(window, cx);
17842        let buffer = &snapshot.buffer_snapshot();
17843        let position = self
17844            .selections
17845            .newest::<Point>(&snapshot.display_snapshot)
17846            .head();
17847        let anchor_position = buffer.anchor_after(position);
17848
17849        // Get all document highlights (both read and write)
17850        let mut all_highlights = Vec::new();
17851
17852        if let Some((_, read_highlights)) = self
17853            .background_highlights
17854            .get(&HighlightKey::DocumentHighlightRead)
17855        {
17856            all_highlights.extend(read_highlights.iter());
17857        }
17858
17859        if let Some((_, write_highlights)) = self
17860            .background_highlights
17861            .get(&HighlightKey::DocumentHighlightWrite)
17862        {
17863            all_highlights.extend(write_highlights.iter());
17864        }
17865
17866        if all_highlights.is_empty() {
17867            return;
17868        }
17869
17870        // Sort highlights by position
17871        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17872
17873        let target_highlight = match direction {
17874            Direction::Next => {
17875                // Find the first highlight after the current position
17876                all_highlights
17877                    .iter()
17878                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17879            }
17880            Direction::Prev => {
17881                // Find the last highlight before the current position
17882                all_highlights
17883                    .iter()
17884                    .rev()
17885                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17886            }
17887        };
17888
17889        if let Some(highlight) = target_highlight {
17890            let destination = highlight.start.to_point(buffer);
17891            let autoscroll = Autoscroll::center();
17892
17893            self.unfold_ranges(&[destination..destination], false, false, cx);
17894            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17895                s.select_ranges([destination..destination]);
17896            });
17897        }
17898    }
17899
17900    fn go_to_line<T: 'static>(
17901        &mut self,
17902        position: Anchor,
17903        highlight_color: Option<Hsla>,
17904        window: &mut Window,
17905        cx: &mut Context<Self>,
17906    ) {
17907        let snapshot = self.snapshot(window, cx).display_snapshot;
17908        let position = position.to_point(&snapshot.buffer_snapshot());
17909        let start = snapshot
17910            .buffer_snapshot()
17911            .clip_point(Point::new(position.row, 0), Bias::Left);
17912        let end = start + Point::new(1, 0);
17913        let start = snapshot.buffer_snapshot().anchor_before(start);
17914        let end = snapshot.buffer_snapshot().anchor_before(end);
17915
17916        self.highlight_rows::<T>(
17917            start..end,
17918            highlight_color
17919                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17920            Default::default(),
17921            cx,
17922        );
17923
17924        if self.buffer.read(cx).is_singleton() {
17925            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17926        }
17927    }
17928
17929    pub fn go_to_definition(
17930        &mut self,
17931        _: &GoToDefinition,
17932        window: &mut Window,
17933        cx: &mut Context<Self>,
17934    ) -> Task<Result<Navigated>> {
17935        let definition =
17936            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17937        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17938        cx.spawn_in(window, async move |editor, cx| {
17939            if definition.await? == Navigated::Yes {
17940                return Ok(Navigated::Yes);
17941            }
17942            match fallback_strategy {
17943                GoToDefinitionFallback::None => Ok(Navigated::No),
17944                GoToDefinitionFallback::FindAllReferences => {
17945                    match editor.update_in(cx, |editor, window, cx| {
17946                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17947                    })? {
17948                        Some(references) => references.await,
17949                        None => Ok(Navigated::No),
17950                    }
17951                }
17952            }
17953        })
17954    }
17955
17956    pub fn go_to_declaration(
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, false, window, cx)
17963    }
17964
17965    pub fn go_to_declaration_split(
17966        &mut self,
17967        _: &GoToDeclaration,
17968        window: &mut Window,
17969        cx: &mut Context<Self>,
17970    ) -> Task<Result<Navigated>> {
17971        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17972    }
17973
17974    pub fn go_to_implementation(
17975        &mut self,
17976        _: &GoToImplementation,
17977        window: &mut Window,
17978        cx: &mut Context<Self>,
17979    ) -> Task<Result<Navigated>> {
17980        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17981    }
17982
17983    pub fn go_to_implementation_split(
17984        &mut self,
17985        _: &GoToImplementationSplit,
17986        window: &mut Window,
17987        cx: &mut Context<Self>,
17988    ) -> Task<Result<Navigated>> {
17989        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17990    }
17991
17992    pub fn go_to_type_definition(
17993        &mut self,
17994        _: &GoToTypeDefinition,
17995        window: &mut Window,
17996        cx: &mut Context<Self>,
17997    ) -> Task<Result<Navigated>> {
17998        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17999    }
18000
18001    pub fn go_to_definition_split(
18002        &mut self,
18003        _: &GoToDefinitionSplit,
18004        window: &mut Window,
18005        cx: &mut Context<Self>,
18006    ) -> Task<Result<Navigated>> {
18007        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18008    }
18009
18010    pub fn go_to_type_definition_split(
18011        &mut self,
18012        _: &GoToTypeDefinitionSplit,
18013        window: &mut Window,
18014        cx: &mut Context<Self>,
18015    ) -> Task<Result<Navigated>> {
18016        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18017    }
18018
18019    fn go_to_definition_of_kind(
18020        &mut self,
18021        kind: GotoDefinitionKind,
18022        split: bool,
18023        window: &mut Window,
18024        cx: &mut Context<Self>,
18025    ) -> Task<Result<Navigated>> {
18026        let Some(provider) = self.semantics_provider.clone() else {
18027            return Task::ready(Ok(Navigated::No));
18028        };
18029        let head = self
18030            .selections
18031            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18032            .head();
18033        let buffer = self.buffer.read(cx);
18034        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18035            return Task::ready(Ok(Navigated::No));
18036        };
18037        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18038            return Task::ready(Ok(Navigated::No));
18039        };
18040
18041        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18042
18043        cx.spawn_in(window, async move |editor, cx| {
18044            let Some(definitions) = definitions.await? else {
18045                return Ok(Navigated::No);
18046            };
18047            let navigated = editor
18048                .update_in(cx, |editor, window, cx| {
18049                    editor.navigate_to_hover_links(
18050                        Some(kind),
18051                        definitions
18052                            .into_iter()
18053                            .filter(|location| {
18054                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18055                            })
18056                            .map(HoverLink::Text)
18057                            .collect::<Vec<_>>(),
18058                        nav_entry,
18059                        split,
18060                        window,
18061                        cx,
18062                    )
18063                })?
18064                .await?;
18065            anyhow::Ok(navigated)
18066        })
18067    }
18068
18069    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18070        let selection = self.selections.newest_anchor();
18071        let head = selection.head();
18072        let tail = selection.tail();
18073
18074        let Some((buffer, start_position)) =
18075            self.buffer.read(cx).text_anchor_for_position(head, cx)
18076        else {
18077            return;
18078        };
18079
18080        let end_position = if head != tail {
18081            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18082                return;
18083            };
18084            Some(pos)
18085        } else {
18086            None
18087        };
18088
18089        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18090            let url = if let Some(end_pos) = end_position {
18091                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18092            } else {
18093                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18094            };
18095
18096            if let Some(url) = url {
18097                cx.update(|window, cx| {
18098                    if parse_zed_link(&url, cx).is_some() {
18099                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18100                    } else {
18101                        cx.open_url(&url);
18102                    }
18103                })?;
18104            }
18105
18106            anyhow::Ok(())
18107        });
18108
18109        url_finder.detach();
18110    }
18111
18112    pub fn open_selected_filename(
18113        &mut self,
18114        _: &OpenSelectedFilename,
18115        window: &mut Window,
18116        cx: &mut Context<Self>,
18117    ) {
18118        let Some(workspace) = self.workspace() else {
18119            return;
18120        };
18121
18122        let position = self.selections.newest_anchor().head();
18123
18124        let Some((buffer, buffer_position)) =
18125            self.buffer.read(cx).text_anchor_for_position(position, cx)
18126        else {
18127            return;
18128        };
18129
18130        let project = self.project.clone();
18131
18132        cx.spawn_in(window, async move |_, cx| {
18133            let result = find_file(&buffer, project, buffer_position, cx).await;
18134
18135            if let Some((_, path)) = result {
18136                workspace
18137                    .update_in(cx, |workspace, window, cx| {
18138                        workspace.open_resolved_path(path, window, cx)
18139                    })?
18140                    .await?;
18141            }
18142            anyhow::Ok(())
18143        })
18144        .detach();
18145    }
18146
18147    pub(crate) fn navigate_to_hover_links(
18148        &mut self,
18149        kind: Option<GotoDefinitionKind>,
18150        definitions: Vec<HoverLink>,
18151        origin: Option<NavigationEntry>,
18152        split: bool,
18153        window: &mut Window,
18154        cx: &mut Context<Editor>,
18155    ) -> Task<Result<Navigated>> {
18156        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18157        let mut first_url_or_file = None;
18158        let definitions: Vec<_> = definitions
18159            .into_iter()
18160            .filter_map(|def| match def {
18161                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18162                HoverLink::InlayHint(lsp_location, server_id) => {
18163                    let computation =
18164                        self.compute_target_location(lsp_location, server_id, window, cx);
18165                    Some(cx.background_spawn(computation))
18166                }
18167                HoverLink::Url(url) => {
18168                    first_url_or_file = Some(Either::Left(url));
18169                    None
18170                }
18171                HoverLink::File(path) => {
18172                    first_url_or_file = Some(Either::Right(path));
18173                    None
18174                }
18175            })
18176            .collect();
18177
18178        let workspace = self.workspace();
18179
18180        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18181        cx.spawn_in(window, async move |editor, cx| {
18182            let locations: Vec<Location> = future::join_all(definitions)
18183                .await
18184                .into_iter()
18185                .filter_map(|location| location.transpose())
18186                .collect::<Result<_>>()
18187                .context("location tasks")?;
18188            let mut locations = cx.update(|_, cx| {
18189                locations
18190                    .into_iter()
18191                    .map(|location| {
18192                        let buffer = location.buffer.read(cx);
18193                        (location.buffer, location.range.to_point(buffer))
18194                    })
18195                    .into_group_map()
18196            })?;
18197            let mut num_locations = 0;
18198            for ranges in locations.values_mut() {
18199                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18200                ranges.dedup();
18201                let fits_in_one_excerpt = ranges
18202                    .iter()
18203                    .tuple_windows()
18204                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18205                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18206            }
18207
18208            if num_locations > 1 {
18209                let tab_kind = match kind {
18210                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18211                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18212                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18213                    Some(GotoDefinitionKind::Type) => "Types",
18214                };
18215                let title = editor
18216                    .update_in(cx, |_, _, cx| {
18217                        let target = locations
18218                            .iter()
18219                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18220                            .map(|(buffer, location)| {
18221                                buffer
18222                                    .read(cx)
18223                                    .text_for_range(location.clone())
18224                                    .collect::<String>()
18225                            })
18226                            .filter(|text| !text.contains('\n'))
18227                            .unique()
18228                            .take(3)
18229                            .join(", ");
18230                        if target.is_empty() {
18231                            tab_kind.to_owned()
18232                        } else {
18233                            format!("{tab_kind} for {target}")
18234                        }
18235                    })
18236                    .context("buffer title")?;
18237
18238                let Some(workspace) = workspace else {
18239                    return Ok(Navigated::No);
18240                };
18241
18242                let opened = workspace
18243                    .update_in(cx, |workspace, window, cx| {
18244                        let allow_preview = PreviewTabsSettings::get_global(cx)
18245                            .enable_preview_multibuffer_from_code_navigation;
18246                        if let Some((target_editor, target_pane)) =
18247                            Self::open_locations_in_multibuffer(
18248                                workspace,
18249                                locations,
18250                                title,
18251                                split,
18252                                allow_preview,
18253                                MultibufferSelectionMode::First,
18254                                window,
18255                                cx,
18256                            )
18257                        {
18258                            // We create our own nav history instead of using
18259                            // `target_editor.nav_history` because `nav_history`
18260                            // seems to be populated asynchronously when an item
18261                            // is added to a pane
18262                            let mut nav_history = target_pane
18263                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18264                            target_editor.update(cx, |editor, cx| {
18265                                let nav_data = editor
18266                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18267                                let target =
18268                                    Some(nav_history.navigation_entry(Some(
18269                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18270                                    )));
18271                                nav_history.push_tag(origin, target);
18272                            })
18273                        }
18274                    })
18275                    .is_ok();
18276
18277                anyhow::Ok(Navigated::from_bool(opened))
18278            } else if num_locations == 0 {
18279                // If there is one url or file, open it directly
18280                match first_url_or_file {
18281                    Some(Either::Left(url)) => {
18282                        cx.update(|window, cx| {
18283                            if parse_zed_link(&url, cx).is_some() {
18284                                window
18285                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18286                            } else {
18287                                cx.open_url(&url);
18288                            }
18289                        })?;
18290                        Ok(Navigated::Yes)
18291                    }
18292                    Some(Either::Right(path)) => {
18293                        // TODO(andrew): respect preview tab settings
18294                        //               `enable_keep_preview_on_code_navigation` and
18295                        //               `enable_preview_file_from_code_navigation`
18296                        let Some(workspace) = workspace else {
18297                            return Ok(Navigated::No);
18298                        };
18299                        workspace
18300                            .update_in(cx, |workspace, window, cx| {
18301                                workspace.open_resolved_path(path, window, cx)
18302                            })?
18303                            .await?;
18304                        Ok(Navigated::Yes)
18305                    }
18306                    None => Ok(Navigated::No),
18307                }
18308            } else {
18309                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18310
18311                editor.update_in(cx, |editor, window, cx| {
18312                    let target_ranges = target_ranges
18313                        .into_iter()
18314                        .map(|r| editor.range_for_match(&r))
18315                        .map(collapse_multiline_range)
18316                        .collect::<Vec<_>>();
18317                    if !split
18318                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18319                    {
18320                        let multibuffer = editor.buffer.read(cx);
18321                        let target_ranges = target_ranges
18322                            .into_iter()
18323                            .filter_map(|r| {
18324                                let start = multibuffer.buffer_point_to_anchor(
18325                                    &target_buffer,
18326                                    r.start,
18327                                    cx,
18328                                )?;
18329                                let end = multibuffer.buffer_point_to_anchor(
18330                                    &target_buffer,
18331                                    r.end,
18332                                    cx,
18333                                )?;
18334                                Some(start..end)
18335                            })
18336                            .collect::<Vec<_>>();
18337                        if target_ranges.is_empty() {
18338                            return Navigated::No;
18339                        }
18340
18341                        editor.change_selections(
18342                            SelectionEffects::default().nav_history(true),
18343                            window,
18344                            cx,
18345                            |s| s.select_anchor_ranges(target_ranges),
18346                        );
18347
18348                        let target =
18349                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18350                        if let Some(mut nav_history) = editor.nav_history.clone() {
18351                            nav_history.push_tag(origin, target);
18352                        }
18353                    } else {
18354                        let Some(workspace) = workspace else {
18355                            return Navigated::No;
18356                        };
18357                        let pane = workspace.read(cx).active_pane().clone();
18358                        window.defer(cx, move |window, cx| {
18359                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18360                                workspace.update(cx, |workspace, cx| {
18361                                    let pane = if split {
18362                                        workspace.adjacent_pane(window, cx)
18363                                    } else {
18364                                        workspace.active_pane().clone()
18365                                    };
18366
18367                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18368                                    let keep_old_preview = preview_tabs_settings
18369                                        .enable_keep_preview_on_code_navigation;
18370                                    let allow_new_preview = preview_tabs_settings
18371                                        .enable_preview_file_from_code_navigation;
18372
18373                                    let editor = workspace.open_project_item(
18374                                        pane.clone(),
18375                                        target_buffer.clone(),
18376                                        true,
18377                                        true,
18378                                        keep_old_preview,
18379                                        allow_new_preview,
18380                                        window,
18381                                        cx,
18382                                    );
18383                                    (editor, pane)
18384                                });
18385                            // We create our own nav history instead of using
18386                            // `target_editor.nav_history` because `nav_history`
18387                            // seems to be populated asynchronously when an item
18388                            // is added to a pane
18389                            let mut nav_history = target_pane
18390                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18391                            target_editor.update(cx, |target_editor, cx| {
18392                                // When selecting a definition in a different buffer, disable the nav history
18393                                // to avoid creating a history entry at the previous cursor location.
18394                                pane.update(cx, |pane, _| pane.disable_history());
18395
18396                                let multibuffer = target_editor.buffer.read(cx);
18397                                let Some(target_buffer) = multibuffer.as_singleton() else {
18398                                    return Navigated::No;
18399                                };
18400                                let target_ranges = target_ranges
18401                                    .into_iter()
18402                                    .filter_map(|r| {
18403                                        let start = multibuffer.buffer_point_to_anchor(
18404                                            &target_buffer,
18405                                            r.start,
18406                                            cx,
18407                                        )?;
18408                                        let end = multibuffer.buffer_point_to_anchor(
18409                                            &target_buffer,
18410                                            r.end,
18411                                            cx,
18412                                        )?;
18413                                        Some(start..end)
18414                                    })
18415                                    .collect::<Vec<_>>();
18416                                if target_ranges.is_empty() {
18417                                    return Navigated::No;
18418                                }
18419
18420                                target_editor.change_selections(
18421                                    SelectionEffects::default().nav_history(true),
18422                                    window,
18423                                    cx,
18424                                    |s| s.select_anchor_ranges(target_ranges),
18425                                );
18426
18427                                let nav_data = target_editor.navigation_data(
18428                                    target_editor.selections.newest_anchor().head(),
18429                                    cx,
18430                                );
18431                                let target =
18432                                    Some(nav_history.navigation_entry(Some(
18433                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18434                                    )));
18435                                nav_history.push_tag(origin, target);
18436                                pane.update(cx, |pane, _| pane.enable_history());
18437                                Navigated::Yes
18438                            });
18439                        });
18440                    }
18441                    Navigated::Yes
18442                })
18443            }
18444        })
18445    }
18446
18447    fn compute_target_location(
18448        &self,
18449        lsp_location: lsp::Location,
18450        server_id: LanguageServerId,
18451        window: &mut Window,
18452        cx: &mut Context<Self>,
18453    ) -> Task<anyhow::Result<Option<Location>>> {
18454        let Some(project) = self.project.clone() else {
18455            return Task::ready(Ok(None));
18456        };
18457
18458        cx.spawn_in(window, async move |editor, cx| {
18459            let location_task = editor.update(cx, |_, cx| {
18460                project.update(cx, |project, cx| {
18461                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18462                })
18463            })?;
18464            let location = Some({
18465                let target_buffer_handle = location_task.await.context("open local buffer")?;
18466                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18467                    let target_start = target_buffer
18468                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18469                    let target_end = target_buffer
18470                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18471                    target_buffer.anchor_after(target_start)
18472                        ..target_buffer.anchor_before(target_end)
18473                });
18474                Location {
18475                    buffer: target_buffer_handle,
18476                    range,
18477                }
18478            });
18479            Ok(location)
18480        })
18481    }
18482
18483    fn go_to_next_reference(
18484        &mut self,
18485        _: &GoToNextReference,
18486        window: &mut Window,
18487        cx: &mut Context<Self>,
18488    ) {
18489        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18490        if let Some(task) = task {
18491            task.detach();
18492        };
18493    }
18494
18495    fn go_to_prev_reference(
18496        &mut self,
18497        _: &GoToPreviousReference,
18498        window: &mut Window,
18499        cx: &mut Context<Self>,
18500    ) {
18501        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18502        if let Some(task) = task {
18503            task.detach();
18504        };
18505    }
18506
18507    fn go_to_symbol_by_offset(
18508        &mut self,
18509        window: &mut Window,
18510        cx: &mut Context<Self>,
18511        offset: i8,
18512    ) -> Task<Result<()>> {
18513        let editor_snapshot = self.snapshot(window, cx);
18514
18515        // We don't care about multi-buffer symbols
18516        let Some((excerpt_id, _, _)) = editor_snapshot.as_singleton() else {
18517            return Task::ready(Ok(()));
18518        };
18519
18520        let cursor_offset = self
18521            .selections
18522            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18523            .head();
18524
18525        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18526            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18527                let buffer = ed.buffer.read(cx).as_singleton()?;
18528                Some(buffer.read(cx).remote_id())
18529            }) else {
18530                return Ok(());
18531            };
18532
18533            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18534            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18535
18536            let multi_snapshot = editor_snapshot.buffer();
18537            let buffer_range = |range: &Range<_>| {
18538                Anchor::range_in_buffer(excerpt_id, range.clone()).to_offset(multi_snapshot)
18539            };
18540
18541            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18542                let current_idx = outline_items
18543                    .iter()
18544                    .enumerate()
18545                    .filter_map(|(idx, item)| {
18546                        // Find the closest outline item by distance between outline text and cursor location
18547                        let source_range = buffer_range(&item.source_range_for_text);
18548                        let distance_to_closest_endpoint = cmp::min(
18549                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18550                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18551                        );
18552
18553                        let item_towards_offset =
18554                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18555                                == (offset as isize).signum();
18556
18557                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18558
18559                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18560                        // we should not already be within the outline's source range. We then pick the closest outline
18561                        // item.
18562                        (item_towards_offset && !source_range_contains_cursor)
18563                            .then_some((distance_to_closest_endpoint, idx))
18564                    })
18565                    .min()
18566                    .map(|(_, idx)| idx);
18567
18568                let Some(idx) = current_idx else {
18569                    return;
18570                };
18571
18572                let range = buffer_range(&outline_items[idx].source_range_for_text);
18573                let selection = [range.start..range.start];
18574
18575                let _ = editor
18576                    .update(acx, |editor, ecx| {
18577                        editor.change_selections(
18578                            SelectionEffects::scroll(Autoscroll::newest()),
18579                            window,
18580                            ecx,
18581                            |s| s.select_ranges(selection),
18582                        );
18583                    })
18584                    .ok();
18585            })?;
18586
18587            Ok(())
18588        })
18589    }
18590
18591    fn go_to_next_symbol(
18592        &mut self,
18593        _: &GoToNextSymbol,
18594        window: &mut Window,
18595        cx: &mut Context<Self>,
18596    ) {
18597        self.go_to_symbol_by_offset(window, cx, 1).detach();
18598    }
18599
18600    fn go_to_previous_symbol(
18601        &mut self,
18602        _: &GoToPreviousSymbol,
18603        window: &mut Window,
18604        cx: &mut Context<Self>,
18605    ) {
18606        self.go_to_symbol_by_offset(window, cx, -1).detach();
18607    }
18608
18609    pub fn go_to_reference_before_or_after_position(
18610        &mut self,
18611        direction: Direction,
18612        count: usize,
18613        window: &mut Window,
18614        cx: &mut Context<Self>,
18615    ) -> Option<Task<Result<()>>> {
18616        let selection = self.selections.newest_anchor();
18617        let head = selection.head();
18618
18619        let multi_buffer = self.buffer.read(cx);
18620
18621        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18622        let workspace = self.workspace()?;
18623        let project = workspace.read(cx).project().clone();
18624        let references =
18625            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18626        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18627            let Some(locations) = references.await? else {
18628                return Ok(());
18629            };
18630
18631            if locations.is_empty() {
18632                // totally normal - the cursor may be on something which is not
18633                // a symbol (e.g. a keyword)
18634                log::info!("no references found under cursor");
18635                return Ok(());
18636            }
18637
18638            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18639
18640            let (locations, current_location_index) =
18641                multi_buffer.update(cx, |multi_buffer, cx| {
18642                    let mut locations = locations
18643                        .into_iter()
18644                        .filter_map(|loc| {
18645                            let start = multi_buffer.buffer_anchor_to_anchor(
18646                                &loc.buffer,
18647                                loc.range.start,
18648                                cx,
18649                            )?;
18650                            let end = multi_buffer.buffer_anchor_to_anchor(
18651                                &loc.buffer,
18652                                loc.range.end,
18653                                cx,
18654                            )?;
18655                            Some(start..end)
18656                        })
18657                        .collect::<Vec<_>>();
18658
18659                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18660                    // There is an O(n) implementation, but given this list will be
18661                    // small (usually <100 items), the extra O(log(n)) factor isn't
18662                    // worth the (surprisingly large amount of) extra complexity.
18663                    locations
18664                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18665
18666                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18667
18668                    let current_location_index = locations.iter().position(|loc| {
18669                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18670                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18671                    });
18672
18673                    (locations, current_location_index)
18674                });
18675
18676            let Some(current_location_index) = current_location_index else {
18677                // This indicates something has gone wrong, because we already
18678                // handle the "no references" case above
18679                log::error!(
18680                    "failed to find current reference under cursor. Total references: {}",
18681                    locations.len()
18682                );
18683                return Ok(());
18684            };
18685
18686            let destination_location_index = match direction {
18687                Direction::Next => (current_location_index + count) % locations.len(),
18688                Direction::Prev => {
18689                    (current_location_index + locations.len() - count % locations.len())
18690                        % locations.len()
18691                }
18692            };
18693
18694            // TODO(cameron): is this needed?
18695            // the thinking is to avoid "jumping to the current location" (avoid
18696            // polluting "jumplist" in vim terms)
18697            if current_location_index == destination_location_index {
18698                return Ok(());
18699            }
18700
18701            let Range { start, end } = locations[destination_location_index];
18702
18703            editor.update_in(cx, |editor, window, cx| {
18704                let effects = SelectionEffects::default();
18705
18706                editor.unfold_ranges(&[start..end], false, false, cx);
18707                editor.change_selections(effects, window, cx, |s| {
18708                    s.select_ranges([start..start]);
18709                });
18710            })?;
18711
18712            Ok(())
18713        }))
18714    }
18715
18716    pub fn find_all_references(
18717        &mut self,
18718        action: &FindAllReferences,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) -> Option<Task<Result<Navigated>>> {
18722        let always_open_multibuffer = action.always_open_multibuffer;
18723        let selection = self.selections.newest_anchor();
18724        let multi_buffer = self.buffer.read(cx);
18725        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18726        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18727        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18728        let head = selection_offset.head();
18729
18730        let head_anchor = multi_buffer_snapshot.anchor_at(
18731            head,
18732            if head < selection_offset.tail() {
18733                Bias::Right
18734            } else {
18735                Bias::Left
18736            },
18737        );
18738
18739        match self
18740            .find_all_references_task_sources
18741            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18742        {
18743            Ok(_) => {
18744                log::info!(
18745                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18746                );
18747                return None;
18748            }
18749            Err(i) => {
18750                self.find_all_references_task_sources.insert(i, head_anchor);
18751            }
18752        }
18753
18754        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18755        let workspace = self.workspace()?;
18756        let project = workspace.read(cx).project().clone();
18757        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18758        Some(cx.spawn_in(window, async move |editor, cx| {
18759            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18760                if let Ok(i) = editor
18761                    .find_all_references_task_sources
18762                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18763                {
18764                    editor.find_all_references_task_sources.remove(i);
18765                }
18766            });
18767
18768            let Some(locations) = references.await? else {
18769                return anyhow::Ok(Navigated::No);
18770            };
18771            let mut locations = cx.update(|_, cx| {
18772                locations
18773                    .into_iter()
18774                    .map(|location| {
18775                        let buffer = location.buffer.read(cx);
18776                        (location.buffer, location.range.to_point(buffer))
18777                    })
18778                    // if special-casing the single-match case, remove ranges
18779                    // that intersect current selection
18780                    .filter(|(location_buffer, location)| {
18781                        if always_open_multibuffer || &buffer != location_buffer {
18782                            return true;
18783                        }
18784
18785                        !location.contains_inclusive(&selection_point.range())
18786                    })
18787                    .into_group_map()
18788            })?;
18789            if locations.is_empty() {
18790                return anyhow::Ok(Navigated::No);
18791            }
18792            for ranges in locations.values_mut() {
18793                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18794                ranges.dedup();
18795            }
18796            let mut num_locations = 0;
18797            for ranges in locations.values_mut() {
18798                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18799                ranges.dedup();
18800                num_locations += ranges.len();
18801            }
18802
18803            if num_locations == 1 && !always_open_multibuffer {
18804                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18805                let target_range = target_ranges.first().unwrap().clone();
18806
18807                return editor.update_in(cx, |editor, window, cx| {
18808                    let range = target_range.to_point(target_buffer.read(cx));
18809                    let range = editor.range_for_match(&range);
18810                    let range = range.start..range.start;
18811
18812                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18813                        editor.go_to_singleton_buffer_range(range, window, cx);
18814                    } else {
18815                        let pane = workspace.read(cx).active_pane().clone();
18816                        window.defer(cx, move |window, cx| {
18817                            let target_editor: Entity<Self> =
18818                                workspace.update(cx, |workspace, cx| {
18819                                    let pane = workspace.active_pane().clone();
18820
18821                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18822                                    let keep_old_preview = preview_tabs_settings
18823                                        .enable_keep_preview_on_code_navigation;
18824                                    let allow_new_preview = preview_tabs_settings
18825                                        .enable_preview_file_from_code_navigation;
18826
18827                                    workspace.open_project_item(
18828                                        pane,
18829                                        target_buffer.clone(),
18830                                        true,
18831                                        true,
18832                                        keep_old_preview,
18833                                        allow_new_preview,
18834                                        window,
18835                                        cx,
18836                                    )
18837                                });
18838                            target_editor.update(cx, |target_editor, cx| {
18839                                // When selecting a definition in a different buffer, disable the nav history
18840                                // to avoid creating a history entry at the previous cursor location.
18841                                pane.update(cx, |pane, _| pane.disable_history());
18842                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18843                                pane.update(cx, |pane, _| pane.enable_history());
18844                            });
18845                        });
18846                    }
18847                    Navigated::No
18848                });
18849            }
18850
18851            workspace.update_in(cx, |workspace, window, cx| {
18852                let target = locations
18853                    .iter()
18854                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18855                    .map(|(buffer, location)| {
18856                        buffer
18857                            .read(cx)
18858                            .text_for_range(location.clone())
18859                            .collect::<String>()
18860                    })
18861                    .filter(|text| !text.contains('\n'))
18862                    .unique()
18863                    .take(3)
18864                    .join(", ");
18865                let title = if target.is_empty() {
18866                    "References".to_owned()
18867                } else {
18868                    format!("References to {target}")
18869                };
18870                let allow_preview = PreviewTabsSettings::get_global(cx)
18871                    .enable_preview_multibuffer_from_code_navigation;
18872                Self::open_locations_in_multibuffer(
18873                    workspace,
18874                    locations,
18875                    title,
18876                    false,
18877                    allow_preview,
18878                    MultibufferSelectionMode::First,
18879                    window,
18880                    cx,
18881                );
18882                Navigated::Yes
18883            })
18884        }))
18885    }
18886
18887    /// Opens a multibuffer with the given project locations in it.
18888    pub fn open_locations_in_multibuffer(
18889        workspace: &mut Workspace,
18890        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18891        title: String,
18892        split: bool,
18893        allow_preview: bool,
18894        multibuffer_selection_mode: MultibufferSelectionMode,
18895        window: &mut Window,
18896        cx: &mut Context<Workspace>,
18897    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18898        if locations.is_empty() {
18899            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18900            return None;
18901        }
18902
18903        let capability = workspace.project().read(cx).capability();
18904        let mut ranges = <Vec<Range<Anchor>>>::new();
18905
18906        // a key to find existing multibuffer editors with the same set of locations
18907        // to prevent us from opening more and more multibuffer tabs for searches and the like
18908        let mut key = (title.clone(), vec![]);
18909        let excerpt_buffer = cx.new(|cx| {
18910            let key = &mut key.1;
18911            let mut multibuffer = MultiBuffer::new(capability);
18912            for (buffer, mut ranges_for_buffer) in locations {
18913                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18914                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18915                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18916                    PathKey::for_buffer(&buffer, cx),
18917                    buffer.clone(),
18918                    ranges_for_buffer,
18919                    multibuffer_context_lines(cx),
18920                    cx,
18921                );
18922                ranges.extend(new_ranges)
18923            }
18924
18925            multibuffer.with_title(title)
18926        });
18927        let existing = workspace.active_pane().update(cx, |pane, cx| {
18928            pane.items()
18929                .filter_map(|item| item.downcast::<Editor>())
18930                .find(|editor| {
18931                    editor
18932                        .read(cx)
18933                        .lookup_key
18934                        .as_ref()
18935                        .and_then(|it| {
18936                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18937                        })
18938                        .is_some_and(|it| *it == key)
18939                })
18940        });
18941        let was_existing = existing.is_some();
18942        let editor = existing.unwrap_or_else(|| {
18943            cx.new(|cx| {
18944                let mut editor = Editor::for_multibuffer(
18945                    excerpt_buffer,
18946                    Some(workspace.project().clone()),
18947                    window,
18948                    cx,
18949                );
18950                editor.lookup_key = Some(Box::new(key));
18951                editor
18952            })
18953        });
18954        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18955            MultibufferSelectionMode::First => {
18956                if let Some(first_range) = ranges.first() {
18957                    editor.change_selections(
18958                        SelectionEffects::no_scroll(),
18959                        window,
18960                        cx,
18961                        |selections| {
18962                            selections.clear_disjoint();
18963                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18964                        },
18965                    );
18966                }
18967                editor.highlight_background(
18968                    HighlightKey::Editor,
18969                    &ranges,
18970                    |_, theme| theme.colors().editor_highlighted_line_background,
18971                    cx,
18972                );
18973            }
18974            MultibufferSelectionMode::All => {
18975                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18976                    selections.clear_disjoint();
18977                    selections.select_anchor_ranges(ranges);
18978                });
18979            }
18980        });
18981
18982        let item = Box::new(editor.clone());
18983
18984        let pane = if split {
18985            workspace.adjacent_pane(window, cx)
18986        } else {
18987            workspace.active_pane().clone()
18988        };
18989        let activate_pane = split;
18990
18991        let mut destination_index = None;
18992        pane.update(cx, |pane, cx| {
18993            if allow_preview && !was_existing {
18994                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18995            }
18996            if was_existing && !allow_preview {
18997                pane.unpreview_item_if_preview(item.item_id());
18998            }
18999            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19000        });
19001
19002        Some((editor, pane))
19003    }
19004
19005    pub fn rename(
19006        &mut self,
19007        _: &Rename,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) -> Option<Task<Result<()>>> {
19011        use language::ToOffset as _;
19012
19013        let provider = self.semantics_provider.clone()?;
19014        let selection = self.selections.newest_anchor().clone();
19015        let (cursor_buffer, cursor_buffer_position) = self
19016            .buffer
19017            .read(cx)
19018            .text_anchor_for_position(selection.head(), cx)?;
19019        let (tail_buffer, cursor_buffer_position_end) = self
19020            .buffer
19021            .read(cx)
19022            .text_anchor_for_position(selection.tail(), cx)?;
19023        if tail_buffer != cursor_buffer {
19024            return None;
19025        }
19026
19027        let snapshot = cursor_buffer.read(cx).snapshot();
19028        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19029        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19030        let prepare_rename = provider
19031            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
19032            .unwrap_or_else(|| Task::ready(Ok(None)));
19033        drop(snapshot);
19034
19035        Some(cx.spawn_in(window, async move |this, cx| {
19036            let rename_range = if let Some(range) = prepare_rename.await? {
19037                Some(range)
19038            } else {
19039                this.update(cx, |this, cx| {
19040                    let buffer = this.buffer.read(cx).snapshot(cx);
19041                    let mut buffer_highlights = this
19042                        .document_highlights_for_position(selection.head(), &buffer)
19043                        .filter(|highlight| {
19044                            highlight.start.excerpt_id == selection.head().excerpt_id
19045                                && highlight.end.excerpt_id == selection.head().excerpt_id
19046                        });
19047                    buffer_highlights
19048                        .next()
19049                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
19050                })?
19051            };
19052            if let Some(rename_range) = rename_range {
19053                this.update_in(cx, |this, window, cx| {
19054                    let snapshot = cursor_buffer.read(cx).snapshot();
19055                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19056                    let cursor_offset_in_rename_range =
19057                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19058                    let cursor_offset_in_rename_range_end =
19059                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19060
19061                    this.take_rename(false, window, cx);
19062                    let buffer = this.buffer.read(cx).read(cx);
19063                    let cursor_offset = selection.head().to_offset(&buffer);
19064                    let rename_start =
19065                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19066                    let rename_end = rename_start + rename_buffer_range.len();
19067                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19068                    let mut old_highlight_id = None;
19069                    let old_name: Arc<str> = buffer
19070                        .chunks(rename_start..rename_end, true)
19071                        .map(|chunk| {
19072                            if old_highlight_id.is_none() {
19073                                old_highlight_id = chunk.syntax_highlight_id;
19074                            }
19075                            chunk.text
19076                        })
19077                        .collect::<String>()
19078                        .into();
19079
19080                    drop(buffer);
19081
19082                    // Position the selection in the rename editor so that it matches the current selection.
19083                    this.show_local_selections = false;
19084                    let rename_editor = cx.new(|cx| {
19085                        let mut editor = Editor::single_line(window, cx);
19086                        editor.buffer.update(cx, |buffer, cx| {
19087                            buffer.edit(
19088                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19089                                None,
19090                                cx,
19091                            )
19092                        });
19093                        let cursor_offset_in_rename_range =
19094                            MultiBufferOffset(cursor_offset_in_rename_range);
19095                        let cursor_offset_in_rename_range_end =
19096                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19097                        let rename_selection_range = match cursor_offset_in_rename_range
19098                            .cmp(&cursor_offset_in_rename_range_end)
19099                        {
19100                            Ordering::Equal => {
19101                                editor.select_all(&SelectAll, window, cx);
19102                                return editor;
19103                            }
19104                            Ordering::Less => {
19105                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19106                            }
19107                            Ordering::Greater => {
19108                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19109                            }
19110                        };
19111                        if rename_selection_range.end.0 > old_name.len() {
19112                            editor.select_all(&SelectAll, window, cx);
19113                        } else {
19114                            editor.change_selections(Default::default(), window, cx, |s| {
19115                                s.select_ranges([rename_selection_range]);
19116                            });
19117                        }
19118                        editor
19119                    });
19120                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19121                        if e == &EditorEvent::Focused {
19122                            cx.emit(EditorEvent::FocusedIn)
19123                        }
19124                    })
19125                    .detach();
19126
19127                    let write_highlights =
19128                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19129                    let read_highlights =
19130                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19131                    let ranges = write_highlights
19132                        .iter()
19133                        .flat_map(|(_, ranges)| ranges.iter())
19134                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19135                        .cloned()
19136                        .collect();
19137
19138                    this.highlight_text(
19139                        HighlightKey::Rename,
19140                        ranges,
19141                        HighlightStyle {
19142                            fade_out: Some(0.6),
19143                            ..Default::default()
19144                        },
19145                        cx,
19146                    );
19147                    let rename_focus_handle = rename_editor.focus_handle(cx);
19148                    window.focus(&rename_focus_handle, cx);
19149                    let block_id = this.insert_blocks(
19150                        [BlockProperties {
19151                            style: BlockStyle::Flex,
19152                            placement: BlockPlacement::Below(range.start),
19153                            height: Some(1),
19154                            render: Arc::new({
19155                                let rename_editor = rename_editor.clone();
19156                                move |cx: &mut BlockContext| {
19157                                    let mut text_style = cx.editor_style.text.clone();
19158                                    if let Some(highlight_style) = old_highlight_id
19159                                        .and_then(|h| h.style(&cx.editor_style.syntax))
19160                                    {
19161                                        text_style = text_style.highlight(highlight_style);
19162                                    }
19163                                    div()
19164                                        .block_mouse_except_scroll()
19165                                        .pl(cx.anchor_x)
19166                                        .child(EditorElement::new(
19167                                            &rename_editor,
19168                                            EditorStyle {
19169                                                background: cx.theme().system().transparent,
19170                                                local_player: cx.editor_style.local_player,
19171                                                text: text_style,
19172                                                scrollbar_width: cx.editor_style.scrollbar_width,
19173                                                syntax: cx.editor_style.syntax.clone(),
19174                                                status: cx.editor_style.status.clone(),
19175                                                inlay_hints_style: HighlightStyle {
19176                                                    font_weight: Some(FontWeight::BOLD),
19177                                                    ..make_inlay_hints_style(cx.app)
19178                                                },
19179                                                edit_prediction_styles: make_suggestion_styles(
19180                                                    cx.app,
19181                                                ),
19182                                                ..EditorStyle::default()
19183                                            },
19184                                        ))
19185                                        .into_any_element()
19186                                }
19187                            }),
19188                            priority: 0,
19189                        }],
19190                        Some(Autoscroll::fit()),
19191                        cx,
19192                    )[0];
19193                    this.pending_rename = Some(RenameState {
19194                        range,
19195                        old_name,
19196                        editor: rename_editor,
19197                        block_id,
19198                    });
19199                })?;
19200            }
19201
19202            Ok(())
19203        }))
19204    }
19205
19206    pub fn confirm_rename(
19207        &mut self,
19208        _: &ConfirmRename,
19209        window: &mut Window,
19210        cx: &mut Context<Self>,
19211    ) -> Option<Task<Result<()>>> {
19212        let rename = self.take_rename(false, window, cx)?;
19213        let workspace = self.workspace()?.downgrade();
19214        let (buffer, start) = self
19215            .buffer
19216            .read(cx)
19217            .text_anchor_for_position(rename.range.start, cx)?;
19218        let (end_buffer, _) = self
19219            .buffer
19220            .read(cx)
19221            .text_anchor_for_position(rename.range.end, cx)?;
19222        if buffer != end_buffer {
19223            return None;
19224        }
19225
19226        let old_name = rename.old_name;
19227        let new_name = rename.editor.read(cx).text(cx);
19228
19229        let rename = self.semantics_provider.as_ref()?.perform_rename(
19230            &buffer,
19231            start,
19232            new_name.clone(),
19233            cx,
19234        )?;
19235
19236        Some(cx.spawn_in(window, async move |editor, cx| {
19237            let project_transaction = rename.await?;
19238            Self::open_project_transaction(
19239                &editor,
19240                workspace,
19241                project_transaction,
19242                format!("Rename: {}{}", old_name, new_name),
19243                cx,
19244            )
19245            .await?;
19246
19247            editor.update(cx, |editor, cx| {
19248                editor.refresh_document_highlights(cx);
19249            })?;
19250            Ok(())
19251        }))
19252    }
19253
19254    fn take_rename(
19255        &mut self,
19256        moving_cursor: bool,
19257        window: &mut Window,
19258        cx: &mut Context<Self>,
19259    ) -> Option<RenameState> {
19260        let rename = self.pending_rename.take()?;
19261        if rename.editor.focus_handle(cx).is_focused(window) {
19262            window.focus(&self.focus_handle, cx);
19263        }
19264
19265        self.remove_blocks(
19266            [rename.block_id].into_iter().collect(),
19267            Some(Autoscroll::fit()),
19268            cx,
19269        );
19270        self.clear_highlights(HighlightKey::Rename, cx);
19271        self.show_local_selections = true;
19272
19273        if moving_cursor {
19274            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19275                editor
19276                    .selections
19277                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19278                    .head()
19279            });
19280
19281            // Update the selection to match the position of the selection inside
19282            // the rename editor.
19283            let snapshot = self.buffer.read(cx).read(cx);
19284            let rename_range = rename.range.to_offset(&snapshot);
19285            let cursor_in_editor = snapshot
19286                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19287                .min(rename_range.end);
19288            drop(snapshot);
19289
19290            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19291                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19292            });
19293        } else {
19294            self.refresh_document_highlights(cx);
19295        }
19296
19297        Some(rename)
19298    }
19299
19300    pub fn pending_rename(&self) -> Option<&RenameState> {
19301        self.pending_rename.as_ref()
19302    }
19303
19304    fn format(
19305        &mut self,
19306        _: &Format,
19307        window: &mut Window,
19308        cx: &mut Context<Self>,
19309    ) -> Option<Task<Result<()>>> {
19310        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19311
19312        let project = match &self.project {
19313            Some(project) => project.clone(),
19314            None => return None,
19315        };
19316
19317        Some(self.perform_format(
19318            project,
19319            FormatTrigger::Manual,
19320            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19321            window,
19322            cx,
19323        ))
19324    }
19325
19326    fn format_selections(
19327        &mut self,
19328        _: &FormatSelections,
19329        window: &mut Window,
19330        cx: &mut Context<Self>,
19331    ) -> Option<Task<Result<()>>> {
19332        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19333
19334        let project = match &self.project {
19335            Some(project) => project.clone(),
19336            None => return None,
19337        };
19338
19339        let ranges = self
19340            .selections
19341            .all_adjusted(&self.display_snapshot(cx))
19342            .into_iter()
19343            .map(|selection| selection.range())
19344            .collect_vec();
19345
19346        Some(self.perform_format(
19347            project,
19348            FormatTrigger::Manual,
19349            FormatTarget::Ranges(ranges),
19350            window,
19351            cx,
19352        ))
19353    }
19354
19355    fn perform_format(
19356        &mut self,
19357        project: Entity<Project>,
19358        trigger: FormatTrigger,
19359        target: FormatTarget,
19360        window: &mut Window,
19361        cx: &mut Context<Self>,
19362    ) -> Task<Result<()>> {
19363        let buffer = self.buffer.clone();
19364        let (buffers, target) = match target {
19365            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19366            FormatTarget::Ranges(selection_ranges) => {
19367                let multi_buffer = buffer.read(cx);
19368                let snapshot = multi_buffer.read(cx);
19369                let mut buffers = HashSet::default();
19370                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19371                    BTreeMap::new();
19372                for selection_range in selection_ranges {
19373                    for (buffer, buffer_range, _) in
19374                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
19375                    {
19376                        let buffer_id = buffer.remote_id();
19377                        let start = buffer.anchor_before(buffer_range.start);
19378                        let end = buffer.anchor_after(buffer_range.end);
19379                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19380                        buffer_id_to_ranges
19381                            .entry(buffer_id)
19382                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19383                            .or_insert_with(|| vec![start..end]);
19384                    }
19385                }
19386                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19387            }
19388        };
19389
19390        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19391        let selections_prev = transaction_id_prev
19392            .and_then(|transaction_id_prev| {
19393                // default to selections as they were after the last edit, if we have them,
19394                // instead of how they are now.
19395                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19396                // will take you back to where you made the last edit, instead of staying where you scrolled
19397                self.selection_history
19398                    .transaction(transaction_id_prev)
19399                    .map(|t| t.0.clone())
19400            })
19401            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19402
19403        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19404        let format = project.update(cx, |project, cx| {
19405            project.format(buffers, target, true, trigger, cx)
19406        });
19407
19408        cx.spawn_in(window, async move |editor, cx| {
19409            let transaction = futures::select_biased! {
19410                transaction = format.log_err().fuse() => transaction,
19411                () = timeout => {
19412                    log::warn!("timed out waiting for formatting");
19413                    None
19414                }
19415            };
19416
19417            buffer.update(cx, |buffer, cx| {
19418                if let Some(transaction) = transaction
19419                    && !buffer.is_singleton()
19420                {
19421                    buffer.push_transaction(&transaction.0, cx);
19422                }
19423                cx.notify();
19424            });
19425
19426            if let Some(transaction_id_now) =
19427                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19428            {
19429                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19430                if has_new_transaction {
19431                    editor
19432                        .update(cx, |editor, _| {
19433                            editor
19434                                .selection_history
19435                                .insert_transaction(transaction_id_now, selections_prev);
19436                        })
19437                        .ok();
19438                }
19439            }
19440
19441            Ok(())
19442        })
19443    }
19444
19445    fn organize_imports(
19446        &mut self,
19447        _: &OrganizeImports,
19448        window: &mut Window,
19449        cx: &mut Context<Self>,
19450    ) -> Option<Task<Result<()>>> {
19451        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19452        let project = match &self.project {
19453            Some(project) => project.clone(),
19454            None => return None,
19455        };
19456        Some(self.perform_code_action_kind(
19457            project,
19458            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19459            window,
19460            cx,
19461        ))
19462    }
19463
19464    fn perform_code_action_kind(
19465        &mut self,
19466        project: Entity<Project>,
19467        kind: CodeActionKind,
19468        window: &mut Window,
19469        cx: &mut Context<Self>,
19470    ) -> Task<Result<()>> {
19471        let buffer = self.buffer.clone();
19472        let buffers = buffer.read(cx).all_buffers();
19473        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19474        let apply_action = project.update(cx, |project, cx| {
19475            project.apply_code_action_kind(buffers, kind, true, cx)
19476        });
19477        cx.spawn_in(window, async move |_, cx| {
19478            let transaction = futures::select_biased! {
19479                () = timeout => {
19480                    log::warn!("timed out waiting for executing code action");
19481                    None
19482                }
19483                transaction = apply_action.log_err().fuse() => transaction,
19484            };
19485            buffer.update(cx, |buffer, cx| {
19486                // check if we need this
19487                if let Some(transaction) = transaction
19488                    && !buffer.is_singleton()
19489                {
19490                    buffer.push_transaction(&transaction.0, cx);
19491                }
19492                cx.notify();
19493            });
19494            Ok(())
19495        })
19496    }
19497
19498    pub fn restart_language_server(
19499        &mut self,
19500        _: &RestartLanguageServer,
19501        _: &mut Window,
19502        cx: &mut Context<Self>,
19503    ) {
19504        if let Some(project) = self.project.clone() {
19505            self.buffer.update(cx, |multi_buffer, cx| {
19506                project.update(cx, |project, cx| {
19507                    project.restart_language_servers_for_buffers(
19508                        multi_buffer.all_buffers().into_iter().collect(),
19509                        HashSet::default(),
19510                        cx,
19511                    );
19512                });
19513            })
19514        }
19515    }
19516
19517    pub fn stop_language_server(
19518        &mut self,
19519        _: &StopLanguageServer,
19520        _: &mut Window,
19521        cx: &mut Context<Self>,
19522    ) {
19523        if let Some(project) = self.project.clone() {
19524            self.buffer.update(cx, |multi_buffer, cx| {
19525                project.update(cx, |project, cx| {
19526                    project.stop_language_servers_for_buffers(
19527                        multi_buffer.all_buffers().into_iter().collect(),
19528                        HashSet::default(),
19529                        cx,
19530                    );
19531                });
19532            });
19533        }
19534    }
19535
19536    fn cancel_language_server_work(
19537        workspace: &mut Workspace,
19538        _: &actions::CancelLanguageServerWork,
19539        _: &mut Window,
19540        cx: &mut Context<Workspace>,
19541    ) {
19542        let project = workspace.project();
19543        let buffers = workspace
19544            .active_item(cx)
19545            .and_then(|item| item.act_as::<Editor>(cx))
19546            .map_or(HashSet::default(), |editor| {
19547                editor.read(cx).buffer.read(cx).all_buffers()
19548            });
19549        project.update(cx, |project, cx| {
19550            project.cancel_language_server_work_for_buffers(buffers, cx);
19551        });
19552    }
19553
19554    fn show_character_palette(
19555        &mut self,
19556        _: &ShowCharacterPalette,
19557        window: &mut Window,
19558        _: &mut Context<Self>,
19559    ) {
19560        window.show_character_palette();
19561    }
19562
19563    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19564        if !self.diagnostics_enabled() {
19565            return;
19566        }
19567
19568        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19569            let buffer = self.buffer.read(cx).snapshot(cx);
19570            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19571            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19572            let is_valid = buffer
19573                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19574                .any(|entry| {
19575                    entry.diagnostic.is_primary
19576                        && !entry.range.is_empty()
19577                        && entry.range.start == primary_range_start
19578                        && entry.diagnostic.message == active_diagnostics.active_message
19579                });
19580
19581            if !is_valid {
19582                self.dismiss_diagnostics(cx);
19583            }
19584        }
19585    }
19586
19587    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19588        match &self.active_diagnostics {
19589            ActiveDiagnostic::Group(group) => Some(group),
19590            _ => None,
19591        }
19592    }
19593
19594    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19595        if !self.diagnostics_enabled() {
19596            return;
19597        }
19598        self.dismiss_diagnostics(cx);
19599        self.active_diagnostics = ActiveDiagnostic::All;
19600    }
19601
19602    fn activate_diagnostics(
19603        &mut self,
19604        buffer_id: BufferId,
19605        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19606        window: &mut Window,
19607        cx: &mut Context<Self>,
19608    ) {
19609        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19610            return;
19611        }
19612        self.dismiss_diagnostics(cx);
19613        let snapshot = self.snapshot(window, cx);
19614        let buffer = self.buffer.read(cx).snapshot(cx);
19615        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19616            return;
19617        };
19618
19619        let diagnostic_group = buffer
19620            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19621            .collect::<Vec<_>>();
19622
19623        let language_registry = self
19624            .project()
19625            .map(|project| project.read(cx).languages().clone());
19626
19627        let blocks = renderer.render_group(
19628            diagnostic_group,
19629            buffer_id,
19630            snapshot,
19631            cx.weak_entity(),
19632            language_registry,
19633            cx,
19634        );
19635
19636        let blocks = self.display_map.update(cx, |display_map, cx| {
19637            display_map.insert_blocks(blocks, cx).into_iter().collect()
19638        });
19639        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19640            active_range: buffer.anchor_before(diagnostic.range.start)
19641                ..buffer.anchor_after(diagnostic.range.end),
19642            active_message: diagnostic.diagnostic.message.clone(),
19643            group_id: diagnostic.diagnostic.group_id,
19644            blocks,
19645        });
19646        cx.notify();
19647    }
19648
19649    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19650        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19651            return;
19652        };
19653
19654        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19655        if let ActiveDiagnostic::Group(group) = prev {
19656            self.display_map.update(cx, |display_map, cx| {
19657                display_map.remove_blocks(group.blocks, cx);
19658            });
19659            cx.notify();
19660        }
19661    }
19662
19663    /// Disable inline diagnostics rendering for this editor.
19664    pub fn disable_inline_diagnostics(&mut self) {
19665        self.inline_diagnostics_enabled = false;
19666        self.inline_diagnostics_update = Task::ready(());
19667        self.inline_diagnostics.clear();
19668    }
19669
19670    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19671        self.diagnostics_enabled = false;
19672        self.dismiss_diagnostics(cx);
19673        self.inline_diagnostics_update = Task::ready(());
19674        self.inline_diagnostics.clear();
19675    }
19676
19677    pub fn disable_word_completions(&mut self) {
19678        self.word_completions_enabled = false;
19679    }
19680
19681    pub fn diagnostics_enabled(&self) -> bool {
19682        self.diagnostics_enabled && self.lsp_data_enabled()
19683    }
19684
19685    pub fn inline_diagnostics_enabled(&self) -> bool {
19686        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19687    }
19688
19689    pub fn show_inline_diagnostics(&self) -> bool {
19690        self.show_inline_diagnostics
19691    }
19692
19693    pub fn toggle_inline_diagnostics(
19694        &mut self,
19695        _: &ToggleInlineDiagnostics,
19696        window: &mut Window,
19697        cx: &mut Context<Editor>,
19698    ) {
19699        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19700        self.refresh_inline_diagnostics(false, window, cx);
19701    }
19702
19703    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19704        self.diagnostics_max_severity = severity;
19705        self.display_map.update(cx, |display_map, _| {
19706            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19707        });
19708    }
19709
19710    pub fn toggle_diagnostics(
19711        &mut self,
19712        _: &ToggleDiagnostics,
19713        window: &mut Window,
19714        cx: &mut Context<Editor>,
19715    ) {
19716        if !self.diagnostics_enabled() {
19717            return;
19718        }
19719
19720        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19721            EditorSettings::get_global(cx)
19722                .diagnostics_max_severity
19723                .filter(|severity| severity != &DiagnosticSeverity::Off)
19724                .unwrap_or(DiagnosticSeverity::Hint)
19725        } else {
19726            DiagnosticSeverity::Off
19727        };
19728        self.set_max_diagnostics_severity(new_severity, cx);
19729        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19730            self.active_diagnostics = ActiveDiagnostic::None;
19731            self.inline_diagnostics_update = Task::ready(());
19732            self.inline_diagnostics.clear();
19733        } else {
19734            self.refresh_inline_diagnostics(false, window, cx);
19735        }
19736
19737        cx.notify();
19738    }
19739
19740    pub fn toggle_minimap(
19741        &mut self,
19742        _: &ToggleMinimap,
19743        window: &mut Window,
19744        cx: &mut Context<Editor>,
19745    ) {
19746        if self.supports_minimap(cx) {
19747            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19748        }
19749    }
19750
19751    fn refresh_inline_diagnostics(
19752        &mut self,
19753        debounce: bool,
19754        window: &mut Window,
19755        cx: &mut Context<Self>,
19756    ) {
19757        let max_severity = ProjectSettings::get_global(cx)
19758            .diagnostics
19759            .inline
19760            .max_severity
19761            .unwrap_or(self.diagnostics_max_severity);
19762
19763        if !self.inline_diagnostics_enabled()
19764            || !self.diagnostics_enabled()
19765            || !self.show_inline_diagnostics
19766            || max_severity == DiagnosticSeverity::Off
19767        {
19768            self.inline_diagnostics_update = Task::ready(());
19769            self.inline_diagnostics.clear();
19770            return;
19771        }
19772
19773        let debounce_ms = ProjectSettings::get_global(cx)
19774            .diagnostics
19775            .inline
19776            .update_debounce_ms;
19777        let debounce = if debounce && debounce_ms > 0 {
19778            Some(Duration::from_millis(debounce_ms))
19779        } else {
19780            None
19781        };
19782        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19783            if let Some(debounce) = debounce {
19784                cx.background_executor().timer(debounce).await;
19785            }
19786            let Some(snapshot) = editor.upgrade().map(|editor| {
19787                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19788            }) else {
19789                return;
19790            };
19791
19792            let new_inline_diagnostics = cx
19793                .background_spawn(async move {
19794                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19795                    for diagnostic_entry in
19796                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19797                    {
19798                        let message = diagnostic_entry
19799                            .diagnostic
19800                            .message
19801                            .split_once('\n')
19802                            .map(|(line, _)| line)
19803                            .map(SharedString::new)
19804                            .unwrap_or_else(|| {
19805                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19806                            });
19807                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19808                        let (Ok(i) | Err(i)) = inline_diagnostics
19809                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19810                        inline_diagnostics.insert(
19811                            i,
19812                            (
19813                                start_anchor,
19814                                InlineDiagnostic {
19815                                    message,
19816                                    group_id: diagnostic_entry.diagnostic.group_id,
19817                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19818                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19819                                    severity: diagnostic_entry.diagnostic.severity,
19820                                },
19821                            ),
19822                        );
19823                    }
19824                    inline_diagnostics
19825                })
19826                .await;
19827
19828            editor
19829                .update(cx, |editor, cx| {
19830                    editor.inline_diagnostics = new_inline_diagnostics;
19831                    cx.notify();
19832                })
19833                .ok();
19834        });
19835    }
19836
19837    fn pull_diagnostics(
19838        &mut self,
19839        buffer_id: BufferId,
19840        _window: &Window,
19841        cx: &mut Context<Self>,
19842    ) -> Option<()> {
19843        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19844        // skip any LSP updates for it.
19845
19846        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19847            return None;
19848        }
19849        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19850            .diagnostics
19851            .lsp_pull_diagnostics;
19852        if !pull_diagnostics_settings.enabled {
19853            return None;
19854        }
19855        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19856        let project = self.project()?.downgrade();
19857        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19858
19859        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19860            cx.background_executor().timer(debounce).await;
19861            if let Ok(task) = project.update(cx, |project, cx| {
19862                project.lsp_store().update(cx, |lsp_store, cx| {
19863                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19864                })
19865            }) {
19866                task.await.log_err();
19867            }
19868            project
19869                .update(cx, |project, cx| {
19870                    project.lsp_store().update(cx, |lsp_store, cx| {
19871                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19872                    })
19873                })
19874                .log_err();
19875        });
19876
19877        Some(())
19878    }
19879
19880    pub fn set_selections_from_remote(
19881        &mut self,
19882        selections: Vec<Selection<Anchor>>,
19883        pending_selection: Option<Selection<Anchor>>,
19884        window: &mut Window,
19885        cx: &mut Context<Self>,
19886    ) {
19887        let old_cursor_position = self.selections.newest_anchor().head();
19888        self.selections
19889            .change_with(&self.display_snapshot(cx), |s| {
19890                s.select_anchors(selections);
19891                if let Some(pending_selection) = pending_selection {
19892                    s.set_pending(pending_selection, SelectMode::Character);
19893                } else {
19894                    s.clear_pending();
19895                }
19896            });
19897        self.selections_did_change(
19898            false,
19899            &old_cursor_position,
19900            SelectionEffects::default(),
19901            window,
19902            cx,
19903        );
19904    }
19905
19906    pub fn transact(
19907        &mut self,
19908        window: &mut Window,
19909        cx: &mut Context<Self>,
19910        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19911    ) -> Option<TransactionId> {
19912        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19913            this.start_transaction_at(Instant::now(), window, cx);
19914            update(this, window, cx);
19915            this.end_transaction_at(Instant::now(), cx)
19916        })
19917    }
19918
19919    pub fn start_transaction_at(
19920        &mut self,
19921        now: Instant,
19922        window: &mut Window,
19923        cx: &mut Context<Self>,
19924    ) -> Option<TransactionId> {
19925        self.end_selection(window, cx);
19926        if let Some(tx_id) = self
19927            .buffer
19928            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19929        {
19930            self.selection_history
19931                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19932            cx.emit(EditorEvent::TransactionBegun {
19933                transaction_id: tx_id,
19934            });
19935            Some(tx_id)
19936        } else {
19937            None
19938        }
19939    }
19940
19941    pub fn end_transaction_at(
19942        &mut self,
19943        now: Instant,
19944        cx: &mut Context<Self>,
19945    ) -> Option<TransactionId> {
19946        if let Some(transaction_id) = self
19947            .buffer
19948            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19949        {
19950            if let Some((_, end_selections)) =
19951                self.selection_history.transaction_mut(transaction_id)
19952            {
19953                *end_selections = Some(self.selections.disjoint_anchors_arc());
19954            } else {
19955                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19956            }
19957
19958            cx.emit(EditorEvent::Edited { transaction_id });
19959            Some(transaction_id)
19960        } else {
19961            None
19962        }
19963    }
19964
19965    pub fn modify_transaction_selection_history(
19966        &mut self,
19967        transaction_id: TransactionId,
19968        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19969    ) -> bool {
19970        self.selection_history
19971            .transaction_mut(transaction_id)
19972            .map(modify)
19973            .is_some()
19974    }
19975
19976    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19977        if self.selection_mark_mode {
19978            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19979                s.move_with(&mut |_, sel| {
19980                    sel.collapse_to(sel.head(), SelectionGoal::None);
19981                });
19982            })
19983        }
19984        self.selection_mark_mode = true;
19985        cx.notify();
19986    }
19987
19988    pub fn swap_selection_ends(
19989        &mut self,
19990        _: &actions::SwapSelectionEnds,
19991        window: &mut Window,
19992        cx: &mut Context<Self>,
19993    ) {
19994        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19995            s.move_with(&mut |_, sel| {
19996                if sel.start != sel.end {
19997                    sel.reversed = !sel.reversed
19998                }
19999            });
20000        });
20001        self.request_autoscroll(Autoscroll::newest(), cx);
20002        cx.notify();
20003    }
20004
20005    pub fn toggle_focus(
20006        workspace: &mut Workspace,
20007        _: &actions::ToggleFocus,
20008        window: &mut Window,
20009        cx: &mut Context<Workspace>,
20010    ) {
20011        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20012            return;
20013        };
20014        workspace.activate_item(&item, true, true, window, cx);
20015    }
20016
20017    pub fn toggle_fold(
20018        &mut self,
20019        _: &actions::ToggleFold,
20020        window: &mut Window,
20021        cx: &mut Context<Self>,
20022    ) {
20023        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20024            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20025            let selection = self.selections.newest::<Point>(&display_map);
20026
20027            let range = if selection.is_empty() {
20028                let point = selection.head().to_display_point(&display_map);
20029                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20030                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20031                    .to_point(&display_map);
20032                start..end
20033            } else {
20034                selection.range()
20035            };
20036            if display_map.folds_in_range(range).next().is_some() {
20037                self.unfold_lines(&Default::default(), window, cx)
20038            } else {
20039                self.fold(&Default::default(), window, cx)
20040            }
20041        } else {
20042            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20043            let buffer_ids: HashSet<_> = self
20044                .selections
20045                .disjoint_anchor_ranges()
20046                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20047                .collect();
20048
20049            let should_unfold = buffer_ids
20050                .iter()
20051                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20052
20053            for buffer_id in buffer_ids {
20054                if should_unfold {
20055                    self.unfold_buffer(buffer_id, cx);
20056                } else {
20057                    self.fold_buffer(buffer_id, cx);
20058                }
20059            }
20060        }
20061    }
20062
20063    pub fn toggle_fold_recursive(
20064        &mut self,
20065        _: &actions::ToggleFoldRecursive,
20066        window: &mut Window,
20067        cx: &mut Context<Self>,
20068    ) {
20069        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20070
20071        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20072        let range = if selection.is_empty() {
20073            let point = selection.head().to_display_point(&display_map);
20074            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20075            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20076                .to_point(&display_map);
20077            start..end
20078        } else {
20079            selection.range()
20080        };
20081        if display_map.folds_in_range(range).next().is_some() {
20082            self.unfold_recursive(&Default::default(), window, cx)
20083        } else {
20084            self.fold_recursive(&Default::default(), window, cx)
20085        }
20086    }
20087
20088    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20089        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20090            let mut to_fold = Vec::new();
20091            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20092            let selections = self.selections.all_adjusted(&display_map);
20093
20094            for selection in selections {
20095                let range = selection.range().sorted();
20096                let buffer_start_row = range.start.row;
20097
20098                if range.start.row != range.end.row {
20099                    let mut found = false;
20100                    let mut row = range.start.row;
20101                    while row <= range.end.row {
20102                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20103                        {
20104                            found = true;
20105                            row = crease.range().end.row + 1;
20106                            to_fold.push(crease);
20107                        } else {
20108                            row += 1
20109                        }
20110                    }
20111                    if found {
20112                        continue;
20113                    }
20114                }
20115
20116                for row in (0..=range.start.row).rev() {
20117                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20118                        && crease.range().end.row >= buffer_start_row
20119                    {
20120                        to_fold.push(crease);
20121                        if row <= range.start.row {
20122                            break;
20123                        }
20124                    }
20125                }
20126            }
20127
20128            self.fold_creases(to_fold, true, window, cx);
20129        } else {
20130            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20131            let buffer_ids = self
20132                .selections
20133                .disjoint_anchor_ranges()
20134                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20135                .collect::<HashSet<_>>();
20136            for buffer_id in buffer_ids {
20137                self.fold_buffer(buffer_id, cx);
20138            }
20139        }
20140    }
20141
20142    pub fn toggle_fold_all(
20143        &mut self,
20144        _: &actions::ToggleFoldAll,
20145        window: &mut Window,
20146        cx: &mut Context<Self>,
20147    ) {
20148        let has_folds = if self.buffer.read(cx).is_singleton() {
20149            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20150            let has_folds = display_map
20151                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20152                .next()
20153                .is_some();
20154            has_folds
20155        } else {
20156            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
20157            let has_folds = buffer_ids
20158                .iter()
20159                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20160            has_folds
20161        };
20162
20163        if has_folds {
20164            self.unfold_all(&actions::UnfoldAll, window, cx);
20165        } else {
20166            self.fold_all(&actions::FoldAll, window, cx);
20167        }
20168    }
20169
20170    fn fold_at_level(
20171        &mut self,
20172        fold_at: &FoldAtLevel,
20173        window: &mut Window,
20174        cx: &mut Context<Self>,
20175    ) {
20176        if !self.buffer.read(cx).is_singleton() {
20177            return;
20178        }
20179
20180        let fold_at_level = fold_at.0;
20181        let snapshot = self.buffer.read(cx).snapshot(cx);
20182        let mut to_fold = Vec::new();
20183        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20184
20185        let row_ranges_to_keep: Vec<Range<u32>> = self
20186            .selections
20187            .all::<Point>(&self.display_snapshot(cx))
20188            .into_iter()
20189            .map(|sel| sel.start.row..sel.end.row)
20190            .collect();
20191
20192        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20193            while start_row < end_row {
20194                match self
20195                    .snapshot(window, cx)
20196                    .crease_for_buffer_row(MultiBufferRow(start_row))
20197                {
20198                    Some(crease) => {
20199                        let nested_start_row = crease.range().start.row + 1;
20200                        let nested_end_row = crease.range().end.row;
20201
20202                        if current_level < fold_at_level {
20203                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20204                        } else if current_level == fold_at_level {
20205                            // Fold iff there is no selection completely contained within the fold region
20206                            if !row_ranges_to_keep.iter().any(|selection| {
20207                                selection.end >= nested_start_row
20208                                    && selection.start <= nested_end_row
20209                            }) {
20210                                to_fold.push(crease);
20211                            }
20212                        }
20213
20214                        start_row = nested_end_row + 1;
20215                    }
20216                    None => start_row += 1,
20217                }
20218            }
20219        }
20220
20221        self.fold_creases(to_fold, true, window, cx);
20222    }
20223
20224    pub fn fold_at_level_1(
20225        &mut self,
20226        _: &actions::FoldAtLevel1,
20227        window: &mut Window,
20228        cx: &mut Context<Self>,
20229    ) {
20230        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20231    }
20232
20233    pub fn fold_at_level_2(
20234        &mut self,
20235        _: &actions::FoldAtLevel2,
20236        window: &mut Window,
20237        cx: &mut Context<Self>,
20238    ) {
20239        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20240    }
20241
20242    pub fn fold_at_level_3(
20243        &mut self,
20244        _: &actions::FoldAtLevel3,
20245        window: &mut Window,
20246        cx: &mut Context<Self>,
20247    ) {
20248        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20249    }
20250
20251    pub fn fold_at_level_4(
20252        &mut self,
20253        _: &actions::FoldAtLevel4,
20254        window: &mut Window,
20255        cx: &mut Context<Self>,
20256    ) {
20257        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20258    }
20259
20260    pub fn fold_at_level_5(
20261        &mut self,
20262        _: &actions::FoldAtLevel5,
20263        window: &mut Window,
20264        cx: &mut Context<Self>,
20265    ) {
20266        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20267    }
20268
20269    pub fn fold_at_level_6(
20270        &mut self,
20271        _: &actions::FoldAtLevel6,
20272        window: &mut Window,
20273        cx: &mut Context<Self>,
20274    ) {
20275        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20276    }
20277
20278    pub fn fold_at_level_7(
20279        &mut self,
20280        _: &actions::FoldAtLevel7,
20281        window: &mut Window,
20282        cx: &mut Context<Self>,
20283    ) {
20284        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20285    }
20286
20287    pub fn fold_at_level_8(
20288        &mut self,
20289        _: &actions::FoldAtLevel8,
20290        window: &mut Window,
20291        cx: &mut Context<Self>,
20292    ) {
20293        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20294    }
20295
20296    pub fn fold_at_level_9(
20297        &mut self,
20298        _: &actions::FoldAtLevel9,
20299        window: &mut Window,
20300        cx: &mut Context<Self>,
20301    ) {
20302        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20303    }
20304
20305    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20306        if self.buffer.read(cx).is_singleton() {
20307            let mut fold_ranges = Vec::new();
20308            let snapshot = self.buffer.read(cx).snapshot(cx);
20309
20310            for row in 0..snapshot.max_row().0 {
20311                if let Some(foldable_range) = self
20312                    .snapshot(window, cx)
20313                    .crease_for_buffer_row(MultiBufferRow(row))
20314                {
20315                    fold_ranges.push(foldable_range);
20316                }
20317            }
20318
20319            self.fold_creases(fold_ranges, true, window, cx);
20320        } else {
20321            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20322                editor
20323                    .update_in(cx, |editor, _, cx| {
20324                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20325                            editor.fold_buffer(buffer_id, cx);
20326                        }
20327                    })
20328                    .ok();
20329            });
20330        }
20331    }
20332
20333    pub fn fold_function_bodies(
20334        &mut self,
20335        _: &actions::FoldFunctionBodies,
20336        window: &mut Window,
20337        cx: &mut Context<Self>,
20338    ) {
20339        let snapshot = self.buffer.read(cx).snapshot(cx);
20340
20341        let ranges = snapshot
20342            .text_object_ranges(
20343                MultiBufferOffset(0)..snapshot.len(),
20344                TreeSitterOptions::default(),
20345            )
20346            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20347            .collect::<Vec<_>>();
20348
20349        let creases = ranges
20350            .into_iter()
20351            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20352            .collect();
20353
20354        self.fold_creases(creases, true, window, cx);
20355    }
20356
20357    pub fn fold_recursive(
20358        &mut self,
20359        _: &actions::FoldRecursive,
20360        window: &mut Window,
20361        cx: &mut Context<Self>,
20362    ) {
20363        let mut to_fold = Vec::new();
20364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20365        let selections = self.selections.all_adjusted(&display_map);
20366
20367        for selection in selections {
20368            let range = selection.range().sorted();
20369            let buffer_start_row = range.start.row;
20370
20371            if range.start.row != range.end.row {
20372                let mut found = false;
20373                for row in range.start.row..=range.end.row {
20374                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20375                        found = true;
20376                        to_fold.push(crease);
20377                    }
20378                }
20379                if found {
20380                    continue;
20381                }
20382            }
20383
20384            for row in (0..=range.start.row).rev() {
20385                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20386                    if crease.range().end.row >= buffer_start_row {
20387                        to_fold.push(crease);
20388                    } else {
20389                        break;
20390                    }
20391                }
20392            }
20393        }
20394
20395        self.fold_creases(to_fold, true, window, cx);
20396    }
20397
20398    pub fn fold_at(
20399        &mut self,
20400        buffer_row: MultiBufferRow,
20401        window: &mut Window,
20402        cx: &mut Context<Self>,
20403    ) {
20404        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20405
20406        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20407            let autoscroll = self
20408                .selections
20409                .all::<Point>(&display_map)
20410                .iter()
20411                .any(|selection| crease.range().overlaps(&selection.range()));
20412
20413            self.fold_creases(vec![crease], autoscroll, window, cx);
20414        }
20415    }
20416
20417    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20418        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20419            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20420            let buffer = display_map.buffer_snapshot();
20421            let selections = self.selections.all::<Point>(&display_map);
20422            let ranges = selections
20423                .iter()
20424                .map(|s| {
20425                    let range = s.display_range(&display_map).sorted();
20426                    let mut start = range.start.to_point(&display_map);
20427                    let mut end = range.end.to_point(&display_map);
20428                    start.column = 0;
20429                    end.column = buffer.line_len(MultiBufferRow(end.row));
20430                    start..end
20431                })
20432                .collect::<Vec<_>>();
20433
20434            self.unfold_ranges(&ranges, true, true, cx);
20435        } else {
20436            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20437            let buffer_ids = self
20438                .selections
20439                .disjoint_anchor_ranges()
20440                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20441                .collect::<HashSet<_>>();
20442            for buffer_id in buffer_ids {
20443                self.unfold_buffer(buffer_id, cx);
20444            }
20445        }
20446    }
20447
20448    pub fn unfold_recursive(
20449        &mut self,
20450        _: &UnfoldRecursive,
20451        _window: &mut Window,
20452        cx: &mut Context<Self>,
20453    ) {
20454        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20455        let selections = self.selections.all::<Point>(&display_map);
20456        let ranges = selections
20457            .iter()
20458            .map(|s| {
20459                let mut range = s.display_range(&display_map).sorted();
20460                *range.start.column_mut() = 0;
20461                *range.end.column_mut() = display_map.line_len(range.end.row());
20462                let start = range.start.to_point(&display_map);
20463                let end = range.end.to_point(&display_map);
20464                start..end
20465            })
20466            .collect::<Vec<_>>();
20467
20468        self.unfold_ranges(&ranges, true, true, cx);
20469    }
20470
20471    pub fn unfold_at(
20472        &mut self,
20473        buffer_row: MultiBufferRow,
20474        _window: &mut Window,
20475        cx: &mut Context<Self>,
20476    ) {
20477        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20478
20479        let intersection_range = Point::new(buffer_row.0, 0)
20480            ..Point::new(
20481                buffer_row.0,
20482                display_map.buffer_snapshot().line_len(buffer_row),
20483            );
20484
20485        let autoscroll = self
20486            .selections
20487            .all::<Point>(&display_map)
20488            .iter()
20489            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20490
20491        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20492    }
20493
20494    pub fn unfold_all(
20495        &mut self,
20496        _: &actions::UnfoldAll,
20497        _window: &mut Window,
20498        cx: &mut Context<Self>,
20499    ) {
20500        if self.buffer.read(cx).is_singleton() {
20501            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20502            self.unfold_ranges(
20503                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20504                true,
20505                true,
20506                cx,
20507            );
20508        } else {
20509            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20510                editor
20511                    .update(cx, |editor, cx| {
20512                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20513                            editor.unfold_buffer(buffer_id, cx);
20514                        }
20515                    })
20516                    .ok();
20517            });
20518        }
20519    }
20520
20521    pub fn fold_selected_ranges(
20522        &mut self,
20523        _: &FoldSelectedRanges,
20524        window: &mut Window,
20525        cx: &mut Context<Self>,
20526    ) {
20527        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20528        let selections = self.selections.all_adjusted(&display_map);
20529        let ranges = selections
20530            .into_iter()
20531            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20532            .collect::<Vec<_>>();
20533        self.fold_creases(ranges, true, window, cx);
20534    }
20535
20536    pub fn fold_ranges<T: ToOffset + Clone>(
20537        &mut self,
20538        ranges: Vec<Range<T>>,
20539        auto_scroll: bool,
20540        window: &mut Window,
20541        cx: &mut Context<Self>,
20542    ) {
20543        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20544        let ranges = ranges
20545            .into_iter()
20546            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20547            .collect::<Vec<_>>();
20548        self.fold_creases(ranges, auto_scroll, window, cx);
20549    }
20550
20551    pub fn fold_creases<T: ToOffset + Clone>(
20552        &mut self,
20553        creases: Vec<Crease<T>>,
20554        auto_scroll: bool,
20555        window: &mut Window,
20556        cx: &mut Context<Self>,
20557    ) {
20558        if creases.is_empty() {
20559            return;
20560        }
20561
20562        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20563
20564        if auto_scroll {
20565            self.request_autoscroll(Autoscroll::fit(), cx);
20566        }
20567
20568        cx.notify();
20569
20570        self.scrollbar_marker_state.dirty = true;
20571        self.update_data_on_scroll(window, cx);
20572        self.folds_did_change(cx);
20573    }
20574
20575    /// Removes any folds whose ranges intersect any of the given ranges.
20576    pub fn unfold_ranges<T: ToOffset + Clone>(
20577        &mut self,
20578        ranges: &[Range<T>],
20579        inclusive: bool,
20580        auto_scroll: bool,
20581        cx: &mut Context<Self>,
20582    ) {
20583        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20584            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20585        });
20586        self.folds_did_change(cx);
20587    }
20588
20589    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20590        self.fold_buffers([buffer_id], cx);
20591    }
20592
20593    pub fn fold_buffers(
20594        &mut self,
20595        buffer_ids: impl IntoIterator<Item = BufferId>,
20596        cx: &mut Context<Self>,
20597    ) {
20598        if self.buffer().read(cx).is_singleton() {
20599            return;
20600        }
20601
20602        let ids_to_fold: Vec<BufferId> = buffer_ids
20603            .into_iter()
20604            .filter(|id| !self.is_buffer_folded(*id, cx))
20605            .collect();
20606
20607        if ids_to_fold.is_empty() {
20608            return;
20609        }
20610
20611        let mut all_folded_excerpt_ids = Vec::new();
20612        for buffer_id in &ids_to_fold {
20613            let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(*buffer_id, cx);
20614            all_folded_excerpt_ids.extend(folded_excerpts.into_iter().map(|(id, _, _)| id));
20615        }
20616
20617        self.display_map.update(cx, |display_map, cx| {
20618            display_map.fold_buffers(ids_to_fold.clone(), cx)
20619        });
20620
20621        let snapshot = self.display_snapshot(cx);
20622        self.selections.change_with(&snapshot, |selections| {
20623            for buffer_id in ids_to_fold {
20624                selections.remove_selections_from_buffer(buffer_id);
20625            }
20626        });
20627
20628        cx.emit(EditorEvent::BufferFoldToggled {
20629            ids: all_folded_excerpt_ids,
20630            folded: true,
20631        });
20632        cx.notify();
20633    }
20634
20635    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20636        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20637            return;
20638        }
20639        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20640        self.display_map.update(cx, |display_map, cx| {
20641            display_map.unfold_buffers([buffer_id], cx);
20642        });
20643        cx.emit(EditorEvent::BufferFoldToggled {
20644            ids: unfolded_excerpts.iter().map(|&(id, _, _)| id).collect(),
20645            folded: false,
20646        });
20647        cx.notify();
20648    }
20649
20650    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20651        self.display_map.read(cx).is_buffer_folded(buffer)
20652    }
20653
20654    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20655        if self.buffer().read(cx).is_singleton() {
20656            return false;
20657        }
20658        !self.folded_buffers(cx).is_empty()
20659    }
20660
20661    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20662        self.display_map.read(cx).folded_buffers()
20663    }
20664
20665    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20666        self.display_map.update(cx, |display_map, cx| {
20667            display_map.disable_header_for_buffer(buffer_id, cx);
20668        });
20669        cx.notify();
20670    }
20671
20672    /// Removes any folds with the given ranges.
20673    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20674        &mut self,
20675        ranges: &[Range<T>],
20676        type_id: TypeId,
20677        auto_scroll: bool,
20678        cx: &mut Context<Self>,
20679    ) {
20680        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20681            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20682        });
20683        self.folds_did_change(cx);
20684    }
20685
20686    fn remove_folds_with<T: ToOffset + Clone>(
20687        &mut self,
20688        ranges: &[Range<T>],
20689        auto_scroll: bool,
20690        cx: &mut Context<Self>,
20691        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20692    ) {
20693        if ranges.is_empty() {
20694            return;
20695        }
20696
20697        let mut buffers_affected = HashSet::default();
20698        let multi_buffer = self.buffer().read(cx);
20699        for range in ranges {
20700            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20701                buffers_affected.insert(buffer.read(cx).remote_id());
20702            };
20703        }
20704
20705        self.display_map.update(cx, update);
20706
20707        if auto_scroll {
20708            self.request_autoscroll(Autoscroll::fit(), cx);
20709        }
20710
20711        cx.notify();
20712        self.scrollbar_marker_state.dirty = true;
20713        self.active_indent_guides_state.dirty = true;
20714    }
20715
20716    pub fn update_renderer_widths(
20717        &mut self,
20718        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20719        cx: &mut Context<Self>,
20720    ) -> bool {
20721        self.display_map
20722            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20723    }
20724
20725    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20726        self.display_map.read(cx).fold_placeholder.clone()
20727    }
20728
20729    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20730        self.buffer.update(cx, |buffer, cx| {
20731            buffer.set_all_diff_hunks_expanded(cx);
20732        });
20733    }
20734
20735    pub fn expand_all_diff_hunks(
20736        &mut self,
20737        _: &ExpandAllDiffHunks,
20738        _window: &mut Window,
20739        cx: &mut Context<Self>,
20740    ) {
20741        self.buffer.update(cx, |buffer, cx| {
20742            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20743        });
20744    }
20745
20746    pub fn collapse_all_diff_hunks(
20747        &mut self,
20748        _: &CollapseAllDiffHunks,
20749        _window: &mut Window,
20750        cx: &mut Context<Self>,
20751    ) {
20752        self.buffer.update(cx, |buffer, cx| {
20753            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20754        });
20755    }
20756
20757    pub fn toggle_selected_diff_hunks(
20758        &mut self,
20759        _: &ToggleSelectedDiffHunks,
20760        _window: &mut Window,
20761        cx: &mut Context<Self>,
20762    ) {
20763        let ranges: Vec<_> = self
20764            .selections
20765            .disjoint_anchors()
20766            .iter()
20767            .map(|s| s.range())
20768            .collect();
20769        self.toggle_diff_hunks_in_ranges(ranges, cx);
20770    }
20771
20772    pub fn diff_hunks_in_ranges<'a>(
20773        &'a self,
20774        ranges: &'a [Range<Anchor>],
20775        buffer: &'a MultiBufferSnapshot,
20776    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20777        ranges.iter().flat_map(move |range| {
20778            let end_excerpt_id = range.end.excerpt_id;
20779            let range = range.to_point(buffer);
20780            let mut peek_end = range.end;
20781            if range.end.row < buffer.max_row().0 {
20782                peek_end = Point::new(range.end.row + 1, 0);
20783            }
20784            buffer
20785                .diff_hunks_in_range(range.start..peek_end)
20786                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20787        })
20788    }
20789
20790    pub fn has_stageable_diff_hunks_in_ranges(
20791        &self,
20792        ranges: &[Range<Anchor>],
20793        snapshot: &MultiBufferSnapshot,
20794    ) -> bool {
20795        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20796        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20797    }
20798
20799    pub fn toggle_staged_selected_diff_hunks(
20800        &mut self,
20801        _: &::git::ToggleStaged,
20802        _: &mut Window,
20803        cx: &mut Context<Self>,
20804    ) {
20805        let snapshot = self.buffer.read(cx).snapshot(cx);
20806        let ranges: Vec<_> = self
20807            .selections
20808            .disjoint_anchors()
20809            .iter()
20810            .map(|s| s.range())
20811            .collect();
20812        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20813        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20814    }
20815
20816    pub fn set_render_diff_hunk_controls(
20817        &mut self,
20818        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20819        cx: &mut Context<Self>,
20820    ) {
20821        self.render_diff_hunk_controls = render_diff_hunk_controls;
20822        cx.notify();
20823    }
20824
20825    pub fn stage_and_next(
20826        &mut self,
20827        _: &::git::StageAndNext,
20828        window: &mut Window,
20829        cx: &mut Context<Self>,
20830    ) {
20831        self.do_stage_or_unstage_and_next(true, window, cx);
20832    }
20833
20834    pub fn unstage_and_next(
20835        &mut self,
20836        _: &::git::UnstageAndNext,
20837        window: &mut Window,
20838        cx: &mut Context<Self>,
20839    ) {
20840        self.do_stage_or_unstage_and_next(false, window, cx);
20841    }
20842
20843    pub fn stage_or_unstage_diff_hunks(
20844        &mut self,
20845        stage: bool,
20846        ranges: Vec<Range<Anchor>>,
20847        cx: &mut Context<Self>,
20848    ) {
20849        if self.delegate_stage_and_restore {
20850            let snapshot = self.buffer.read(cx).snapshot(cx);
20851            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20852            if !hunks.is_empty() {
20853                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20854            }
20855            return;
20856        }
20857        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20858        cx.spawn(async move |this, cx| {
20859            task.await?;
20860            this.update(cx, |this, cx| {
20861                let snapshot = this.buffer.read(cx).snapshot(cx);
20862                let chunk_by = this
20863                    .diff_hunks_in_ranges(&ranges, &snapshot)
20864                    .chunk_by(|hunk| hunk.buffer_id);
20865                for (buffer_id, hunks) in &chunk_by {
20866                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20867                }
20868            })
20869        })
20870        .detach_and_log_err(cx);
20871    }
20872
20873    fn save_buffers_for_ranges_if_needed(
20874        &mut self,
20875        ranges: &[Range<Anchor>],
20876        cx: &mut Context<Editor>,
20877    ) -> Task<Result<()>> {
20878        let multibuffer = self.buffer.read(cx);
20879        let snapshot = multibuffer.read(cx);
20880        let buffer_ids: HashSet<_> = ranges
20881            .iter()
20882            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20883            .collect();
20884        drop(snapshot);
20885
20886        let mut buffers = HashSet::default();
20887        for buffer_id in buffer_ids {
20888            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20889                let buffer = buffer_entity.read(cx);
20890                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20891                {
20892                    buffers.insert(buffer_entity);
20893                }
20894            }
20895        }
20896
20897        if let Some(project) = &self.project {
20898            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20899        } else {
20900            Task::ready(Ok(()))
20901        }
20902    }
20903
20904    fn do_stage_or_unstage_and_next(
20905        &mut self,
20906        stage: bool,
20907        window: &mut Window,
20908        cx: &mut Context<Self>,
20909    ) {
20910        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20911
20912        if ranges.iter().any(|range| range.start != range.end) {
20913            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20914            return;
20915        }
20916
20917        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20918
20919        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20920        let wrap_around = !all_diff_hunks_expanded;
20921        let snapshot = self.snapshot(window, cx);
20922        let position = self
20923            .selections
20924            .newest::<Point>(&snapshot.display_snapshot)
20925            .head();
20926
20927        self.go_to_hunk_before_or_after_position(
20928            &snapshot,
20929            position,
20930            Direction::Next,
20931            wrap_around,
20932            window,
20933            cx,
20934        );
20935    }
20936
20937    pub(crate) fn do_stage_or_unstage(
20938        &self,
20939        stage: bool,
20940        buffer_id: BufferId,
20941        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20942        cx: &mut App,
20943    ) -> Option<()> {
20944        let project = self.project()?;
20945        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20946        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20947        let buffer_snapshot = buffer.read(cx).snapshot();
20948        let file_exists = buffer_snapshot
20949            .file()
20950            .is_some_and(|file| file.disk_state().exists());
20951        diff.update(cx, |diff, cx| {
20952            diff.stage_or_unstage_hunks(
20953                stage,
20954                &hunks
20955                    .map(|hunk| buffer_diff::DiffHunk {
20956                        buffer_range: hunk.buffer_range,
20957                        // We don't need to pass in word diffs here because they're only used for rendering and
20958                        // this function changes internal state
20959                        base_word_diffs: Vec::default(),
20960                        buffer_word_diffs: Vec::default(),
20961                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20962                            ..hunk.diff_base_byte_range.end.0,
20963                        secondary_status: hunk.status.secondary,
20964                        range: Point::zero()..Point::zero(), // unused
20965                    })
20966                    .collect::<Vec<_>>(),
20967                &buffer_snapshot,
20968                file_exists,
20969                cx,
20970            )
20971        });
20972        None
20973    }
20974
20975    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20976        let ranges: Vec<_> = self
20977            .selections
20978            .disjoint_anchors()
20979            .iter()
20980            .map(|s| s.range())
20981            .collect();
20982        self.buffer
20983            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20984    }
20985
20986    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20987        self.buffer.update(cx, |buffer, cx| {
20988            let ranges = vec![Anchor::min()..Anchor::max()];
20989            if !buffer.all_diff_hunks_expanded()
20990                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20991            {
20992                buffer.collapse_diff_hunks(ranges, cx);
20993                true
20994            } else {
20995                false
20996            }
20997        })
20998    }
20999
21000    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21001        if self.buffer.read(cx).all_diff_hunks_expanded() {
21002            return true;
21003        }
21004        let ranges = vec![Anchor::min()..Anchor::max()];
21005        self.buffer
21006            .read(cx)
21007            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21008    }
21009
21010    fn toggle_diff_hunks_in_ranges(
21011        &mut self,
21012        ranges: Vec<Range<Anchor>>,
21013        cx: &mut Context<Editor>,
21014    ) {
21015        self.buffer.update(cx, |buffer, cx| {
21016            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21017            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21018        })
21019    }
21020
21021    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21022        self.buffer.update(cx, |buffer, cx| {
21023            buffer.toggle_single_diff_hunk(range, cx);
21024        })
21025    }
21026
21027    pub(crate) fn apply_all_diff_hunks(
21028        &mut self,
21029        _: &ApplyAllDiffHunks,
21030        window: &mut Window,
21031        cx: &mut Context<Self>,
21032    ) {
21033        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21034
21035        let buffers = self.buffer.read(cx).all_buffers();
21036        for branch_buffer in buffers {
21037            branch_buffer.update(cx, |branch_buffer, cx| {
21038                branch_buffer.merge_into_base(Vec::new(), cx);
21039            });
21040        }
21041
21042        if let Some(project) = self.project.clone() {
21043            self.save(
21044                SaveOptions {
21045                    format: true,
21046                    autosave: false,
21047                },
21048                project,
21049                window,
21050                cx,
21051            )
21052            .detach_and_log_err(cx);
21053        }
21054    }
21055
21056    pub(crate) fn apply_selected_diff_hunks(
21057        &mut self,
21058        _: &ApplyDiffHunk,
21059        window: &mut Window,
21060        cx: &mut Context<Self>,
21061    ) {
21062        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21063        let snapshot = self.snapshot(window, cx);
21064        let hunks = snapshot.hunks_for_ranges(
21065            self.selections
21066                .all(&snapshot.display_snapshot)
21067                .into_iter()
21068                .map(|selection| selection.range()),
21069        );
21070        let mut ranges_by_buffer = HashMap::default();
21071        self.transact(window, cx, |editor, _window, cx| {
21072            for hunk in hunks {
21073                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21074                    ranges_by_buffer
21075                        .entry(buffer.clone())
21076                        .or_insert_with(Vec::new)
21077                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21078                }
21079            }
21080
21081            for (buffer, ranges) in ranges_by_buffer {
21082                buffer.update(cx, |buffer, cx| {
21083                    buffer.merge_into_base(ranges, cx);
21084                });
21085            }
21086        });
21087
21088        if let Some(project) = self.project.clone() {
21089            self.save(
21090                SaveOptions {
21091                    format: true,
21092                    autosave: false,
21093                },
21094                project,
21095                window,
21096                cx,
21097            )
21098            .detach_and_log_err(cx);
21099        }
21100    }
21101
21102    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21103        if hovered != self.gutter_hovered {
21104            self.gutter_hovered = hovered;
21105            cx.notify();
21106        }
21107    }
21108
21109    pub fn insert_blocks(
21110        &mut self,
21111        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21112        autoscroll: Option<Autoscroll>,
21113        cx: &mut Context<Self>,
21114    ) -> Vec<CustomBlockId> {
21115        let blocks = self
21116            .display_map
21117            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21118        if let Some(autoscroll) = autoscroll {
21119            self.request_autoscroll(autoscroll, cx);
21120        }
21121        cx.notify();
21122        blocks
21123    }
21124
21125    pub fn resize_blocks(
21126        &mut self,
21127        heights: HashMap<CustomBlockId, u32>,
21128        autoscroll: Option<Autoscroll>,
21129        cx: &mut Context<Self>,
21130    ) {
21131        self.display_map
21132            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21133        if let Some(autoscroll) = autoscroll {
21134            self.request_autoscroll(autoscroll, cx);
21135        }
21136        cx.notify();
21137    }
21138
21139    pub fn replace_blocks(
21140        &mut self,
21141        renderers: HashMap<CustomBlockId, RenderBlock>,
21142        autoscroll: Option<Autoscroll>,
21143        cx: &mut Context<Self>,
21144    ) {
21145        self.display_map
21146            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21147        if let Some(autoscroll) = autoscroll {
21148            self.request_autoscroll(autoscroll, cx);
21149        }
21150        cx.notify();
21151    }
21152
21153    pub fn remove_blocks(
21154        &mut self,
21155        block_ids: HashSet<CustomBlockId>,
21156        autoscroll: Option<Autoscroll>,
21157        cx: &mut Context<Self>,
21158    ) {
21159        self.display_map.update(cx, |display_map, cx| {
21160            display_map.remove_blocks(block_ids, cx)
21161        });
21162        if let Some(autoscroll) = autoscroll {
21163            self.request_autoscroll(autoscroll, cx);
21164        }
21165        cx.notify();
21166    }
21167
21168    pub fn row_for_block(
21169        &self,
21170        block_id: CustomBlockId,
21171        cx: &mut Context<Self>,
21172    ) -> Option<DisplayRow> {
21173        self.display_map
21174            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21175    }
21176
21177    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21178        self.focused_block = Some(focused_block);
21179    }
21180
21181    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21182        self.focused_block.take()
21183    }
21184
21185    pub fn insert_creases(
21186        &mut self,
21187        creases: impl IntoIterator<Item = Crease<Anchor>>,
21188        cx: &mut Context<Self>,
21189    ) -> Vec<CreaseId> {
21190        self.display_map
21191            .update(cx, |map, cx| map.insert_creases(creases, cx))
21192    }
21193
21194    pub fn remove_creases(
21195        &mut self,
21196        ids: impl IntoIterator<Item = CreaseId>,
21197        cx: &mut Context<Self>,
21198    ) -> Vec<(CreaseId, Range<Anchor>)> {
21199        self.display_map
21200            .update(cx, |map, cx| map.remove_creases(ids, cx))
21201    }
21202
21203    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21204        self.display_map
21205            .update(cx, |map, cx| map.snapshot(cx))
21206            .longest_row()
21207    }
21208
21209    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21210        self.display_map
21211            .update(cx, |map, cx| map.snapshot(cx))
21212            .max_point()
21213    }
21214
21215    pub fn text(&self, cx: &App) -> String {
21216        self.buffer.read(cx).read(cx).text()
21217    }
21218
21219    pub fn is_empty(&self, cx: &App) -> bool {
21220        self.buffer.read(cx).read(cx).is_empty()
21221    }
21222
21223    pub fn text_option(&self, cx: &App) -> Option<String> {
21224        let text = self.text(cx);
21225        let text = text.trim();
21226
21227        if text.is_empty() {
21228            return None;
21229        }
21230
21231        Some(text.to_string())
21232    }
21233
21234    pub fn set_text(
21235        &mut self,
21236        text: impl Into<Arc<str>>,
21237        window: &mut Window,
21238        cx: &mut Context<Self>,
21239    ) {
21240        self.transact(window, cx, |this, _, cx| {
21241            this.buffer
21242                .read(cx)
21243                .as_singleton()
21244                .expect("you can only call set_text on editors for singleton buffers")
21245                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21246        });
21247    }
21248
21249    pub fn display_text(&self, cx: &mut App) -> String {
21250        self.display_map
21251            .update(cx, |map, cx| map.snapshot(cx))
21252            .text()
21253    }
21254
21255    fn create_minimap(
21256        &self,
21257        minimap_settings: MinimapSettings,
21258        window: &mut Window,
21259        cx: &mut Context<Self>,
21260    ) -> Option<Entity<Self>> {
21261        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21262            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21263    }
21264
21265    fn initialize_new_minimap(
21266        &self,
21267        minimap_settings: MinimapSettings,
21268        window: &mut Window,
21269        cx: &mut Context<Self>,
21270    ) -> Entity<Self> {
21271        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21272        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21273
21274        let mut minimap = Editor::new_internal(
21275            EditorMode::Minimap {
21276                parent: cx.weak_entity(),
21277            },
21278            self.buffer.clone(),
21279            None,
21280            Some(self.display_map.clone()),
21281            window,
21282            cx,
21283        );
21284        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21285        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21286        minimap.scroll_manager.clone_state(
21287            &self.scroll_manager,
21288            &my_snapshot,
21289            &minimap_snapshot,
21290            cx,
21291        );
21292        minimap.set_text_style_refinement(TextStyleRefinement {
21293            font_size: Some(MINIMAP_FONT_SIZE),
21294            font_weight: Some(MINIMAP_FONT_WEIGHT),
21295            font_family: Some(MINIMAP_FONT_FAMILY),
21296            ..Default::default()
21297        });
21298        minimap.update_minimap_configuration(minimap_settings, cx);
21299        cx.new(|_| minimap)
21300    }
21301
21302    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21303        let current_line_highlight = minimap_settings
21304            .current_line_highlight
21305            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21306        self.set_current_line_highlight(Some(current_line_highlight));
21307    }
21308
21309    pub fn minimap(&self) -> Option<&Entity<Self>> {
21310        self.minimap
21311            .as_ref()
21312            .filter(|_| self.minimap_visibility.visible())
21313    }
21314
21315    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21316        let mut wrap_guides = smallvec![];
21317
21318        if self.show_wrap_guides == Some(false) {
21319            return wrap_guides;
21320        }
21321
21322        let settings = self.buffer.read(cx).language_settings(cx);
21323        if settings.show_wrap_guides {
21324            match self.soft_wrap_mode(cx) {
21325                SoftWrap::Column(soft_wrap) => {
21326                    wrap_guides.push((soft_wrap as usize, true));
21327                }
21328                SoftWrap::Bounded(soft_wrap) => {
21329                    wrap_guides.push((soft_wrap as usize, true));
21330                }
21331                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21332            }
21333            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21334        }
21335
21336        wrap_guides
21337    }
21338
21339    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21340        let settings = self.buffer.read(cx).language_settings(cx);
21341        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21342        match mode {
21343            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21344                SoftWrap::None
21345            }
21346            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21347            language_settings::SoftWrap::PreferredLineLength => {
21348                SoftWrap::Column(settings.preferred_line_length)
21349            }
21350            language_settings::SoftWrap::Bounded => {
21351                SoftWrap::Bounded(settings.preferred_line_length)
21352            }
21353        }
21354    }
21355
21356    pub fn set_soft_wrap_mode(
21357        &mut self,
21358        mode: language_settings::SoftWrap,
21359        cx: &mut Context<Self>,
21360    ) {
21361        self.soft_wrap_mode_override = Some(mode);
21362        cx.notify();
21363    }
21364
21365    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21366        self.hard_wrap = hard_wrap;
21367        cx.notify();
21368    }
21369
21370    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21371        self.text_style_refinement = Some(style);
21372    }
21373
21374    /// called by the Element so we know what style we were most recently rendered with.
21375    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21376        // We intentionally do not inform the display map about the minimap style
21377        // so that wrapping is not recalculated and stays consistent for the editor
21378        // and its linked minimap.
21379        if !self.mode.is_minimap() {
21380            let font = style.text.font();
21381            let font_size = style.text.font_size.to_pixels(window.rem_size());
21382            let display_map = self
21383                .placeholder_display_map
21384                .as_ref()
21385                .filter(|_| self.is_empty(cx))
21386                .unwrap_or(&self.display_map);
21387
21388            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21389        }
21390        self.style = Some(style);
21391    }
21392
21393    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21394        if self.style.is_none() {
21395            self.style = Some(self.create_style(cx));
21396        }
21397        self.style.as_ref().unwrap()
21398    }
21399
21400    // Called by the element. This method is not designed to be called outside of the editor
21401    // element's layout code because it does not notify when rewrapping is computed synchronously.
21402    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21403        if self.is_empty(cx) {
21404            self.placeholder_display_map
21405                .as_ref()
21406                .map_or(false, |display_map| {
21407                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21408                })
21409        } else {
21410            self.display_map
21411                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21412        }
21413    }
21414
21415    pub fn set_soft_wrap(&mut self) {
21416        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21417    }
21418
21419    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21420        if self.soft_wrap_mode_override.is_some() {
21421            self.soft_wrap_mode_override.take();
21422        } else {
21423            let soft_wrap = match self.soft_wrap_mode(cx) {
21424                SoftWrap::GitDiff => return,
21425                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21426                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21427                    language_settings::SoftWrap::None
21428                }
21429            };
21430            self.soft_wrap_mode_override = Some(soft_wrap);
21431        }
21432        cx.notify();
21433    }
21434
21435    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21436        let Some(workspace) = self.workspace() else {
21437            return;
21438        };
21439        let fs = workspace.read(cx).app_state().fs.clone();
21440        let current_show = TabBarSettings::get_global(cx).show;
21441        update_settings_file(fs, cx, move |setting, _| {
21442            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21443        });
21444    }
21445
21446    pub fn toggle_indent_guides(
21447        &mut self,
21448        _: &ToggleIndentGuides,
21449        _: &mut Window,
21450        cx: &mut Context<Self>,
21451    ) {
21452        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21453            self.buffer
21454                .read(cx)
21455                .language_settings(cx)
21456                .indent_guides
21457                .enabled
21458        });
21459        self.show_indent_guides = Some(!currently_enabled);
21460        cx.notify();
21461    }
21462
21463    fn should_show_indent_guides(&self) -> Option<bool> {
21464        self.show_indent_guides
21465    }
21466
21467    pub fn disable_indent_guides_for_buffer(
21468        &mut self,
21469        buffer_id: BufferId,
21470        cx: &mut Context<Self>,
21471    ) {
21472        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21473        cx.notify();
21474    }
21475
21476    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21477        self.buffers_with_disabled_indent_guides
21478            .contains(&buffer_id)
21479    }
21480
21481    pub fn toggle_line_numbers(
21482        &mut self,
21483        _: &ToggleLineNumbers,
21484        _: &mut Window,
21485        cx: &mut Context<Self>,
21486    ) {
21487        let mut editor_settings = EditorSettings::get_global(cx).clone();
21488        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21489        EditorSettings::override_global(editor_settings, cx);
21490    }
21491
21492    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21493        if let Some(show_line_numbers) = self.show_line_numbers {
21494            return show_line_numbers;
21495        }
21496        EditorSettings::get_global(cx).gutter.line_numbers
21497    }
21498
21499    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21500        match (
21501            self.use_relative_line_numbers,
21502            EditorSettings::get_global(cx).relative_line_numbers,
21503        ) {
21504            (None, setting) => setting,
21505            (Some(false), _) => RelativeLineNumbers::Disabled,
21506            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21507            (Some(true), _) => RelativeLineNumbers::Enabled,
21508        }
21509    }
21510
21511    pub fn toggle_relative_line_numbers(
21512        &mut self,
21513        _: &ToggleRelativeLineNumbers,
21514        _: &mut Window,
21515        cx: &mut Context<Self>,
21516    ) {
21517        let is_relative = self.relative_line_numbers(cx);
21518        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21519    }
21520
21521    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21522        self.use_relative_line_numbers = is_relative;
21523        cx.notify();
21524    }
21525
21526    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21527        self.show_gutter = show_gutter;
21528        cx.notify();
21529    }
21530
21531    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21532        self.show_scrollbars = ScrollbarAxes {
21533            horizontal: show,
21534            vertical: show,
21535        };
21536        cx.notify();
21537    }
21538
21539    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21540        self.show_scrollbars.vertical = show;
21541        cx.notify();
21542    }
21543
21544    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21545        self.show_scrollbars.horizontal = show;
21546        cx.notify();
21547    }
21548
21549    pub fn set_minimap_visibility(
21550        &mut self,
21551        minimap_visibility: MinimapVisibility,
21552        window: &mut Window,
21553        cx: &mut Context<Self>,
21554    ) {
21555        if self.minimap_visibility != minimap_visibility {
21556            if minimap_visibility.visible() && self.minimap.is_none() {
21557                let minimap_settings = EditorSettings::get_global(cx).minimap;
21558                self.minimap =
21559                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21560            }
21561            self.minimap_visibility = minimap_visibility;
21562            cx.notify();
21563        }
21564    }
21565
21566    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21567        self.set_show_scrollbars(false, cx);
21568        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21569    }
21570
21571    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21572        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21573    }
21574
21575    /// Normally the text in full mode and auto height editors is padded on the
21576    /// left side by roughly half a character width for improved hit testing.
21577    ///
21578    /// Use this method to disable this for cases where this is not wanted (e.g.
21579    /// if you want to align the editor text with some other text above or below)
21580    /// or if you want to add this padding to single-line editors.
21581    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21582        self.offset_content = offset_content;
21583        cx.notify();
21584    }
21585
21586    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21587        self.show_line_numbers = Some(show_line_numbers);
21588        cx.notify();
21589    }
21590
21591    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21592        self.disable_expand_excerpt_buttons = true;
21593        cx.notify();
21594    }
21595
21596    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21597        self.number_deleted_lines = number;
21598        cx.notify();
21599    }
21600
21601    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21602        self.delegate_expand_excerpts = delegate;
21603    }
21604
21605    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21606        self.delegate_stage_and_restore = delegate;
21607    }
21608
21609    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21610        self.delegate_open_excerpts = delegate;
21611    }
21612
21613    pub fn set_on_local_selections_changed(
21614        &mut self,
21615        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21616    ) {
21617        self.on_local_selections_changed = callback;
21618    }
21619
21620    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21621        self.suppress_selection_callback = suppress;
21622    }
21623
21624    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21625        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21626        cx.notify();
21627    }
21628
21629    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21630        self.show_code_actions = Some(show_code_actions);
21631        cx.notify();
21632    }
21633
21634    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21635        self.show_runnables = Some(show_runnables);
21636        cx.notify();
21637    }
21638
21639    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21640        self.show_breakpoints = Some(show_breakpoints);
21641        cx.notify();
21642    }
21643
21644    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21645        self.show_diff_review_button = show;
21646        cx.notify();
21647    }
21648
21649    pub fn show_diff_review_button(&self) -> bool {
21650        self.show_diff_review_button
21651    }
21652
21653    pub fn render_diff_review_button(
21654        &self,
21655        display_row: DisplayRow,
21656        width: Pixels,
21657        cx: &mut Context<Self>,
21658    ) -> impl IntoElement {
21659        let text_color = cx.theme().colors().text;
21660        let icon_color = cx.theme().colors().icon_accent;
21661
21662        h_flex()
21663            .id("diff_review_button")
21664            .cursor_pointer()
21665            .w(width - px(1.))
21666            .h(relative(0.9))
21667            .justify_center()
21668            .rounded_sm()
21669            .border_1()
21670            .border_color(text_color.opacity(0.1))
21671            .bg(text_color.opacity(0.15))
21672            .hover(|s| {
21673                s.bg(icon_color.opacity(0.4))
21674                    .border_color(icon_color.opacity(0.5))
21675            })
21676            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21677            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21678            .on_mouse_down(
21679                gpui::MouseButton::Left,
21680                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21681                    editor.start_diff_review_drag(display_row, window, cx);
21682                }),
21683            )
21684    }
21685
21686    pub fn start_diff_review_drag(
21687        &mut self,
21688        display_row: DisplayRow,
21689        window: &mut Window,
21690        cx: &mut Context<Self>,
21691    ) {
21692        let snapshot = self.snapshot(window, cx);
21693        let point = snapshot
21694            .display_snapshot
21695            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21696        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21697        self.diff_review_drag_state = Some(DiffReviewDragState {
21698            start_anchor: anchor,
21699            current_anchor: anchor,
21700        });
21701        cx.notify();
21702    }
21703
21704    pub fn update_diff_review_drag(
21705        &mut self,
21706        display_row: DisplayRow,
21707        window: &mut Window,
21708        cx: &mut Context<Self>,
21709    ) {
21710        if self.diff_review_drag_state.is_none() {
21711            return;
21712        }
21713        let snapshot = self.snapshot(window, cx);
21714        let point = snapshot
21715            .display_snapshot
21716            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21717        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21718        if let Some(drag_state) = &mut self.diff_review_drag_state {
21719            drag_state.current_anchor = anchor;
21720            cx.notify();
21721        }
21722    }
21723
21724    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21725        if let Some(drag_state) = self.diff_review_drag_state.take() {
21726            let snapshot = self.snapshot(window, cx);
21727            let range = drag_state.row_range(&snapshot.display_snapshot);
21728            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21729        }
21730        cx.notify();
21731    }
21732
21733    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21734        self.diff_review_drag_state = None;
21735        cx.notify();
21736    }
21737
21738    /// Calculates the appropriate block height for the diff review overlay.
21739    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21740    /// and 2 lines per comment when expanded.
21741    fn calculate_overlay_height(
21742        &self,
21743        hunk_key: &DiffHunkKey,
21744        comments_expanded: bool,
21745        snapshot: &MultiBufferSnapshot,
21746    ) -> u32 {
21747        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21748        let base_height: u32 = 2; // Input row with avatar and buttons
21749
21750        if comment_count == 0 {
21751            base_height
21752        } else if comments_expanded {
21753            // Header (1 line) + 2 lines per comment
21754            base_height + 1 + (comment_count as u32 * 2)
21755        } else {
21756            // Just header when collapsed
21757            base_height + 1
21758        }
21759    }
21760
21761    pub fn show_diff_review_overlay(
21762        &mut self,
21763        display_range: Range<DisplayRow>,
21764        window: &mut Window,
21765        cx: &mut Context<Self>,
21766    ) {
21767        let Range { start, end } = display_range.sorted();
21768
21769        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21770        let editor_snapshot = self.snapshot(window, cx);
21771
21772        // Convert display rows to multibuffer points
21773        let start_point = editor_snapshot
21774            .display_snapshot
21775            .display_point_to_point(start.as_display_point(), Bias::Left);
21776        let end_point = editor_snapshot
21777            .display_snapshot
21778            .display_point_to_point(end.as_display_point(), Bias::Left);
21779        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21780
21781        // Create anchor range for the selected lines (start of first line to end of last line)
21782        let line_end = Point::new(
21783            end_point.row,
21784            buffer_snapshot.line_len(end_multi_buffer_row),
21785        );
21786        let anchor_range =
21787            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21788
21789        // Compute the hunk key for this display row
21790        let file_path = buffer_snapshot
21791            .file_at(start_point)
21792            .map(|file: &Arc<dyn language::File>| file.path().clone())
21793            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21794        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21795        let new_hunk_key = DiffHunkKey {
21796            file_path,
21797            hunk_start_anchor,
21798        };
21799
21800        // Check if we already have an overlay for this hunk
21801        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21802            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21803        }) {
21804            // Just focus the existing overlay's prompt editor
21805            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21806            window.focus(&focus_handle, cx);
21807            return;
21808        }
21809
21810        // Dismiss overlays that have no comments for their hunks
21811        self.dismiss_overlays_without_comments(cx);
21812
21813        // Get the current user's avatar URI from the project's user_store
21814        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21815            let user_store = project.read(cx).user_store();
21816            user_store
21817                .read(cx)
21818                .current_user()
21819                .map(|user| user.avatar_uri.clone())
21820        });
21821
21822        // Create anchor at the end of the last row so the block appears immediately below it
21823        // Use multibuffer coordinates for anchor creation
21824        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21825        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21826
21827        // Use the hunk key we already computed
21828        let hunk_key = new_hunk_key;
21829
21830        // Create the prompt editor for the review input
21831        let prompt_editor = cx.new(|cx| {
21832            let mut editor = Editor::single_line(window, cx);
21833            editor.set_placeholder_text("Add a review comment...", window, cx);
21834            editor
21835        });
21836
21837        // Register the Newline action on the prompt editor to submit the review
21838        let parent_editor = cx.entity().downgrade();
21839        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21840            prompt_editor.register_action({
21841                let parent_editor = parent_editor.clone();
21842                move |_: &crate::actions::Newline, window, cx| {
21843                    if let Some(editor) = parent_editor.upgrade() {
21844                        editor.update(cx, |editor, cx| {
21845                            editor.submit_diff_review_comment(window, cx);
21846                        });
21847                    }
21848                }
21849            })
21850        });
21851
21852        // Calculate initial height based on existing comments for this hunk
21853        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21854
21855        // Create the overlay block
21856        let prompt_editor_for_render = prompt_editor.clone();
21857        let hunk_key_for_render = hunk_key.clone();
21858        let editor_handle = cx.entity().downgrade();
21859        let block = BlockProperties {
21860            style: BlockStyle::Sticky,
21861            placement: BlockPlacement::Below(anchor),
21862            height: Some(initial_height),
21863            render: Arc::new(move |cx| {
21864                Self::render_diff_review_overlay(
21865                    &prompt_editor_for_render,
21866                    &hunk_key_for_render,
21867                    &editor_handle,
21868                    cx,
21869                )
21870            }),
21871            priority: 0,
21872        };
21873
21874        let block_ids = self.insert_blocks([block], None, cx);
21875        let Some(block_id) = block_ids.into_iter().next() else {
21876            log::error!("Failed to insert diff review overlay block");
21877            return;
21878        };
21879
21880        self.diff_review_overlays.push(DiffReviewOverlay {
21881            anchor_range,
21882            block_id,
21883            prompt_editor: prompt_editor.clone(),
21884            hunk_key,
21885            comments_expanded: true,
21886            inline_edit_editors: HashMap::default(),
21887            inline_edit_subscriptions: HashMap::default(),
21888            user_avatar_uri,
21889            _subscription: subscription,
21890        });
21891
21892        // Focus the prompt editor
21893        let focus_handle = prompt_editor.focus_handle(cx);
21894        window.focus(&focus_handle, cx);
21895
21896        cx.notify();
21897    }
21898
21899    /// Dismisses all diff review overlays.
21900    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21901        if self.diff_review_overlays.is_empty() {
21902            return;
21903        }
21904        let block_ids: HashSet<_> = self
21905            .diff_review_overlays
21906            .drain(..)
21907            .map(|overlay| overlay.block_id)
21908            .collect();
21909        self.remove_blocks(block_ids, None, cx);
21910        cx.notify();
21911    }
21912
21913    /// Dismisses overlays that have no comments stored for their hunks.
21914    /// Keeps overlays that have at least one comment.
21915    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21916        let snapshot = self.buffer.read(cx).snapshot(cx);
21917
21918        // First, compute which overlays have comments (to avoid borrow issues with retain)
21919        let overlays_with_comments: Vec<bool> = self
21920            .diff_review_overlays
21921            .iter()
21922            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21923            .collect();
21924
21925        // Now collect block IDs to remove and retain overlays
21926        let mut block_ids_to_remove = HashSet::default();
21927        let mut index = 0;
21928        self.diff_review_overlays.retain(|overlay| {
21929            let has_comments = overlays_with_comments[index];
21930            index += 1;
21931            if !has_comments {
21932                block_ids_to_remove.insert(overlay.block_id);
21933            }
21934            has_comments
21935        });
21936
21937        if !block_ids_to_remove.is_empty() {
21938            self.remove_blocks(block_ids_to_remove, None, cx);
21939            cx.notify();
21940        }
21941    }
21942
21943    /// Refreshes the diff review overlay block to update its height and render function.
21944    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21945    fn refresh_diff_review_overlay_height(
21946        &mut self,
21947        hunk_key: &DiffHunkKey,
21948        _window: &mut Window,
21949        cx: &mut Context<Self>,
21950    ) {
21951        // Extract all needed data from overlay first to avoid borrow conflicts
21952        let snapshot = self.buffer.read(cx).snapshot(cx);
21953        let (comments_expanded, block_id, prompt_editor) = {
21954            let Some(overlay) = self
21955                .diff_review_overlays
21956                .iter()
21957                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21958            else {
21959                return;
21960            };
21961
21962            (
21963                overlay.comments_expanded,
21964                overlay.block_id,
21965                overlay.prompt_editor.clone(),
21966            )
21967        };
21968
21969        // Calculate new height
21970        let snapshot = self.buffer.read(cx).snapshot(cx);
21971        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21972
21973        // Update the block height using resize_blocks (avoids flicker)
21974        let mut heights = HashMap::default();
21975        heights.insert(block_id, new_height);
21976        self.resize_blocks(heights, None, cx);
21977
21978        // Update the render function using replace_blocks (avoids flicker)
21979        let hunk_key_for_render = hunk_key.clone();
21980        let editor_handle = cx.entity().downgrade();
21981        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21982            Arc::new(move |cx| {
21983                Self::render_diff_review_overlay(
21984                    &prompt_editor,
21985                    &hunk_key_for_render,
21986                    &editor_handle,
21987                    cx,
21988                )
21989            });
21990
21991        let mut renderers = HashMap::default();
21992        renderers.insert(block_id, render);
21993        self.replace_blocks(renderers, None, cx);
21994    }
21995
21996    /// Action handler for SubmitDiffReviewComment.
21997    pub fn submit_diff_review_comment_action(
21998        &mut self,
21999        _: &SubmitDiffReviewComment,
22000        window: &mut Window,
22001        cx: &mut Context<Self>,
22002    ) {
22003        self.submit_diff_review_comment(window, cx);
22004    }
22005
22006    /// Stores the diff review comment locally.
22007    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22008    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22009        // Find the overlay that currently has focus
22010        let overlay_index = self
22011            .diff_review_overlays
22012            .iter()
22013            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22014        let Some(overlay_index) = overlay_index else {
22015            return;
22016        };
22017        let overlay = &self.diff_review_overlays[overlay_index];
22018
22019        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22020        if comment_text.is_empty() {
22021            return;
22022        }
22023
22024        let anchor_range = overlay.anchor_range.clone();
22025        let hunk_key = overlay.hunk_key.clone();
22026
22027        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22028
22029        // Clear the prompt editor but keep the overlay open
22030        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22031            overlay.prompt_editor.update(cx, |editor, cx| {
22032                editor.clear(window, cx);
22033            });
22034        }
22035
22036        // Refresh the overlay to update the block height for the new comment
22037        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22038
22039        cx.notify();
22040    }
22041
22042    /// Returns the prompt editor for the diff review overlay, if one is active.
22043    /// This is primarily used for testing.
22044    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22045        self.diff_review_overlays
22046            .first()
22047            .map(|overlay| &overlay.prompt_editor)
22048    }
22049
22050    /// Returns the line range for the first diff review overlay, if one is active.
22051    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22052    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22053        let overlay = self.diff_review_overlays.first()?;
22054        let snapshot = self.buffer.read(cx).snapshot(cx);
22055        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22056        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22057        let start_row = snapshot
22058            .point_to_buffer_point(start_point)
22059            .map(|(_, p, _)| p.row)
22060            .unwrap_or(start_point.row);
22061        let end_row = snapshot
22062            .point_to_buffer_point(end_point)
22063            .map(|(_, p, _)| p.row)
22064            .unwrap_or(end_point.row);
22065        Some((start_row, end_row))
22066    }
22067
22068    /// Sets whether the comments section is expanded in the diff review overlay.
22069    /// This is primarily used for testing.
22070    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22071        for overlay in &mut self.diff_review_overlays {
22072            overlay.comments_expanded = expanded;
22073        }
22074        cx.notify();
22075    }
22076
22077    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22078    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22079        a.file_path == b.file_path
22080            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22081    }
22082
22083    /// Returns comments for a specific hunk, ordered by creation time.
22084    pub fn comments_for_hunk<'a>(
22085        &'a self,
22086        key: &DiffHunkKey,
22087        snapshot: &MultiBufferSnapshot,
22088    ) -> &'a [StoredReviewComment] {
22089        let key_point = key.hunk_start_anchor.to_point(snapshot);
22090        self.stored_review_comments
22091            .iter()
22092            .find(|(k, _)| {
22093                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22094            })
22095            .map(|(_, comments)| comments.as_slice())
22096            .unwrap_or(&[])
22097    }
22098
22099    /// Returns the total count of stored review comments across all hunks.
22100    pub fn total_review_comment_count(&self) -> usize {
22101        self.stored_review_comments
22102            .iter()
22103            .map(|(_, v)| v.len())
22104            .sum()
22105    }
22106
22107    /// Returns the count of comments for a specific hunk.
22108    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22109        let key_point = key.hunk_start_anchor.to_point(snapshot);
22110        self.stored_review_comments
22111            .iter()
22112            .find(|(k, _)| {
22113                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22114            })
22115            .map(|(_, v)| v.len())
22116            .unwrap_or(0)
22117    }
22118
22119    /// Adds a new review comment to a specific hunk.
22120    pub fn add_review_comment(
22121        &mut self,
22122        hunk_key: DiffHunkKey,
22123        comment: String,
22124        anchor_range: Range<Anchor>,
22125        cx: &mut Context<Self>,
22126    ) -> usize {
22127        let id = self.next_review_comment_id;
22128        self.next_review_comment_id += 1;
22129
22130        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22131
22132        let snapshot = self.buffer.read(cx).snapshot(cx);
22133        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22134
22135        // Find existing entry for this hunk or add a new one
22136        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22137            k.file_path == hunk_key.file_path
22138                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22139        }) {
22140            comments.push(stored_comment);
22141        } else {
22142            self.stored_review_comments
22143                .push((hunk_key, vec![stored_comment]));
22144        }
22145
22146        cx.emit(EditorEvent::ReviewCommentsChanged {
22147            total_count: self.total_review_comment_count(),
22148        });
22149        cx.notify();
22150        id
22151    }
22152
22153    /// Removes a review comment by ID from any hunk.
22154    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22155        for (_, comments) in self.stored_review_comments.iter_mut() {
22156            if let Some(index) = comments.iter().position(|c| c.id == id) {
22157                comments.remove(index);
22158                cx.emit(EditorEvent::ReviewCommentsChanged {
22159                    total_count: self.total_review_comment_count(),
22160                });
22161                cx.notify();
22162                return true;
22163            }
22164        }
22165        false
22166    }
22167
22168    /// Updates a review comment's text by ID.
22169    pub fn update_review_comment(
22170        &mut self,
22171        id: usize,
22172        new_comment: String,
22173        cx: &mut Context<Self>,
22174    ) -> bool {
22175        for (_, comments) in self.stored_review_comments.iter_mut() {
22176            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22177                comment.comment = new_comment;
22178                comment.is_editing = false;
22179                cx.emit(EditorEvent::ReviewCommentsChanged {
22180                    total_count: self.total_review_comment_count(),
22181                });
22182                cx.notify();
22183                return true;
22184            }
22185        }
22186        false
22187    }
22188
22189    /// Sets a comment's editing state.
22190    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22191        for (_, comments) in self.stored_review_comments.iter_mut() {
22192            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22193                comment.is_editing = is_editing;
22194                cx.notify();
22195                return;
22196            }
22197        }
22198    }
22199
22200    /// Takes all stored comments from all hunks, clearing the storage.
22201    /// Returns a Vec of (hunk_key, comments) pairs.
22202    pub fn take_all_review_comments(
22203        &mut self,
22204        cx: &mut Context<Self>,
22205    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22206        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22207        self.dismiss_all_diff_review_overlays(cx);
22208        let comments = std::mem::take(&mut self.stored_review_comments);
22209        // Reset the ID counter since all comments have been taken
22210        self.next_review_comment_id = 0;
22211        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22212        cx.notify();
22213        comments
22214    }
22215
22216    /// Removes review comments whose anchors are no longer valid or whose
22217    /// associated diff hunks no longer exist.
22218    ///
22219    /// This should be called when the buffer changes to prevent orphaned comments
22220    /// from accumulating.
22221    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22222        let snapshot = self.buffer.read(cx).snapshot(cx);
22223        let original_count = self.total_review_comment_count();
22224
22225        // Remove comments with invalid hunk anchors
22226        self.stored_review_comments
22227            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22228
22229        // Also clean up individual comments with invalid anchor ranges
22230        for (_, comments) in &mut self.stored_review_comments {
22231            comments.retain(|comment| {
22232                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22233            });
22234        }
22235
22236        // Remove empty hunk entries
22237        self.stored_review_comments
22238            .retain(|(_, comments)| !comments.is_empty());
22239
22240        let new_count = self.total_review_comment_count();
22241        if new_count != original_count {
22242            cx.emit(EditorEvent::ReviewCommentsChanged {
22243                total_count: new_count,
22244            });
22245            cx.notify();
22246        }
22247    }
22248
22249    /// Toggles the expanded state of the comments section in the overlay.
22250    pub fn toggle_review_comments_expanded(
22251        &mut self,
22252        _: &ToggleReviewCommentsExpanded,
22253        window: &mut Window,
22254        cx: &mut Context<Self>,
22255    ) {
22256        // Find the overlay that currently has focus, or use the first one
22257        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22258            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22259                overlay.comments_expanded = !overlay.comments_expanded;
22260                Some(overlay.hunk_key.clone())
22261            } else {
22262                None
22263            }
22264        });
22265
22266        // If no focused overlay found, toggle the first one
22267        let hunk_key = overlay_info.or_else(|| {
22268            self.diff_review_overlays.first_mut().map(|overlay| {
22269                overlay.comments_expanded = !overlay.comments_expanded;
22270                overlay.hunk_key.clone()
22271            })
22272        });
22273
22274        if let Some(hunk_key) = hunk_key {
22275            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22276            cx.notify();
22277        }
22278    }
22279
22280    /// Handles the EditReviewComment action - sets a comment into editing mode.
22281    pub fn edit_review_comment(
22282        &mut self,
22283        action: &EditReviewComment,
22284        window: &mut Window,
22285        cx: &mut Context<Self>,
22286    ) {
22287        let comment_id = action.id;
22288
22289        // Set the comment to editing mode
22290        self.set_comment_editing(comment_id, true, cx);
22291
22292        // Find the overlay that contains this comment and create an inline editor if needed
22293        // First, find which hunk this comment belongs to
22294        let hunk_key = self
22295            .stored_review_comments
22296            .iter()
22297            .find_map(|(key, comments)| {
22298                if comments.iter().any(|c| c.id == comment_id) {
22299                    Some(key.clone())
22300                } else {
22301                    None
22302                }
22303            });
22304
22305        let snapshot = self.buffer.read(cx).snapshot(cx);
22306        if let Some(hunk_key) = hunk_key {
22307            if let Some(overlay) = self
22308                .diff_review_overlays
22309                .iter_mut()
22310                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22311            {
22312                if let std::collections::hash_map::Entry::Vacant(entry) =
22313                    overlay.inline_edit_editors.entry(comment_id)
22314                {
22315                    // Find the comment text
22316                    let comment_text = self
22317                        .stored_review_comments
22318                        .iter()
22319                        .flat_map(|(_, comments)| comments)
22320                        .find(|c| c.id == comment_id)
22321                        .map(|c| c.comment.clone())
22322                        .unwrap_or_default();
22323
22324                    // Create inline editor
22325                    let parent_editor = cx.entity().downgrade();
22326                    let inline_editor = cx.new(|cx| {
22327                        let mut editor = Editor::single_line(window, cx);
22328                        editor.set_text(&*comment_text, window, cx);
22329                        // Select all text for easy replacement
22330                        editor.select_all(&crate::actions::SelectAll, window, cx);
22331                        editor
22332                    });
22333
22334                    // Register the Newline action to confirm the edit
22335                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22336                        inline_editor.register_action({
22337                            let parent_editor = parent_editor.clone();
22338                            move |_: &crate::actions::Newline, window, cx| {
22339                                if let Some(editor) = parent_editor.upgrade() {
22340                                    editor.update(cx, |editor, cx| {
22341                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22342                                    });
22343                                }
22344                            }
22345                        })
22346                    });
22347
22348                    // Store the subscription to keep the action handler alive
22349                    overlay
22350                        .inline_edit_subscriptions
22351                        .insert(comment_id, subscription);
22352
22353                    // Focus the inline editor
22354                    let focus_handle = inline_editor.focus_handle(cx);
22355                    window.focus(&focus_handle, cx);
22356
22357                    entry.insert(inline_editor);
22358                }
22359            }
22360        }
22361
22362        cx.notify();
22363    }
22364
22365    /// Confirms an inline edit of a review comment.
22366    pub fn confirm_edit_review_comment(
22367        &mut self,
22368        comment_id: usize,
22369        _window: &mut Window,
22370        cx: &mut Context<Self>,
22371    ) {
22372        // Get the new text from the inline editor
22373        // Find the overlay containing this comment's inline editor
22374        let snapshot = self.buffer.read(cx).snapshot(cx);
22375        let hunk_key = self
22376            .stored_review_comments
22377            .iter()
22378            .find_map(|(key, comments)| {
22379                if comments.iter().any(|c| c.id == comment_id) {
22380                    Some(key.clone())
22381                } else {
22382                    None
22383                }
22384            });
22385
22386        let new_text = hunk_key
22387            .as_ref()
22388            .and_then(|hunk_key| {
22389                self.diff_review_overlays
22390                    .iter()
22391                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22392            })
22393            .as_ref()
22394            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22395            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22396
22397        if let Some(new_text) = new_text {
22398            if !new_text.is_empty() {
22399                self.update_review_comment(comment_id, new_text, cx);
22400            }
22401        }
22402
22403        // Remove the inline editor and its subscription
22404        if let Some(hunk_key) = hunk_key {
22405            if let Some(overlay) = self
22406                .diff_review_overlays
22407                .iter_mut()
22408                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22409            {
22410                overlay.inline_edit_editors.remove(&comment_id);
22411                overlay.inline_edit_subscriptions.remove(&comment_id);
22412            }
22413        }
22414
22415        // Clear editing state
22416        self.set_comment_editing(comment_id, false, cx);
22417    }
22418
22419    /// Cancels an inline edit of a review comment.
22420    pub fn cancel_edit_review_comment(
22421        &mut self,
22422        comment_id: usize,
22423        _window: &mut Window,
22424        cx: &mut Context<Self>,
22425    ) {
22426        // Find which hunk this comment belongs to
22427        let hunk_key = self
22428            .stored_review_comments
22429            .iter()
22430            .find_map(|(key, comments)| {
22431                if comments.iter().any(|c| c.id == comment_id) {
22432                    Some(key.clone())
22433                } else {
22434                    None
22435                }
22436            });
22437
22438        // Remove the inline editor and its subscription
22439        if let Some(hunk_key) = hunk_key {
22440            let snapshot = self.buffer.read(cx).snapshot(cx);
22441            if let Some(overlay) = self
22442                .diff_review_overlays
22443                .iter_mut()
22444                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22445            {
22446                overlay.inline_edit_editors.remove(&comment_id);
22447                overlay.inline_edit_subscriptions.remove(&comment_id);
22448            }
22449        }
22450
22451        // Clear editing state
22452        self.set_comment_editing(comment_id, false, cx);
22453    }
22454
22455    /// Action handler for ConfirmEditReviewComment.
22456    pub fn confirm_edit_review_comment_action(
22457        &mut self,
22458        action: &ConfirmEditReviewComment,
22459        window: &mut Window,
22460        cx: &mut Context<Self>,
22461    ) {
22462        self.confirm_edit_review_comment(action.id, window, cx);
22463    }
22464
22465    /// Action handler for CancelEditReviewComment.
22466    pub fn cancel_edit_review_comment_action(
22467        &mut self,
22468        action: &CancelEditReviewComment,
22469        window: &mut Window,
22470        cx: &mut Context<Self>,
22471    ) {
22472        self.cancel_edit_review_comment(action.id, window, cx);
22473    }
22474
22475    /// Handles the DeleteReviewComment action - removes a comment.
22476    pub fn delete_review_comment(
22477        &mut self,
22478        action: &DeleteReviewComment,
22479        window: &mut Window,
22480        cx: &mut Context<Self>,
22481    ) {
22482        // Get the hunk key before removing the comment
22483        // Find the hunk key from the comment itself
22484        let comment_id = action.id;
22485        let hunk_key = self
22486            .stored_review_comments
22487            .iter()
22488            .find_map(|(key, comments)| {
22489                if comments.iter().any(|c| c.id == comment_id) {
22490                    Some(key.clone())
22491                } else {
22492                    None
22493                }
22494            });
22495
22496        // Also get it from the overlay for refresh purposes
22497        let overlay_hunk_key = self
22498            .diff_review_overlays
22499            .first()
22500            .map(|o| o.hunk_key.clone());
22501
22502        self.remove_review_comment(action.id, cx);
22503
22504        // Refresh the overlay height after removing a comment
22505        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22506            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22507        }
22508    }
22509
22510    fn render_diff_review_overlay(
22511        prompt_editor: &Entity<Editor>,
22512        hunk_key: &DiffHunkKey,
22513        editor_handle: &WeakEntity<Editor>,
22514        cx: &mut BlockContext,
22515    ) -> AnyElement {
22516        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22517            if ranges.is_empty() {
22518                return None;
22519            }
22520            let formatted: Vec<String> = ranges
22521                .iter()
22522                .map(|(start, end)| {
22523                    let start_line = start + 1;
22524                    let end_line = end + 1;
22525                    if start_line == end_line {
22526                        format!("Line {start_line}")
22527                    } else {
22528                        format!("Lines {start_line}-{end_line}")
22529                    }
22530                })
22531                .collect();
22532            // Don't show label for single line in single excerpt
22533            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22534                return None;
22535            }
22536            Some(formatted.join(""))
22537        }
22538
22539        let theme = cx.theme();
22540        let colors = theme.colors();
22541
22542        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22543            editor_handle
22544                .upgrade()
22545                .map(|editor| {
22546                    let editor = editor.read(cx);
22547                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22548                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22549                    let (expanded, editors, avatar_uri, line_ranges) = editor
22550                        .diff_review_overlays
22551                        .iter()
22552                        .find(|overlay| {
22553                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22554                        })
22555                        .map(|o| {
22556                            let start_point = o.anchor_range.start.to_point(&snapshot);
22557                            let end_point = o.anchor_range.end.to_point(&snapshot);
22558                            // Get line ranges per excerpt to detect discontinuities
22559                            let buffer_ranges =
22560                                snapshot.range_to_buffer_ranges(start_point..end_point);
22561                            let ranges: Vec<(u32, u32)> = buffer_ranges
22562                                .iter()
22563                                .map(|(buffer, range, _)| {
22564                                    let start = buffer.offset_to_point(range.start.0).row;
22565                                    let end = buffer.offset_to_point(range.end.0).row;
22566                                    (start, end)
22567                                })
22568                                .collect();
22569                            (
22570                                o.comments_expanded,
22571                                o.inline_edit_editors.clone(),
22572                                o.user_avatar_uri.clone(),
22573                                if ranges.is_empty() {
22574                                    None
22575                                } else {
22576                                    Some(ranges)
22577                                },
22578                            )
22579                        })
22580                        .unwrap_or((true, HashMap::default(), None, None));
22581                    (comments, expanded, editors, avatar_uri, line_ranges)
22582                })
22583                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22584
22585        let comment_count = comments.len();
22586        let avatar_size = px(20.);
22587        let action_icon_size = IconSize::XSmall;
22588
22589        v_flex()
22590            .w_full()
22591            .bg(colors.editor_background)
22592            .border_b_1()
22593            .border_color(colors.border)
22594            .px_2()
22595            .pb_2()
22596            .gap_2()
22597            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22598            .when_some(line_ranges, |el, ranges| {
22599                let label = format_line_ranges(&ranges);
22600                if let Some(label) = label {
22601                    el.child(
22602                        h_flex()
22603                            .w_full()
22604                            .px_2()
22605                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22606                    )
22607                } else {
22608                    el
22609                }
22610            })
22611            // Top row: editable input with user's avatar
22612            .child(
22613                h_flex()
22614                    .w_full()
22615                    .items_center()
22616                    .gap_2()
22617                    .px_2()
22618                    .py_1p5()
22619                    .rounded_md()
22620                    .bg(colors.surface_background)
22621                    .child(
22622                        div()
22623                            .size(avatar_size)
22624                            .flex_shrink_0()
22625                            .rounded_full()
22626                            .overflow_hidden()
22627                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22628                                Avatar::new(avatar_uri.clone())
22629                                    .size(avatar_size)
22630                                    .into_any_element()
22631                            } else {
22632                                Icon::new(IconName::Person)
22633                                    .size(IconSize::Small)
22634                                    .color(ui::Color::Muted)
22635                                    .into_any_element()
22636                            }),
22637                    )
22638                    .child(
22639                        div()
22640                            .flex_1()
22641                            .border_1()
22642                            .border_color(colors.border)
22643                            .rounded_md()
22644                            .bg(colors.editor_background)
22645                            .px_2()
22646                            .py_1()
22647                            .child(prompt_editor.clone()),
22648                    )
22649                    .child(
22650                        h_flex()
22651                            .flex_shrink_0()
22652                            .gap_1()
22653                            .child(
22654                                IconButton::new("diff-review-close", IconName::Close)
22655                                    .icon_color(ui::Color::Muted)
22656                                    .icon_size(action_icon_size)
22657                                    .tooltip(Tooltip::text("Close"))
22658                                    .on_click(|_, window, cx| {
22659                                        window
22660                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22661                                    }),
22662                            )
22663                            .child(
22664                                IconButton::new("diff-review-add", IconName::Return)
22665                                    .icon_color(ui::Color::Muted)
22666                                    .icon_size(action_icon_size)
22667                                    .tooltip(Tooltip::text("Add comment"))
22668                                    .on_click(|_, window, cx| {
22669                                        window.dispatch_action(
22670                                            Box::new(crate::actions::SubmitDiffReviewComment),
22671                                            cx,
22672                                        );
22673                                    }),
22674                            ),
22675                    ),
22676            )
22677            // Expandable comments section (only shown when there are comments)
22678            .when(comment_count > 0, |el| {
22679                el.child(Self::render_comments_section(
22680                    comments,
22681                    comments_expanded,
22682                    inline_editors,
22683                    user_avatar_uri,
22684                    avatar_size,
22685                    action_icon_size,
22686                    colors,
22687                ))
22688            })
22689            .into_any_element()
22690    }
22691
22692    fn render_comments_section(
22693        comments: Vec<StoredReviewComment>,
22694        expanded: bool,
22695        inline_editors: HashMap<usize, Entity<Editor>>,
22696        user_avatar_uri: Option<SharedUri>,
22697        avatar_size: Pixels,
22698        action_icon_size: IconSize,
22699        colors: &theme::ThemeColors,
22700    ) -> impl IntoElement {
22701        let comment_count = comments.len();
22702
22703        v_flex()
22704            .w_full()
22705            .gap_1()
22706            // Header with expand/collapse toggle
22707            .child(
22708                h_flex()
22709                    .id("review-comments-header")
22710                    .w_full()
22711                    .items_center()
22712                    .gap_1()
22713                    .px_2()
22714                    .py_1()
22715                    .cursor_pointer()
22716                    .rounded_md()
22717                    .hover(|style| style.bg(colors.ghost_element_hover))
22718                    .on_click(|_, window: &mut Window, cx| {
22719                        window.dispatch_action(
22720                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22721                            cx,
22722                        );
22723                    })
22724                    .child(
22725                        Icon::new(if expanded {
22726                            IconName::ChevronDown
22727                        } else {
22728                            IconName::ChevronRight
22729                        })
22730                        .size(IconSize::Small)
22731                        .color(ui::Color::Muted),
22732                    )
22733                    .child(
22734                        Label::new(format!(
22735                            "{} Comment{}",
22736                            comment_count,
22737                            if comment_count == 1 { "" } else { "s" }
22738                        ))
22739                        .size(LabelSize::Small)
22740                        .color(Color::Muted),
22741                    ),
22742            )
22743            // Comments list (when expanded)
22744            .when(expanded, |el| {
22745                el.children(comments.into_iter().map(|comment| {
22746                    let inline_editor = inline_editors.get(&comment.id).cloned();
22747                    Self::render_comment_row(
22748                        comment,
22749                        inline_editor,
22750                        user_avatar_uri.clone(),
22751                        avatar_size,
22752                        action_icon_size,
22753                        colors,
22754                    )
22755                }))
22756            })
22757    }
22758
22759    fn render_comment_row(
22760        comment: StoredReviewComment,
22761        inline_editor: Option<Entity<Editor>>,
22762        user_avatar_uri: Option<SharedUri>,
22763        avatar_size: Pixels,
22764        action_icon_size: IconSize,
22765        colors: &theme::ThemeColors,
22766    ) -> impl IntoElement {
22767        let comment_id = comment.id;
22768        let is_editing = inline_editor.is_some();
22769
22770        h_flex()
22771            .w_full()
22772            .items_center()
22773            .gap_2()
22774            .px_2()
22775            .py_1p5()
22776            .rounded_md()
22777            .bg(colors.surface_background)
22778            .child(
22779                div()
22780                    .size(avatar_size)
22781                    .flex_shrink_0()
22782                    .rounded_full()
22783                    .overflow_hidden()
22784                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22785                        Avatar::new(avatar_uri.clone())
22786                            .size(avatar_size)
22787                            .into_any_element()
22788                    } else {
22789                        Icon::new(IconName::Person)
22790                            .size(IconSize::Small)
22791                            .color(ui::Color::Muted)
22792                            .into_any_element()
22793                    }),
22794            )
22795            .child(if let Some(editor) = inline_editor {
22796                // Inline edit mode: show an editable text field
22797                div()
22798                    .flex_1()
22799                    .border_1()
22800                    .border_color(colors.border)
22801                    .rounded_md()
22802                    .bg(colors.editor_background)
22803                    .px_2()
22804                    .py_1()
22805                    .child(editor)
22806                    .into_any_element()
22807            } else {
22808                // Display mode: show the comment text
22809                div()
22810                    .flex_1()
22811                    .text_sm()
22812                    .text_color(colors.text)
22813                    .child(comment.comment)
22814                    .into_any_element()
22815            })
22816            .child(if is_editing {
22817                // Editing mode: show close and confirm buttons
22818                h_flex()
22819                    .gap_1()
22820                    .child(
22821                        IconButton::new(
22822                            format!("diff-review-cancel-edit-{comment_id}"),
22823                            IconName::Close,
22824                        )
22825                        .icon_color(ui::Color::Muted)
22826                        .icon_size(action_icon_size)
22827                        .tooltip(Tooltip::text("Cancel"))
22828                        .on_click(move |_, window, cx| {
22829                            window.dispatch_action(
22830                                Box::new(crate::actions::CancelEditReviewComment {
22831                                    id: comment_id,
22832                                }),
22833                                cx,
22834                            );
22835                        }),
22836                    )
22837                    .child(
22838                        IconButton::new(
22839                            format!("diff-review-confirm-edit-{comment_id}"),
22840                            IconName::Return,
22841                        )
22842                        .icon_color(ui::Color::Muted)
22843                        .icon_size(action_icon_size)
22844                        .tooltip(Tooltip::text("Confirm"))
22845                        .on_click(move |_, window, cx| {
22846                            window.dispatch_action(
22847                                Box::new(crate::actions::ConfirmEditReviewComment {
22848                                    id: comment_id,
22849                                }),
22850                                cx,
22851                            );
22852                        }),
22853                    )
22854                    .into_any_element()
22855            } else {
22856                // Display mode: no action buttons for now (edit/delete not yet implemented)
22857                gpui::Empty.into_any_element()
22858            })
22859    }
22860
22861    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22862        if self.display_map.read(cx).masked != masked {
22863            self.display_map.update(cx, |map, _| map.masked = masked);
22864        }
22865        cx.notify()
22866    }
22867
22868    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22869        self.show_wrap_guides = Some(show_wrap_guides);
22870        cx.notify();
22871    }
22872
22873    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22874        self.show_indent_guides = Some(show_indent_guides);
22875        cx.notify();
22876    }
22877
22878    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22879        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22880            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22881                && let Some(dir) = file.abs_path(cx).parent()
22882            {
22883                return Some(dir.to_owned());
22884            }
22885        }
22886
22887        None
22888    }
22889
22890    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22891        self.active_excerpt(cx)?
22892            .1
22893            .read(cx)
22894            .file()
22895            .and_then(|f| f.as_local())
22896    }
22897
22898    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22899        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22900            let buffer = buffer.read(cx);
22901            if let Some(project_path) = buffer.project_path(cx) {
22902                let project = self.project()?.read(cx);
22903                project.absolute_path(&project_path, cx)
22904            } else {
22905                buffer
22906                    .file()
22907                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22908            }
22909        })
22910    }
22911
22912    pub fn reveal_in_finder(
22913        &mut self,
22914        _: &RevealInFileManager,
22915        _window: &mut Window,
22916        cx: &mut Context<Self>,
22917    ) {
22918        if let Some(path) = self.target_file_abs_path(cx) {
22919            if let Some(project) = self.project() {
22920                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22921            } else {
22922                cx.reveal_path(&path);
22923            }
22924        }
22925    }
22926
22927    pub fn copy_path(
22928        &mut self,
22929        _: &zed_actions::workspace::CopyPath,
22930        _window: &mut Window,
22931        cx: &mut Context<Self>,
22932    ) {
22933        if let Some(path) = self.target_file_abs_path(cx)
22934            && let Some(path) = path.to_str()
22935        {
22936            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22937        } else {
22938            cx.propagate();
22939        }
22940    }
22941
22942    pub fn copy_relative_path(
22943        &mut self,
22944        _: &zed_actions::workspace::CopyRelativePath,
22945        _window: &mut Window,
22946        cx: &mut Context<Self>,
22947    ) {
22948        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22949            let project = self.project()?.read(cx);
22950            let path = buffer.read(cx).file()?.path();
22951            let path = path.display(project.path_style(cx));
22952            Some(path)
22953        }) {
22954            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22955        } else {
22956            cx.propagate();
22957        }
22958    }
22959
22960    /// Returns the project path for the editor's buffer, if any buffer is
22961    /// opened in the editor.
22962    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22963        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22964            buffer.read(cx).project_path(cx)
22965        } else {
22966            None
22967        }
22968    }
22969
22970    // Returns true if the editor handled a go-to-line request
22971    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22972        maybe!({
22973            let breakpoint_store = self.breakpoint_store.as_ref()?;
22974
22975            let (active_stack_frame, debug_line_pane_id) = {
22976                let store = breakpoint_store.read(cx);
22977                let active_stack_frame = store.active_position().cloned();
22978                let debug_line_pane_id = store.active_debug_line_pane_id();
22979                (active_stack_frame, debug_line_pane_id)
22980            };
22981
22982            let Some(active_stack_frame) = active_stack_frame else {
22983                self.clear_row_highlights::<ActiveDebugLine>();
22984                return None;
22985            };
22986
22987            if let Some(debug_line_pane_id) = debug_line_pane_id {
22988                if let Some(workspace) = self
22989                    .workspace
22990                    .as_ref()
22991                    .and_then(|(workspace, _)| workspace.upgrade())
22992                {
22993                    let editor_pane_id = workspace
22994                        .read(cx)
22995                        .pane_for_item_id(cx.entity_id())
22996                        .map(|pane| pane.entity_id());
22997
22998                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
22999                        self.clear_row_highlights::<ActiveDebugLine>();
23000                        return None;
23001                    }
23002                }
23003            }
23004
23005            let position = active_stack_frame.position;
23006            let buffer_id = position.buffer_id?;
23007            let snapshot = self
23008                .project
23009                .as_ref()?
23010                .read(cx)
23011                .buffer_for_id(buffer_id, cx)?
23012                .read(cx)
23013                .snapshot();
23014
23015            let mut handled = false;
23016            for (id, _, ExcerptRange { context, .. }) in
23017                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
23018            {
23019                if context.start.cmp(&position, &snapshot).is_ge()
23020                    || context.end.cmp(&position, &snapshot).is_lt()
23021                {
23022                    continue;
23023                }
23024                let snapshot = self.buffer.read(cx).snapshot(cx);
23025                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
23026
23027                handled = true;
23028                self.clear_row_highlights::<ActiveDebugLine>();
23029
23030                self.go_to_line::<ActiveDebugLine>(
23031                    multibuffer_anchor,
23032                    Some(cx.theme().colors().editor_debugger_active_line_background),
23033                    window,
23034                    cx,
23035                );
23036
23037                cx.notify();
23038            }
23039
23040            handled.then_some(())
23041        })
23042        .is_some()
23043    }
23044
23045    pub fn copy_file_name_without_extension(
23046        &mut self,
23047        _: &CopyFileNameWithoutExtension,
23048        _: &mut Window,
23049        cx: &mut Context<Self>,
23050    ) {
23051        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23052            let file = buffer.read(cx).file()?;
23053            file.path().file_stem()
23054        }) {
23055            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23056        }
23057    }
23058
23059    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23060        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23061            let file = buffer.read(cx).file()?;
23062            Some(file.file_name(cx))
23063        }) {
23064            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23065        }
23066    }
23067
23068    pub fn toggle_git_blame(
23069        &mut self,
23070        _: &::git::Blame,
23071        window: &mut Window,
23072        cx: &mut Context<Self>,
23073    ) {
23074        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23075
23076        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23077            self.start_git_blame(true, window, cx);
23078        }
23079
23080        cx.notify();
23081    }
23082
23083    pub fn toggle_git_blame_inline(
23084        &mut self,
23085        _: &ToggleGitBlameInline,
23086        window: &mut Window,
23087        cx: &mut Context<Self>,
23088    ) {
23089        self.toggle_git_blame_inline_internal(true, window, cx);
23090        cx.notify();
23091    }
23092
23093    pub fn open_git_blame_commit(
23094        &mut self,
23095        _: &OpenGitBlameCommit,
23096        window: &mut Window,
23097        cx: &mut Context<Self>,
23098    ) {
23099        self.open_git_blame_commit_internal(window, cx);
23100    }
23101
23102    fn open_git_blame_commit_internal(
23103        &mut self,
23104        window: &mut Window,
23105        cx: &mut Context<Self>,
23106    ) -> Option<()> {
23107        let blame = self.blame.as_ref()?;
23108        let snapshot = self.snapshot(window, cx);
23109        let cursor = self
23110            .selections
23111            .newest::<Point>(&snapshot.display_snapshot)
23112            .head();
23113        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23114        let (_, blame_entry) = blame
23115            .update(cx, |blame, cx| {
23116                blame
23117                    .blame_for_rows(
23118                        &[RowInfo {
23119                            buffer_id: Some(buffer.remote_id()),
23120                            buffer_row: Some(point.row),
23121                            ..Default::default()
23122                        }],
23123                        cx,
23124                    )
23125                    .next()
23126            })
23127            .flatten()?;
23128        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23129        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23130        let workspace = self.workspace()?.downgrade();
23131        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23132        None
23133    }
23134
23135    pub fn git_blame_inline_enabled(&self) -> bool {
23136        self.git_blame_inline_enabled
23137    }
23138
23139    pub fn toggle_selection_menu(
23140        &mut self,
23141        _: &ToggleSelectionMenu,
23142        _: &mut Window,
23143        cx: &mut Context<Self>,
23144    ) {
23145        self.show_selection_menu = self
23146            .show_selection_menu
23147            .map(|show_selections_menu| !show_selections_menu)
23148            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23149
23150        cx.notify();
23151    }
23152
23153    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23154        self.show_selection_menu
23155            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23156    }
23157
23158    fn start_git_blame(
23159        &mut self,
23160        user_triggered: bool,
23161        window: &mut Window,
23162        cx: &mut Context<Self>,
23163    ) {
23164        if let Some(project) = self.project() {
23165            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23166                && buffer.read(cx).file().is_none()
23167            {
23168                return;
23169            }
23170
23171            let focused = self.focus_handle(cx).contains_focused(window, cx);
23172
23173            let project = project.clone();
23174            let blame = cx
23175                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23176            self.blame_subscription =
23177                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23178            self.blame = Some(blame);
23179        }
23180    }
23181
23182    fn toggle_git_blame_inline_internal(
23183        &mut self,
23184        user_triggered: bool,
23185        window: &mut Window,
23186        cx: &mut Context<Self>,
23187    ) {
23188        if self.git_blame_inline_enabled {
23189            self.git_blame_inline_enabled = false;
23190            self.show_git_blame_inline = false;
23191            self.show_git_blame_inline_delay_task.take();
23192        } else {
23193            self.git_blame_inline_enabled = true;
23194            self.start_git_blame_inline(user_triggered, window, cx);
23195        }
23196
23197        cx.notify();
23198    }
23199
23200    fn start_git_blame_inline(
23201        &mut self,
23202        user_triggered: bool,
23203        window: &mut Window,
23204        cx: &mut Context<Self>,
23205    ) {
23206        self.start_git_blame(user_triggered, window, cx);
23207
23208        if ProjectSettings::get_global(cx)
23209            .git
23210            .inline_blame_delay()
23211            .is_some()
23212        {
23213            self.start_inline_blame_timer(window, cx);
23214        } else {
23215            self.show_git_blame_inline = true
23216        }
23217    }
23218
23219    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23220        self.blame.as_ref()
23221    }
23222
23223    pub fn show_git_blame_gutter(&self) -> bool {
23224        self.show_git_blame_gutter
23225    }
23226
23227    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23228        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23229    }
23230
23231    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23232        self.show_git_blame_inline
23233            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23234            && !self.newest_selection_head_on_empty_line(cx)
23235            && self.has_blame_entries(cx)
23236    }
23237
23238    fn has_blame_entries(&self, cx: &App) -> bool {
23239        self.blame()
23240            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23241    }
23242
23243    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23244        let cursor_anchor = self.selections.newest_anchor().head();
23245
23246        let snapshot = self.buffer.read(cx).snapshot(cx);
23247        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23248
23249        snapshot.line_len(buffer_row) == 0
23250    }
23251
23252    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23253        let buffer_and_selection = maybe!({
23254            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23255            let selection_range = selection.range();
23256
23257            let multi_buffer = self.buffer().read(cx);
23258            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23259            let buffer_ranges = multi_buffer_snapshot
23260                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
23261
23262            let (buffer, range, _) = if selection.reversed {
23263                buffer_ranges.first()
23264            } else {
23265                buffer_ranges.last()
23266            }?;
23267
23268            let buffer_range = range.to_point(buffer);
23269
23270            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
23271                return Some((
23272                    multi_buffer.buffer(buffer.remote_id()).unwrap(),
23273                    buffer_range.start.row..buffer_range.end.row,
23274                ));
23275            };
23276
23277            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23278            let start =
23279                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.start, buffer);
23280            let end =
23281                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.end, buffer);
23282
23283            Some((
23284                multi_buffer.buffer(buffer.remote_id()).unwrap(),
23285                start.row..end.row,
23286            ))
23287        });
23288
23289        let Some((buffer, selection)) = buffer_and_selection else {
23290            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23291        };
23292
23293        let Some(project) = self.project() else {
23294            return Task::ready(Err(anyhow!("editor does not have project")));
23295        };
23296
23297        project.update(cx, |project, cx| {
23298            project.get_permalink_to_line(&buffer, selection, cx)
23299        })
23300    }
23301
23302    pub fn copy_permalink_to_line(
23303        &mut self,
23304        _: &CopyPermalinkToLine,
23305        window: &mut Window,
23306        cx: &mut Context<Self>,
23307    ) {
23308        let permalink_task = self.get_permalink_to_line(cx);
23309        let workspace = self.workspace();
23310
23311        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23312            Ok(permalink) => {
23313                cx.update(|_, cx| {
23314                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23315                })
23316                .ok();
23317            }
23318            Err(err) => {
23319                let message = format!("Failed to copy permalink: {err}");
23320
23321                anyhow::Result::<()>::Err(err).log_err();
23322
23323                if let Some(workspace) = workspace {
23324                    workspace
23325                        .update_in(cx, |workspace, _, cx| {
23326                            struct CopyPermalinkToLine;
23327
23328                            workspace.show_toast(
23329                                Toast::new(
23330                                    NotificationId::unique::<CopyPermalinkToLine>(),
23331                                    message,
23332                                ),
23333                                cx,
23334                            )
23335                        })
23336                        .ok();
23337                }
23338            }
23339        })
23340        .detach();
23341    }
23342
23343    pub fn copy_file_location(
23344        &mut self,
23345        _: &CopyFileLocation,
23346        _: &mut Window,
23347        cx: &mut Context<Self>,
23348    ) {
23349        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23350
23351        let start_line = selection.start.row + 1;
23352        let end_line = selection.end.row + 1;
23353
23354        let end_line = if selection.end.column == 0 && end_line > start_line {
23355            end_line - 1
23356        } else {
23357            end_line
23358        };
23359
23360        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
23361            let project = self.project()?.read(cx);
23362            let file = buffer.read(cx).file()?;
23363            let path = file.path().display(project.path_style(cx));
23364
23365            let location = if start_line == end_line {
23366                format!("{path}:{start_line}")
23367            } else {
23368                format!("{path}:{start_line}-{end_line}")
23369            };
23370            Some(location)
23371        }) {
23372            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23373        }
23374    }
23375
23376    pub fn open_permalink_to_line(
23377        &mut self,
23378        _: &OpenPermalinkToLine,
23379        window: &mut Window,
23380        cx: &mut Context<Self>,
23381    ) {
23382        let permalink_task = self.get_permalink_to_line(cx);
23383        let workspace = self.workspace();
23384
23385        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23386            Ok(permalink) => {
23387                cx.update(|_, cx| {
23388                    cx.open_url(permalink.as_ref());
23389                })
23390                .ok();
23391            }
23392            Err(err) => {
23393                let message = format!("Failed to open permalink: {err}");
23394
23395                anyhow::Result::<()>::Err(err).log_err();
23396
23397                if let Some(workspace) = workspace {
23398                    workspace.update(cx, |workspace, cx| {
23399                        struct OpenPermalinkToLine;
23400
23401                        workspace.show_toast(
23402                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23403                            cx,
23404                        )
23405                    });
23406                }
23407            }
23408        })
23409        .detach();
23410    }
23411
23412    pub fn insert_uuid_v4(
23413        &mut self,
23414        _: &InsertUuidV4,
23415        window: &mut Window,
23416        cx: &mut Context<Self>,
23417    ) {
23418        self.insert_uuid(UuidVersion::V4, window, cx);
23419    }
23420
23421    pub fn insert_uuid_v7(
23422        &mut self,
23423        _: &InsertUuidV7,
23424        window: &mut Window,
23425        cx: &mut Context<Self>,
23426    ) {
23427        self.insert_uuid(UuidVersion::V7, window, cx);
23428    }
23429
23430    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23431        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23432        self.transact(window, cx, |this, window, cx| {
23433            let edits = this
23434                .selections
23435                .all::<Point>(&this.display_snapshot(cx))
23436                .into_iter()
23437                .map(|selection| {
23438                    let uuid = match version {
23439                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23440                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23441                    };
23442
23443                    (selection.range(), uuid.to_string())
23444                });
23445            this.edit(edits, cx);
23446            this.refresh_edit_prediction(true, false, window, cx);
23447        });
23448    }
23449
23450    pub fn open_selections_in_multibuffer(
23451        &mut self,
23452        _: &OpenSelectionsInMultibuffer,
23453        window: &mut Window,
23454        cx: &mut Context<Self>,
23455    ) {
23456        let multibuffer = self.buffer.read(cx);
23457
23458        let Some(buffer) = multibuffer.as_singleton() else {
23459            return;
23460        };
23461
23462        let Some(workspace) = self.workspace() else {
23463            return;
23464        };
23465
23466        let title = multibuffer.title(cx).to_string();
23467
23468        let locations = self
23469            .selections
23470            .all_anchors(&self.display_snapshot(cx))
23471            .iter()
23472            .map(|selection| {
23473                (
23474                    buffer.clone(),
23475                    (selection.start.text_anchor..selection.end.text_anchor)
23476                        .to_point(buffer.read(cx)),
23477                )
23478            })
23479            .into_group_map();
23480
23481        cx.spawn_in(window, async move |_, cx| {
23482            workspace.update_in(cx, |workspace, window, cx| {
23483                Self::open_locations_in_multibuffer(
23484                    workspace,
23485                    locations,
23486                    format!("Selections for '{title}'"),
23487                    false,
23488                    false,
23489                    MultibufferSelectionMode::All,
23490                    window,
23491                    cx,
23492                );
23493            })
23494        })
23495        .detach();
23496    }
23497
23498    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23499    /// last highlight added will be used.
23500    ///
23501    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23502    pub fn highlight_rows<T: 'static>(
23503        &mut self,
23504        range: Range<Anchor>,
23505        color: Hsla,
23506        options: RowHighlightOptions,
23507        cx: &mut Context<Self>,
23508    ) {
23509        let snapshot = self.buffer().read(cx).snapshot(cx);
23510        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23511        let ix = row_highlights.binary_search_by(|highlight| {
23512            Ordering::Equal
23513                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23514                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23515        });
23516
23517        if let Err(mut ix) = ix {
23518            let index = post_inc(&mut self.highlight_order);
23519
23520            // If this range intersects with the preceding highlight, then merge it with
23521            // the preceding highlight. Otherwise insert a new highlight.
23522            let mut merged = false;
23523            if ix > 0 {
23524                let prev_highlight = &mut row_highlights[ix - 1];
23525                if prev_highlight
23526                    .range
23527                    .end
23528                    .cmp(&range.start, &snapshot)
23529                    .is_ge()
23530                {
23531                    ix -= 1;
23532                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23533                        prev_highlight.range.end = range.end;
23534                    }
23535                    merged = true;
23536                    prev_highlight.index = index;
23537                    prev_highlight.color = color;
23538                    prev_highlight.options = options;
23539                }
23540            }
23541
23542            if !merged {
23543                row_highlights.insert(
23544                    ix,
23545                    RowHighlight {
23546                        range,
23547                        index,
23548                        color,
23549                        options,
23550                        type_id: TypeId::of::<T>(),
23551                    },
23552                );
23553            }
23554
23555            // If any of the following highlights intersect with this one, merge them.
23556            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23557                let highlight = &row_highlights[ix];
23558                if next_highlight
23559                    .range
23560                    .start
23561                    .cmp(&highlight.range.end, &snapshot)
23562                    .is_le()
23563                {
23564                    if next_highlight
23565                        .range
23566                        .end
23567                        .cmp(&highlight.range.end, &snapshot)
23568                        .is_gt()
23569                    {
23570                        row_highlights[ix].range.end = next_highlight.range.end;
23571                    }
23572                    row_highlights.remove(ix + 1);
23573                } else {
23574                    break;
23575                }
23576            }
23577        }
23578    }
23579
23580    /// Remove any highlighted row ranges of the given type that intersect the
23581    /// given ranges.
23582    pub fn remove_highlighted_rows<T: 'static>(
23583        &mut self,
23584        ranges_to_remove: Vec<Range<Anchor>>,
23585        cx: &mut Context<Self>,
23586    ) {
23587        let snapshot = self.buffer().read(cx).snapshot(cx);
23588        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23589        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23590        row_highlights.retain(|highlight| {
23591            while let Some(range_to_remove) = ranges_to_remove.peek() {
23592                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23593                    Ordering::Less | Ordering::Equal => {
23594                        ranges_to_remove.next();
23595                    }
23596                    Ordering::Greater => {
23597                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23598                            Ordering::Less | Ordering::Equal => {
23599                                return false;
23600                            }
23601                            Ordering::Greater => break,
23602                        }
23603                    }
23604                }
23605            }
23606
23607            true
23608        })
23609    }
23610
23611    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23612    pub fn clear_row_highlights<T: 'static>(&mut self) {
23613        self.highlighted_rows.remove(&TypeId::of::<T>());
23614    }
23615
23616    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23617    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23618        self.highlighted_rows
23619            .get(&TypeId::of::<T>())
23620            .map_or(&[] as &[_], |vec| vec.as_slice())
23621            .iter()
23622            .map(|highlight| (highlight.range.clone(), highlight.color))
23623    }
23624
23625    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23626    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23627    /// Allows to ignore certain kinds of highlights.
23628    pub fn highlighted_display_rows(
23629        &self,
23630        window: &mut Window,
23631        cx: &mut App,
23632    ) -> BTreeMap<DisplayRow, LineHighlight> {
23633        let snapshot = self.snapshot(window, cx);
23634        let mut used_highlight_orders = HashMap::default();
23635        self.highlighted_rows
23636            .iter()
23637            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23638            .fold(
23639                BTreeMap::<DisplayRow, LineHighlight>::new(),
23640                |mut unique_rows, highlight| {
23641                    let start = highlight.range.start.to_display_point(&snapshot);
23642                    let end = highlight.range.end.to_display_point(&snapshot);
23643                    let start_row = start.row().0;
23644                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
23645                    {
23646                        end.row().0.saturating_sub(1)
23647                    } else {
23648                        end.row().0
23649                    };
23650                    for row in start_row..=end_row {
23651                        let used_index =
23652                            used_highlight_orders.entry(row).or_insert(highlight.index);
23653                        if highlight.index >= *used_index {
23654                            *used_index = highlight.index;
23655                            unique_rows.insert(
23656                                DisplayRow(row),
23657                                LineHighlight {
23658                                    include_gutter: highlight.options.include_gutter,
23659                                    border: None,
23660                                    background: highlight.color.into(),
23661                                    type_id: Some(highlight.type_id),
23662                                },
23663                            );
23664                        }
23665                    }
23666                    unique_rows
23667                },
23668            )
23669    }
23670
23671    pub fn highlighted_display_row_for_autoscroll(
23672        &self,
23673        snapshot: &DisplaySnapshot,
23674    ) -> Option<DisplayRow> {
23675        self.highlighted_rows
23676            .values()
23677            .flat_map(|highlighted_rows| highlighted_rows.iter())
23678            .filter_map(|highlight| {
23679                if highlight.options.autoscroll {
23680                    Some(highlight.range.start.to_display_point(snapshot).row())
23681                } else {
23682                    None
23683                }
23684            })
23685            .min()
23686    }
23687
23688    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23689        self.highlight_background(
23690            HighlightKey::SearchWithinRange,
23691            ranges,
23692            |_, colors| colors.colors().editor_document_highlight_read_background,
23693            cx,
23694        )
23695    }
23696
23697    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23698        self.breadcrumb_header = Some(new_header);
23699    }
23700
23701    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23702        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23703    }
23704
23705    pub fn highlight_background(
23706        &mut self,
23707        key: HighlightKey,
23708        ranges: &[Range<Anchor>],
23709        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23710        cx: &mut Context<Self>,
23711    ) {
23712        self.background_highlights
23713            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23714        self.scrollbar_marker_state.dirty = true;
23715        cx.notify();
23716    }
23717
23718    pub fn clear_background_highlights(
23719        &mut self,
23720        key: HighlightKey,
23721        cx: &mut Context<Self>,
23722    ) -> Option<BackgroundHighlight> {
23723        let text_highlights = self.background_highlights.remove(&key)?;
23724        if !text_highlights.1.is_empty() {
23725            self.scrollbar_marker_state.dirty = true;
23726            cx.notify();
23727        }
23728        Some(text_highlights)
23729    }
23730
23731    pub fn highlight_gutter<T: 'static>(
23732        &mut self,
23733        ranges: impl Into<Vec<Range<Anchor>>>,
23734        color_fetcher: fn(&App) -> Hsla,
23735        cx: &mut Context<Self>,
23736    ) {
23737        self.gutter_highlights
23738            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23739        cx.notify();
23740    }
23741
23742    pub fn clear_gutter_highlights<T: 'static>(
23743        &mut self,
23744        cx: &mut Context<Self>,
23745    ) -> Option<GutterHighlight> {
23746        cx.notify();
23747        self.gutter_highlights.remove(&TypeId::of::<T>())
23748    }
23749
23750    pub fn insert_gutter_highlight<T: 'static>(
23751        &mut self,
23752        range: Range<Anchor>,
23753        color_fetcher: fn(&App) -> Hsla,
23754        cx: &mut Context<Self>,
23755    ) {
23756        let snapshot = self.buffer().read(cx).snapshot(cx);
23757        let mut highlights = self
23758            .gutter_highlights
23759            .remove(&TypeId::of::<T>())
23760            .map(|(_, highlights)| highlights)
23761            .unwrap_or_default();
23762        let ix = highlights.binary_search_by(|highlight| {
23763            Ordering::Equal
23764                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23765                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23766        });
23767        if let Err(ix) = ix {
23768            highlights.insert(ix, range);
23769        }
23770        self.gutter_highlights
23771            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23772    }
23773
23774    pub fn remove_gutter_highlights<T: 'static>(
23775        &mut self,
23776        ranges_to_remove: Vec<Range<Anchor>>,
23777        cx: &mut Context<Self>,
23778    ) {
23779        let snapshot = self.buffer().read(cx).snapshot(cx);
23780        let Some((color_fetcher, mut gutter_highlights)) =
23781            self.gutter_highlights.remove(&TypeId::of::<T>())
23782        else {
23783            return;
23784        };
23785        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23786        gutter_highlights.retain(|highlight| {
23787            while let Some(range_to_remove) = ranges_to_remove.peek() {
23788                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23789                    Ordering::Less | Ordering::Equal => {
23790                        ranges_to_remove.next();
23791                    }
23792                    Ordering::Greater => {
23793                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23794                            Ordering::Less | Ordering::Equal => {
23795                                return false;
23796                            }
23797                            Ordering::Greater => break,
23798                        }
23799                    }
23800                }
23801            }
23802
23803            true
23804        });
23805        self.gutter_highlights
23806            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23807    }
23808
23809    #[cfg(any(test, feature = "test-support"))]
23810    pub fn all_text_highlights(
23811        &self,
23812        window: &mut Window,
23813        cx: &mut Context<Self>,
23814    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23815        let snapshot = self.snapshot(window, cx);
23816        self.display_map.update(cx, |display_map, _| {
23817            display_map
23818                .all_text_highlights()
23819                .map(|(_, highlight)| {
23820                    let (style, ranges) = highlight.as_ref();
23821                    (
23822                        *style,
23823                        ranges
23824                            .iter()
23825                            .map(|range| range.clone().to_display_points(&snapshot))
23826                            .collect(),
23827                    )
23828                })
23829                .collect()
23830        })
23831    }
23832
23833    #[cfg(any(test, feature = "test-support"))]
23834    pub fn all_text_background_highlights(
23835        &self,
23836        window: &mut Window,
23837        cx: &mut Context<Self>,
23838    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23839        let snapshot = self.snapshot(window, cx);
23840        let buffer = &snapshot.buffer_snapshot();
23841        let start = buffer.anchor_before(MultiBufferOffset(0));
23842        let end = buffer.anchor_after(buffer.len());
23843        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23844    }
23845
23846    #[cfg(any(test, feature = "test-support"))]
23847    pub fn sorted_background_highlights_in_range(
23848        &self,
23849        search_range: Range<Anchor>,
23850        display_snapshot: &DisplaySnapshot,
23851        theme: &Theme,
23852    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23853        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23854        res.sort_by(|a, b| {
23855            a.0.start
23856                .cmp(&b.0.start)
23857                .then_with(|| a.0.end.cmp(&b.0.end))
23858                .then_with(|| a.1.cmp(&b.1))
23859        });
23860        res
23861    }
23862
23863    #[cfg(any(test, feature = "test-support"))]
23864    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23865        let snapshot = self.buffer().read(cx).snapshot(cx);
23866
23867        let highlights = self
23868            .background_highlights
23869            .get(&HighlightKey::BufferSearchHighlights);
23870
23871        if let Some((_color, ranges)) = highlights {
23872            ranges
23873                .iter()
23874                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23875                .collect_vec()
23876        } else {
23877            vec![]
23878        }
23879    }
23880
23881    fn document_highlights_for_position<'a>(
23882        &'a self,
23883        position: Anchor,
23884        buffer: &'a MultiBufferSnapshot,
23885    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23886        let read_highlights = self
23887            .background_highlights
23888            .get(&HighlightKey::DocumentHighlightRead)
23889            .map(|h| &h.1);
23890        let write_highlights = self
23891            .background_highlights
23892            .get(&HighlightKey::DocumentHighlightWrite)
23893            .map(|h| &h.1);
23894        let left_position = position.bias_left(buffer);
23895        let right_position = position.bias_right(buffer);
23896        read_highlights
23897            .into_iter()
23898            .chain(write_highlights)
23899            .flat_map(move |ranges| {
23900                let start_ix = match ranges.binary_search_by(|probe| {
23901                    let cmp = probe.end.cmp(&left_position, buffer);
23902                    if cmp.is_ge() {
23903                        Ordering::Greater
23904                    } else {
23905                        Ordering::Less
23906                    }
23907                }) {
23908                    Ok(i) | Err(i) => i,
23909                };
23910
23911                ranges[start_ix..]
23912                    .iter()
23913                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23914            })
23915    }
23916
23917    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23918        self.background_highlights
23919            .get(&key)
23920            .is_some_and(|(_, highlights)| !highlights.is_empty())
23921    }
23922
23923    /// Returns all background highlights for a given range.
23924    ///
23925    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23926    pub fn background_highlights_in_range(
23927        &self,
23928        search_range: Range<Anchor>,
23929        display_snapshot: &DisplaySnapshot,
23930        theme: &Theme,
23931    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23932        let mut results = Vec::new();
23933        for (color_fetcher, ranges) in self.background_highlights.values() {
23934            let start_ix = match ranges.binary_search_by(|probe| {
23935                let cmp = probe
23936                    .end
23937                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23938                if cmp.is_gt() {
23939                    Ordering::Greater
23940                } else {
23941                    Ordering::Less
23942                }
23943            }) {
23944                Ok(i) | Err(i) => i,
23945            };
23946            for (index, range) in ranges[start_ix..].iter().enumerate() {
23947                if range
23948                    .start
23949                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23950                    .is_ge()
23951                {
23952                    break;
23953                }
23954
23955                let color = color_fetcher(&(start_ix + index), theme);
23956                let start = range.start.to_display_point(display_snapshot);
23957                let end = range.end.to_display_point(display_snapshot);
23958                results.push((start..end, color))
23959            }
23960        }
23961        results
23962    }
23963
23964    pub fn gutter_highlights_in_range(
23965        &self,
23966        search_range: Range<Anchor>,
23967        display_snapshot: &DisplaySnapshot,
23968        cx: &App,
23969    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23970        let mut results = Vec::new();
23971        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23972            let color = color_fetcher(cx);
23973            let start_ix = match ranges.binary_search_by(|probe| {
23974                let cmp = probe
23975                    .end
23976                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23977                if cmp.is_gt() {
23978                    Ordering::Greater
23979                } else {
23980                    Ordering::Less
23981                }
23982            }) {
23983                Ok(i) | Err(i) => i,
23984            };
23985            for range in &ranges[start_ix..] {
23986                if range
23987                    .start
23988                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23989                    .is_ge()
23990                {
23991                    break;
23992                }
23993
23994                let start = range.start.to_display_point(display_snapshot);
23995                let end = range.end.to_display_point(display_snapshot);
23996                results.push((start..end, color))
23997            }
23998        }
23999        results
24000    }
24001
24002    /// Get the text ranges corresponding to the redaction query
24003    pub fn redacted_ranges(
24004        &self,
24005        search_range: Range<Anchor>,
24006        display_snapshot: &DisplaySnapshot,
24007        cx: &App,
24008    ) -> Vec<Range<DisplayPoint>> {
24009        display_snapshot
24010            .buffer_snapshot()
24011            .redacted_ranges(search_range, |file| {
24012                if let Some(file) = file {
24013                    file.is_private()
24014                        && EditorSettings::get(
24015                            Some(SettingsLocation {
24016                                worktree_id: file.worktree_id(cx),
24017                                path: file.path().as_ref(),
24018                            }),
24019                            cx,
24020                        )
24021                        .redact_private_values
24022                } else {
24023                    false
24024                }
24025            })
24026            .map(|range| {
24027                range.start.to_display_point(display_snapshot)
24028                    ..range.end.to_display_point(display_snapshot)
24029            })
24030            .collect()
24031    }
24032
24033    pub fn highlight_text_key(
24034        &mut self,
24035        key: HighlightKey,
24036        ranges: Vec<Range<Anchor>>,
24037        style: HighlightStyle,
24038        merge: bool,
24039        cx: &mut Context<Self>,
24040    ) {
24041        self.display_map.update(cx, |map, cx| {
24042            map.highlight_text(key, ranges, style, merge, cx);
24043        });
24044        cx.notify();
24045    }
24046
24047    pub fn highlight_text(
24048        &mut self,
24049        key: HighlightKey,
24050        ranges: Vec<Range<Anchor>>,
24051        style: HighlightStyle,
24052        cx: &mut Context<Self>,
24053    ) {
24054        self.display_map.update(cx, |map, cx| {
24055            map.highlight_text(key, ranges, style, false, cx)
24056        });
24057        cx.notify();
24058    }
24059
24060    pub fn text_highlights<'a>(
24061        &'a self,
24062        key: HighlightKey,
24063        cx: &'a App,
24064    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24065        self.display_map.read(cx).text_highlights(key)
24066    }
24067
24068    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24069        let cleared = self
24070            .display_map
24071            .update(cx, |map, _| map.clear_highlights(key));
24072        if cleared {
24073            cx.notify();
24074        }
24075    }
24076
24077    pub fn clear_highlights_with(
24078        &mut self,
24079        f: &mut dyn FnMut(&HighlightKey) -> bool,
24080        cx: &mut Context<Self>,
24081    ) {
24082        let cleared = self
24083            .display_map
24084            .update(cx, |map, _| map.clear_highlights_with(f));
24085        if cleared {
24086            cx.notify();
24087        }
24088    }
24089
24090    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24091        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24092            && self.focus_handle.is_focused(window)
24093    }
24094
24095    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24096        self.show_cursor_when_unfocused = is_enabled;
24097        cx.notify();
24098    }
24099
24100    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24101        cx.notify();
24102    }
24103
24104    fn on_debug_session_event(
24105        &mut self,
24106        _session: Entity<Session>,
24107        event: &SessionEvent,
24108        cx: &mut Context<Self>,
24109    ) {
24110        if let SessionEvent::InvalidateInlineValue = event {
24111            self.refresh_inline_values(cx);
24112        }
24113    }
24114
24115    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24116        let Some(semantics) = self.semantics_provider.clone() else {
24117            return;
24118        };
24119
24120        if !self.inline_value_cache.enabled {
24121            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24122            self.splice_inlays(&inlays, Vec::new(), cx);
24123            return;
24124        }
24125
24126        let current_execution_position = self
24127            .highlighted_rows
24128            .get(&TypeId::of::<ActiveDebugLine>())
24129            .and_then(|lines| lines.last().map(|line| line.range.end));
24130
24131        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24132            let inline_values = editor
24133                .update(cx, |editor, cx| {
24134                    let Some(current_execution_position) = current_execution_position else {
24135                        return Some(Task::ready(Ok(Vec::new())));
24136                    };
24137
24138                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
24139                        let snapshot = buffer.snapshot(cx);
24140
24141                        let excerpt = snapshot.excerpt_containing(
24142                            current_execution_position..current_execution_position,
24143                        )?;
24144
24145                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
24146                    })?;
24147
24148                    if current_execution_position
24149                        .text_anchor
24150                        .buffer_id
24151                        .is_some_and(|id| id != buffer.read(cx).remote_id())
24152                    {
24153                        return Some(Task::ready(Ok(Vec::new())));
24154                    }
24155
24156                    let range =
24157                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
24158
24159                    semantics.inline_values(buffer, range, cx)
24160                })
24161                .ok()
24162                .flatten()?
24163                .await
24164                .context("refreshing debugger inlays")
24165                .log_err()?;
24166
24167            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24168
24169            for (buffer_id, inline_value) in inline_values
24170                .into_iter()
24171                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
24172            {
24173                buffer_inline_values
24174                    .entry(buffer_id)
24175                    .or_default()
24176                    .push(inline_value);
24177            }
24178
24179            editor
24180                .update(cx, |editor, cx| {
24181                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24182                    let mut new_inlays = Vec::default();
24183
24184                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
24185                        let buffer_id = buffer_snapshot.remote_id();
24186                        buffer_inline_values
24187                            .get(&buffer_id)
24188                            .into_iter()
24189                            .flatten()
24190                            .for_each(|hint| {
24191                                let inlay = Inlay::debugger(
24192                                    post_inc(&mut editor.next_inlay_id),
24193                                    Anchor::in_buffer(excerpt_id, hint.position),
24194                                    hint.text(),
24195                                );
24196                                if !inlay.text().chars().contains(&'\n') {
24197                                    new_inlays.push(inlay);
24198                                }
24199                            });
24200                    }
24201
24202                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24203                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24204
24205                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24206                })
24207                .ok()?;
24208            Some(())
24209        });
24210    }
24211
24212    fn on_buffer_event(
24213        &mut self,
24214        multibuffer: &Entity<MultiBuffer>,
24215        event: &multi_buffer::Event,
24216        window: &mut Window,
24217        cx: &mut Context<Self>,
24218    ) {
24219        match event {
24220            multi_buffer::Event::Edited {
24221                edited_buffer,
24222                is_local,
24223            } => {
24224                self.scrollbar_marker_state.dirty = true;
24225                self.active_indent_guides_state.dirty = true;
24226                self.refresh_active_diagnostics(cx);
24227                self.refresh_code_actions(window, cx);
24228                self.refresh_single_line_folds(window, cx);
24229                let snapshot = self.snapshot(window, cx);
24230                self.refresh_matching_bracket_highlights(&snapshot, cx);
24231                self.refresh_outline_symbols_at_cursor(cx);
24232                self.refresh_sticky_headers(&snapshot, cx);
24233                if *is_local && self.has_active_edit_prediction() {
24234                    self.update_visible_edit_prediction(window, cx);
24235                }
24236
24237                // Clean up orphaned review comments after edits
24238                self.cleanup_orphaned_review_comments(cx);
24239
24240                if let Some(buffer) = edited_buffer {
24241                    if buffer.read(cx).file().is_none() {
24242                        cx.emit(EditorEvent::TitleChanged);
24243                    }
24244
24245                    if self.project.is_some() {
24246                        let buffer_id = buffer.read(cx).remote_id();
24247                        self.register_buffer(buffer_id, cx);
24248                        self.update_lsp_data(Some(buffer_id), window, cx);
24249                        self.refresh_inlay_hints(
24250                            InlayHintRefreshReason::BufferEdited(buffer_id),
24251                            cx,
24252                        );
24253                    }
24254                }
24255
24256                cx.emit(EditorEvent::BufferEdited);
24257                cx.emit(SearchEvent::MatchesInvalidated);
24258
24259                let Some(project) = &self.project else { return };
24260                let (telemetry, is_via_ssh) = {
24261                    let project = project.read(cx);
24262                    let telemetry = project.client().telemetry().clone();
24263                    let is_via_ssh = project.is_via_remote_server();
24264                    (telemetry, is_via_ssh)
24265                };
24266                telemetry.log_edit_event("editor", is_via_ssh);
24267            }
24268            multi_buffer::Event::ExcerptsAdded {
24269                buffer,
24270                predecessor,
24271                excerpts,
24272            } => {
24273                let buffer_id = buffer.read(cx).remote_id();
24274                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24275                    && let Some(project) = &self.project
24276                {
24277                    update_uncommitted_diff_for_buffer(
24278                        cx.entity(),
24279                        project,
24280                        [buffer.clone()],
24281                        self.buffer.clone(),
24282                        cx,
24283                    )
24284                    .detach();
24285                }
24286                self.semantic_token_state
24287                    .invalidate_buffer(&buffer.read(cx).remote_id());
24288                self.update_lsp_data(Some(buffer_id), window, cx);
24289                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24290                self.refresh_runnables(None, window, cx);
24291                self.colorize_brackets(false, cx);
24292                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24293                cx.emit(EditorEvent::ExcerptsAdded {
24294                    buffer: buffer.clone(),
24295                    predecessor: *predecessor,
24296                    excerpts: excerpts.clone(),
24297                });
24298            }
24299            multi_buffer::Event::ExcerptsRemoved {
24300                ids,
24301                removed_buffer_ids,
24302            } => {
24303                if let Some(inlay_hints) = &mut self.inlay_hints {
24304                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24305                }
24306                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
24307                for buffer_id in removed_buffer_ids {
24308                    self.registered_buffers.remove(buffer_id);
24309                    self.clear_runnables(Some(*buffer_id));
24310                    self.semantic_token_state.invalidate_buffer(buffer_id);
24311                    self.display_map.update(cx, |display_map, cx| {
24312                        display_map.invalidate_semantic_highlights(*buffer_id);
24313                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24314                    });
24315                }
24316
24317                self.display_map.update(cx, |display_map, cx| {
24318                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24319                });
24320
24321                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24322                cx.emit(EditorEvent::ExcerptsRemoved {
24323                    ids: ids.clone(),
24324                    removed_buffer_ids: removed_buffer_ids.clone(),
24325                });
24326            }
24327            multi_buffer::Event::ExcerptsEdited {
24328                excerpt_ids,
24329                buffer_ids,
24330            } => {
24331                self.display_map.update(cx, |map, cx| {
24332                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24333                });
24334                cx.emit(EditorEvent::ExcerptsEdited {
24335                    ids: excerpt_ids.clone(),
24336                });
24337            }
24338            multi_buffer::Event::ExcerptsExpanded { ids } => {
24339                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24340                self.refresh_document_highlights(cx);
24341                let snapshot = multibuffer.read(cx).snapshot(cx);
24342                for id in ids {
24343                    self.bracket_fetched_tree_sitter_chunks.remove(id);
24344                    if let Some(buffer) = snapshot.buffer_for_excerpt(*id) {
24345                        self.semantic_token_state
24346                            .invalidate_buffer(&buffer.remote_id());
24347                    }
24348                }
24349                self.colorize_brackets(false, cx);
24350                self.update_lsp_data(None, window, cx);
24351                self.refresh_runnables(None, window, cx);
24352                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
24353            }
24354            multi_buffer::Event::Reparsed(buffer_id) => {
24355                self.refresh_runnables(Some(*buffer_id), window, cx);
24356                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24357                self.colorize_brackets(true, cx);
24358                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24359
24360                cx.emit(EditorEvent::Reparsed(*buffer_id));
24361            }
24362            multi_buffer::Event::DiffHunksToggled => {
24363                self.refresh_runnables(None, window, cx);
24364            }
24365            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24366                if !is_fresh_language {
24367                    self.registered_buffers.remove(&buffer_id);
24368                }
24369                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24370                cx.emit(EditorEvent::Reparsed(*buffer_id));
24371                self.update_edit_prediction_settings(cx);
24372                cx.notify();
24373            }
24374            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24375            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24376            multi_buffer::Event::FileHandleChanged
24377            | multi_buffer::Event::Reloaded
24378            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24379            multi_buffer::Event::DiagnosticsUpdated => {
24380                self.update_diagnostics_state(window, cx);
24381            }
24382            _ => {}
24383        };
24384    }
24385
24386    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24387        if !self.diagnostics_enabled() {
24388            return;
24389        }
24390        self.refresh_active_diagnostics(cx);
24391        self.refresh_inline_diagnostics(true, window, cx);
24392        self.scrollbar_marker_state.dirty = true;
24393        cx.notify();
24394    }
24395
24396    pub fn start_temporary_diff_override(&mut self) {
24397        self.load_diff_task.take();
24398        self.temporary_diff_override = true;
24399    }
24400
24401    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24402        self.temporary_diff_override = false;
24403        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24404        self.buffer.update(cx, |buffer, cx| {
24405            buffer.set_all_diff_hunks_collapsed(cx);
24406        });
24407
24408        if let Some(project) = self.project.clone() {
24409            self.load_diff_task = Some(
24410                update_uncommitted_diff_for_buffer(
24411                    cx.entity(),
24412                    &project,
24413                    self.buffer.read(cx).all_buffers(),
24414                    self.buffer.clone(),
24415                    cx,
24416                )
24417                .shared(),
24418            );
24419        }
24420    }
24421
24422    fn on_display_map_changed(
24423        &mut self,
24424        _: Entity<DisplayMap>,
24425        _: &mut Window,
24426        cx: &mut Context<Self>,
24427    ) {
24428        cx.notify();
24429    }
24430
24431    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24432        if !self.mode.is_full() {
24433            return None;
24434        }
24435
24436        let theme_settings = theme::ThemeSettings::get_global(cx);
24437        let theme = cx.theme();
24438        let accent_colors = theme.accents().clone();
24439
24440        let accent_overrides = theme_settings
24441            .theme_overrides
24442            .get(theme.name.as_ref())
24443            .map(|theme_style| &theme_style.accents)
24444            .into_iter()
24445            .flatten()
24446            .chain(
24447                theme_settings
24448                    .experimental_theme_overrides
24449                    .as_ref()
24450                    .map(|overrides| &overrides.accents)
24451                    .into_iter()
24452                    .flatten(),
24453            )
24454            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24455            .collect();
24456
24457        Some(AccentData {
24458            colors: accent_colors,
24459            overrides: accent_overrides,
24460        })
24461    }
24462
24463    fn fetch_applicable_language_settings(
24464        &self,
24465        cx: &App,
24466    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24467        if !self.mode.is_full() {
24468            return HashMap::default();
24469        }
24470
24471        self.buffer().read(cx).all_buffers().into_iter().fold(
24472            HashMap::default(),
24473            |mut acc, buffer| {
24474                let buffer = buffer.read(cx);
24475                let language = buffer.language().map(|language| language.name());
24476                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24477                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24478                }
24479                acc
24480            },
24481        )
24482    }
24483
24484    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24485        let new_language_settings = self.fetch_applicable_language_settings(cx);
24486        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24487        self.applicable_language_settings = new_language_settings;
24488
24489        let new_accents = self.fetch_accent_data(cx);
24490        let accents_changed = new_accents != self.accent_data;
24491        self.accent_data = new_accents;
24492
24493        if self.diagnostics_enabled() {
24494            let new_severity = EditorSettings::get_global(cx)
24495                .diagnostics_max_severity
24496                .unwrap_or(DiagnosticSeverity::Hint);
24497            self.set_max_diagnostics_severity(new_severity, cx);
24498        }
24499        self.refresh_runnables(None, window, cx);
24500        self.update_edit_prediction_settings(cx);
24501        self.refresh_edit_prediction(true, false, window, cx);
24502        self.refresh_inline_values(cx);
24503
24504        let old_cursor_shape = self.cursor_shape;
24505        let old_show_breadcrumbs = self.show_breadcrumbs;
24506
24507        {
24508            let editor_settings = EditorSettings::get_global(cx);
24509            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24510            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24511            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24512            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24513        }
24514
24515        if old_cursor_shape != self.cursor_shape {
24516            cx.emit(EditorEvent::CursorShapeChanged);
24517        }
24518
24519        if old_show_breadcrumbs != self.show_breadcrumbs {
24520            cx.emit(EditorEvent::BreadcrumbsChanged);
24521        }
24522
24523        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24524            let project_settings = ProjectSettings::get_global(cx);
24525            (
24526                project_settings.session.restore_unsaved_buffers,
24527                project_settings.diagnostics.inline.enabled,
24528                project_settings.git.inline_blame.enabled,
24529            )
24530        };
24531        self.buffer_serialization = self
24532            .should_serialize_buffer()
24533            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24534
24535        if self.mode.is_full() {
24536            if self.show_inline_diagnostics != show_inline_diagnostics {
24537                self.show_inline_diagnostics = show_inline_diagnostics;
24538                self.refresh_inline_diagnostics(false, window, cx);
24539            }
24540
24541            if self.git_blame_inline_enabled != inline_blame_enabled {
24542                self.toggle_git_blame_inline_internal(false, window, cx);
24543            }
24544
24545            let minimap_settings = EditorSettings::get_global(cx).minimap;
24546            if self.minimap_visibility != MinimapVisibility::Disabled {
24547                if self.minimap_visibility.settings_visibility()
24548                    != minimap_settings.minimap_enabled()
24549                {
24550                    self.set_minimap_visibility(
24551                        MinimapVisibility::for_mode(self.mode(), cx),
24552                        window,
24553                        cx,
24554                    );
24555                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24556                    minimap_entity.update(cx, |minimap_editor, cx| {
24557                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24558                    })
24559                }
24560            }
24561
24562            if language_settings_changed || accents_changed {
24563                self.colorize_brackets(true, cx);
24564            }
24565
24566            if language_settings_changed {
24567                self.clear_disabled_lsp_folding_ranges(window, cx);
24568                self.refresh_document_symbols(None, cx);
24569            }
24570
24571            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24572                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24573            }) {
24574                if !inlay_splice.is_empty() {
24575                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24576                }
24577                self.refresh_document_colors(None, window, cx);
24578            }
24579
24580            self.refresh_inlay_hints(
24581                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24582                    self.selections.newest_anchor().head(),
24583                    &self.buffer.read(cx).snapshot(cx),
24584                    cx,
24585                )),
24586                cx,
24587            );
24588
24589            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24590                .global_lsp_settings
24591                .semantic_token_rules
24592                .clone();
24593            let semantic_token_rules_changed = self
24594                .semantic_token_state
24595                .update_rules(new_semantic_token_rules);
24596            if language_settings_changed || semantic_token_rules_changed {
24597                self.invalidate_semantic_tokens(None);
24598                self.refresh_semantic_tokens(None, None, cx);
24599            }
24600        }
24601
24602        cx.notify();
24603    }
24604
24605    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24606        if !self.mode.is_full() {
24607            return;
24608        }
24609
24610        let new_accents = self.fetch_accent_data(cx);
24611        if new_accents != self.accent_data {
24612            self.accent_data = new_accents;
24613            self.colorize_brackets(true, cx);
24614        }
24615
24616        self.invalidate_semantic_tokens(None);
24617        self.refresh_semantic_tokens(None, None, cx);
24618    }
24619
24620    pub fn set_searchable(&mut self, searchable: bool) {
24621        self.searchable = searchable;
24622    }
24623
24624    pub fn searchable(&self) -> bool {
24625        self.searchable
24626    }
24627
24628    pub fn open_excerpts_in_split(
24629        &mut self,
24630        _: &OpenExcerptsSplit,
24631        window: &mut Window,
24632        cx: &mut Context<Self>,
24633    ) {
24634        self.open_excerpts_common(None, true, window, cx)
24635    }
24636
24637    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24638        self.open_excerpts_common(None, false, window, cx)
24639    }
24640
24641    pub(crate) fn open_excerpts_common(
24642        &mut self,
24643        jump_data: Option<JumpData>,
24644        split: bool,
24645        window: &mut Window,
24646        cx: &mut Context<Self>,
24647    ) {
24648        if self.buffer.read(cx).is_singleton() {
24649            cx.propagate();
24650            return;
24651        }
24652
24653        let mut new_selections_by_buffer = HashMap::default();
24654        match &jump_data {
24655            Some(JumpData::MultiBufferPoint {
24656                excerpt_id,
24657                position,
24658                anchor,
24659                line_offset_from_top,
24660            }) => {
24661                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
24662                if let Some(buffer) = multi_buffer_snapshot
24663                    .buffer_id_for_excerpt(*excerpt_id)
24664                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
24665                {
24666                    let buffer_snapshot = buffer.read(cx).snapshot();
24667                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
24668                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24669                    } else {
24670                        buffer_snapshot.clip_point(*position, Bias::Left)
24671                    };
24672                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24673                    new_selections_by_buffer.insert(
24674                        buffer,
24675                        (
24676                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24677                            Some(*line_offset_from_top),
24678                        ),
24679                    );
24680                }
24681            }
24682            Some(JumpData::MultiBufferRow {
24683                row,
24684                line_offset_from_top,
24685            }) => {
24686                let point = MultiBufferPoint::new(row.0, 0);
24687                if let Some((buffer, buffer_point, _)) =
24688                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24689                {
24690                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24691                    new_selections_by_buffer
24692                        .entry(buffer)
24693                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24694                        .0
24695                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24696                }
24697            }
24698            None => {
24699                let selections = self
24700                    .selections
24701                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24702                let multi_buffer = self.buffer.read(cx);
24703                for selection in selections {
24704                    for (snapshot, range, _, anchor) in multi_buffer
24705                        .snapshot(cx)
24706                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24707                    {
24708                        if let Some(anchor) = anchor {
24709                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24710                            else {
24711                                continue;
24712                            };
24713                            let offset = text::ToOffset::to_offset(
24714                                &anchor.text_anchor,
24715                                &buffer_handle.read(cx).snapshot(),
24716                            );
24717                            let range = BufferOffset(offset)..BufferOffset(offset);
24718                            new_selections_by_buffer
24719                                .entry(buffer_handle)
24720                                .or_insert((Vec::new(), None))
24721                                .0
24722                                .push(range)
24723                        } else {
24724                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24725                            else {
24726                                continue;
24727                            };
24728                            new_selections_by_buffer
24729                                .entry(buffer_handle)
24730                                .or_insert((Vec::new(), None))
24731                                .0
24732                                .push(range)
24733                        }
24734                    }
24735                }
24736            }
24737        }
24738
24739        if self.delegate_open_excerpts {
24740            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24741                .into_iter()
24742                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24743                .collect();
24744            if !selections_by_buffer.is_empty() {
24745                cx.emit(EditorEvent::OpenExcerptsRequested {
24746                    selections_by_buffer,
24747                    split,
24748                });
24749            }
24750            return;
24751        }
24752
24753        let Some(workspace) = self.workspace() else {
24754            cx.propagate();
24755            return;
24756        };
24757
24758        new_selections_by_buffer
24759            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24760
24761        if new_selections_by_buffer.is_empty() {
24762            return;
24763        }
24764
24765        Self::open_buffers_in_workspace(
24766            workspace.downgrade(),
24767            new_selections_by_buffer,
24768            split,
24769            window,
24770            cx,
24771        );
24772    }
24773
24774    pub(crate) fn open_buffers_in_workspace(
24775        workspace: WeakEntity<Workspace>,
24776        new_selections_by_buffer: HashMap<
24777            Entity<language::Buffer>,
24778            (Vec<Range<BufferOffset>>, Option<u32>),
24779        >,
24780        split: bool,
24781        window: &mut Window,
24782        cx: &mut App,
24783    ) {
24784        // We defer the pane interaction because we ourselves are a workspace item
24785        // and activating a new item causes the pane to call a method on us reentrantly,
24786        // which panics if we're on the stack.
24787        window.defer(cx, move |window, cx| {
24788            workspace
24789                .update(cx, |workspace, cx| {
24790                    let pane = if split {
24791                        workspace.adjacent_pane(window, cx)
24792                    } else {
24793                        workspace.active_pane().clone()
24794                    };
24795
24796                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24797                        let buffer_read = buffer.read(cx);
24798                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24799                            (true, project::File::from_dyn(Some(file)).is_some())
24800                        } else {
24801                            (false, false)
24802                        };
24803
24804                        // If project file is none workspace.open_project_item will fail to open the excerpt
24805                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24806                        // so we check if there's a tab match in that case first
24807                        let editor = (!has_file || !is_project_file)
24808                            .then(|| {
24809                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24810                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24811                                // Instead, we try to activate the existing editor in the pane first.
24812                                let (editor, pane_item_index, pane_item_id) =
24813                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24814                                        let editor = item.downcast::<Editor>()?;
24815                                        let singleton_buffer =
24816                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24817                                        if singleton_buffer == buffer {
24818                                            Some((editor, i, item.item_id()))
24819                                        } else {
24820                                            None
24821                                        }
24822                                    })?;
24823                                pane.update(cx, |pane, cx| {
24824                                    pane.activate_item(pane_item_index, true, true, window, cx);
24825                                    if !PreviewTabsSettings::get_global(cx)
24826                                        .enable_preview_from_multibuffer
24827                                    {
24828                                        pane.unpreview_item_if_preview(pane_item_id);
24829                                    }
24830                                });
24831                                Some(editor)
24832                            })
24833                            .flatten()
24834                            .unwrap_or_else(|| {
24835                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24836                                    .enable_keep_preview_on_code_navigation;
24837                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24838                                    .enable_preview_from_multibuffer;
24839                                workspace.open_project_item::<Self>(
24840                                    pane.clone(),
24841                                    buffer,
24842                                    true,
24843                                    true,
24844                                    keep_old_preview,
24845                                    allow_new_preview,
24846                                    window,
24847                                    cx,
24848                                )
24849                            });
24850
24851                        editor.update(cx, |editor, cx| {
24852                            if has_file && !is_project_file {
24853                                editor.set_read_only(true);
24854                            }
24855                            let autoscroll = match scroll_offset {
24856                                Some(scroll_offset) => {
24857                                    Autoscroll::top_relative(scroll_offset as usize)
24858                                }
24859                                None => Autoscroll::newest(),
24860                            };
24861                            let nav_history = editor.nav_history.take();
24862                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24863                            let Some((excerpt_id, _, buffer_snapshot)) =
24864                                multibuffer_snapshot.as_singleton()
24865                            else {
24866                                return;
24867                            };
24868                            editor.change_selections(
24869                                SelectionEffects::scroll(autoscroll),
24870                                window,
24871                                cx,
24872                                |s| {
24873                                    s.select_ranges(ranges.into_iter().map(|range| {
24874                                        let range = buffer_snapshot.anchor_before(range.start)
24875                                            ..buffer_snapshot.anchor_after(range.end);
24876                                        multibuffer_snapshot
24877                                            .anchor_range_in_excerpt(excerpt_id, range)
24878                                            .unwrap()
24879                                    }));
24880                                },
24881                            );
24882                            editor.nav_history = nav_history;
24883                        });
24884                    }
24885                })
24886                .ok();
24887        });
24888    }
24889
24890    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24891        let snapshot = self.buffer.read(cx).read(cx);
24892        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24893        Some(
24894            ranges
24895                .iter()
24896                .map(move |range| {
24897                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24898                })
24899                .collect(),
24900        )
24901    }
24902
24903    fn selection_replacement_ranges(
24904        &self,
24905        range: Range<MultiBufferOffsetUtf16>,
24906        cx: &mut App,
24907    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24908        let selections = self
24909            .selections
24910            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24911        let newest_selection = selections
24912            .iter()
24913            .max_by_key(|selection| selection.id)
24914            .unwrap();
24915        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24916        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24917        let snapshot = self.buffer.read(cx).read(cx);
24918        selections
24919            .into_iter()
24920            .map(|mut selection| {
24921                selection.start.0.0 =
24922                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24923                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24924                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24925                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24926            })
24927            .collect()
24928    }
24929
24930    fn report_editor_event(
24931        &self,
24932        reported_event: ReportEditorEvent,
24933        file_extension: Option<String>,
24934        cx: &App,
24935    ) {
24936        if cfg!(any(test, feature = "test-support")) {
24937            return;
24938        }
24939
24940        let Some(project) = &self.project else { return };
24941
24942        // If None, we are in a file without an extension
24943        let file = self
24944            .buffer
24945            .read(cx)
24946            .as_singleton()
24947            .and_then(|b| b.read(cx).file());
24948        let file_extension = file_extension.or(file
24949            .as_ref()
24950            .and_then(|file| Path::new(file.file_name(cx)).extension())
24951            .and_then(|e| e.to_str())
24952            .map(|a| a.to_string()));
24953
24954        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24955            .map(|vim_mode| vim_mode.0)
24956            .unwrap_or(false);
24957
24958        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24959        let copilot_enabled = edit_predictions_provider
24960            == language::language_settings::EditPredictionProvider::Copilot;
24961        let copilot_enabled_for_language = self
24962            .buffer
24963            .read(cx)
24964            .language_settings(cx)
24965            .show_edit_predictions;
24966
24967        let project = project.read(cx);
24968        let event_type = reported_event.event_type();
24969
24970        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24971            telemetry::event!(
24972                event_type,
24973                type = if auto_saved {"autosave"} else {"manual"},
24974                file_extension,
24975                vim_mode,
24976                copilot_enabled,
24977                copilot_enabled_for_language,
24978                edit_predictions_provider,
24979                is_via_ssh = project.is_via_remote_server(),
24980            );
24981        } else {
24982            telemetry::event!(
24983                event_type,
24984                file_extension,
24985                vim_mode,
24986                copilot_enabled,
24987                copilot_enabled_for_language,
24988                edit_predictions_provider,
24989                is_via_ssh = project.is_via_remote_server(),
24990            );
24991        };
24992    }
24993
24994    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24995    /// with each line being an array of {text, highlight} objects.
24996    fn copy_highlight_json(
24997        &mut self,
24998        _: &CopyHighlightJson,
24999        window: &mut Window,
25000        cx: &mut Context<Self>,
25001    ) {
25002        #[derive(Serialize)]
25003        struct Chunk<'a> {
25004            text: String,
25005            highlight: Option<&'a str>,
25006        }
25007
25008        let snapshot = self.buffer.read(cx).snapshot(cx);
25009        let range = self
25010            .selected_text_range(false, window, cx)
25011            .and_then(|selection| {
25012                if selection.range.is_empty() {
25013                    None
25014                } else {
25015                    Some(
25016                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
25017                            selection.range.start,
25018                        )))
25019                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
25020                                selection.range.end,
25021                            ))),
25022                    )
25023                }
25024            })
25025            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
25026
25027        let chunks = snapshot.chunks(range, true);
25028        let mut lines = Vec::new();
25029        let mut line: VecDeque<Chunk> = VecDeque::new();
25030
25031        let Some(style) = self.style.as_ref() else {
25032            return;
25033        };
25034
25035        for chunk in chunks {
25036            let highlight = chunk
25037                .syntax_highlight_id
25038                .and_then(|id| id.name(&style.syntax));
25039            let mut chunk_lines = chunk.text.split('\n').peekable();
25040            while let Some(text) = chunk_lines.next() {
25041                let mut merged_with_last_token = false;
25042                if let Some(last_token) = line.back_mut()
25043                    && last_token.highlight == highlight
25044                {
25045                    last_token.text.push_str(text);
25046                    merged_with_last_token = true;
25047                }
25048
25049                if !merged_with_last_token {
25050                    line.push_back(Chunk {
25051                        text: text.into(),
25052                        highlight,
25053                    });
25054                }
25055
25056                if chunk_lines.peek().is_some() {
25057                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25058                        line.pop_front();
25059                    }
25060                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25061                        line.pop_back();
25062                    }
25063
25064                    lines.push(mem::take(&mut line));
25065                }
25066            }
25067        }
25068
25069        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25070            return;
25071        };
25072        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25073    }
25074
25075    pub fn open_context_menu(
25076        &mut self,
25077        _: &OpenContextMenu,
25078        window: &mut Window,
25079        cx: &mut Context<Self>,
25080    ) {
25081        self.request_autoscroll(Autoscroll::newest(), cx);
25082        let position = self
25083            .selections
25084            .newest_display(&self.display_snapshot(cx))
25085            .start;
25086        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25087    }
25088
25089    pub fn replay_insert_event(
25090        &mut self,
25091        text: &str,
25092        relative_utf16_range: Option<Range<isize>>,
25093        window: &mut Window,
25094        cx: &mut Context<Self>,
25095    ) {
25096        if !self.input_enabled {
25097            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25098            return;
25099        }
25100        if let Some(relative_utf16_range) = relative_utf16_range {
25101            let selections = self
25102                .selections
25103                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25104            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25105                let new_ranges = selections.into_iter().map(|range| {
25106                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25107                        range
25108                            .head()
25109                            .0
25110                            .0
25111                            .saturating_add_signed(relative_utf16_range.start),
25112                    ));
25113                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25114                        range
25115                            .head()
25116                            .0
25117                            .0
25118                            .saturating_add_signed(relative_utf16_range.end),
25119                    ));
25120                    start..end
25121                });
25122                s.select_ranges(new_ranges);
25123            });
25124        }
25125
25126        self.handle_input(text, window, cx);
25127    }
25128
25129    pub fn is_focused(&self, window: &Window) -> bool {
25130        self.focus_handle.is_focused(window)
25131    }
25132
25133    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25134        cx.emit(EditorEvent::Focused);
25135
25136        if let Some(descendant) = self
25137            .last_focused_descendant
25138            .take()
25139            .and_then(|descendant| descendant.upgrade())
25140        {
25141            window.focus(&descendant, cx);
25142        } else {
25143            if let Some(blame) = self.blame.as_ref() {
25144                blame.update(cx, GitBlame::focus)
25145            }
25146
25147            self.blink_manager.update(cx, BlinkManager::enable);
25148            self.show_cursor_names(window, cx);
25149            self.buffer.update(cx, |buffer, cx| {
25150                buffer.finalize_last_transaction(cx);
25151                if self.leader_id.is_none() {
25152                    buffer.set_active_selections(
25153                        &self.selections.disjoint_anchors_arc(),
25154                        self.selections.line_mode(),
25155                        self.cursor_shape,
25156                        cx,
25157                    );
25158                }
25159            });
25160
25161            if let Some(position_map) = self.last_position_map.clone()
25162                && !self.mouse_cursor_hidden
25163            {
25164                EditorElement::mouse_moved(
25165                    self,
25166                    &MouseMoveEvent {
25167                        position: window.mouse_position(),
25168                        pressed_button: None,
25169                        modifiers: window.modifiers(),
25170                    },
25171                    &position_map,
25172                    None,
25173                    window,
25174                    cx,
25175                );
25176            }
25177        }
25178    }
25179
25180    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25181        cx.emit(EditorEvent::FocusedIn)
25182    }
25183
25184    fn handle_focus_out(
25185        &mut self,
25186        event: FocusOutEvent,
25187        _window: &mut Window,
25188        cx: &mut Context<Self>,
25189    ) {
25190        if event.blurred != self.focus_handle {
25191            self.last_focused_descendant = Some(event.blurred);
25192        }
25193        self.selection_drag_state = SelectionDragState::None;
25194        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25195    }
25196
25197    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25198        self.blink_manager.update(cx, BlinkManager::disable);
25199        self.buffer
25200            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25201
25202        if let Some(blame) = self.blame.as_ref() {
25203            blame.update(cx, GitBlame::blur)
25204        }
25205        if !self.hover_state.focused(window, cx) {
25206            hide_hover(self, cx);
25207        }
25208        if !self
25209            .context_menu
25210            .borrow()
25211            .as_ref()
25212            .is_some_and(|context_menu| context_menu.focused(window, cx))
25213        {
25214            self.hide_context_menu(window, cx);
25215        }
25216        self.take_active_edit_prediction(true, cx);
25217        cx.emit(EditorEvent::Blurred);
25218        cx.notify();
25219    }
25220
25221    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25222        let mut pending: String = window
25223            .pending_input_keystrokes()
25224            .into_iter()
25225            .flatten()
25226            .filter_map(|keystroke| keystroke.key_char.clone())
25227            .collect();
25228
25229        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25230            pending = "".to_string();
25231        }
25232
25233        let existing_pending = self
25234            .text_highlights(HighlightKey::PendingInput, cx)
25235            .map(|(_, ranges)| ranges.to_vec());
25236        if existing_pending.is_none() && pending.is_empty() {
25237            return;
25238        }
25239        let transaction =
25240            self.transact(window, cx, |this, window, cx| {
25241                let selections = this
25242                    .selections
25243                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25244                let edits = selections
25245                    .iter()
25246                    .map(|selection| (selection.end..selection.end, pending.clone()));
25247                this.edit(edits, cx);
25248                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25249                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25250                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25251                    }));
25252                });
25253                if let Some(existing_ranges) = existing_pending {
25254                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25255                    this.edit(edits, cx);
25256                }
25257            });
25258
25259        let snapshot = self.snapshot(window, cx);
25260        let ranges = self
25261            .selections
25262            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25263            .into_iter()
25264            .map(|selection| {
25265                snapshot.buffer_snapshot().anchor_after(selection.end)
25266                    ..snapshot
25267                        .buffer_snapshot()
25268                        .anchor_before(selection.end + pending.len())
25269            })
25270            .collect();
25271
25272        if pending.is_empty() {
25273            self.clear_highlights(HighlightKey::PendingInput, cx);
25274        } else {
25275            self.highlight_text(
25276                HighlightKey::PendingInput,
25277                ranges,
25278                HighlightStyle {
25279                    underline: Some(UnderlineStyle {
25280                        thickness: px(1.),
25281                        color: None,
25282                        wavy: false,
25283                    }),
25284                    ..Default::default()
25285                },
25286                cx,
25287            );
25288        }
25289
25290        self.ime_transaction = self.ime_transaction.or(transaction);
25291        if let Some(transaction) = self.ime_transaction {
25292            self.buffer.update(cx, |buffer, cx| {
25293                buffer.group_until_transaction(transaction, cx);
25294            });
25295        }
25296
25297        if self
25298            .text_highlights(HighlightKey::PendingInput, cx)
25299            .is_none()
25300        {
25301            self.ime_transaction.take();
25302        }
25303    }
25304
25305    pub fn register_action_renderer(
25306        &mut self,
25307        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25308    ) -> Subscription {
25309        let id = self.next_editor_action_id.post_inc();
25310        self.editor_actions
25311            .borrow_mut()
25312            .insert(id, Box::new(listener));
25313
25314        let editor_actions = self.editor_actions.clone();
25315        Subscription::new(move || {
25316            editor_actions.borrow_mut().remove(&id);
25317        })
25318    }
25319
25320    pub fn register_action<A: Action>(
25321        &mut self,
25322        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25323    ) -> Subscription {
25324        let id = self.next_editor_action_id.post_inc();
25325        let listener = Arc::new(listener);
25326        self.editor_actions.borrow_mut().insert(
25327            id,
25328            Box::new(move |_, window, _| {
25329                let listener = listener.clone();
25330                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25331                    let action = action.downcast_ref().unwrap();
25332                    if phase == DispatchPhase::Bubble {
25333                        listener(action, window, cx)
25334                    }
25335                })
25336            }),
25337        );
25338
25339        let editor_actions = self.editor_actions.clone();
25340        Subscription::new(move || {
25341            editor_actions.borrow_mut().remove(&id);
25342        })
25343    }
25344
25345    pub fn file_header_size(&self) -> u32 {
25346        FILE_HEADER_HEIGHT
25347    }
25348
25349    pub fn restore(
25350        &mut self,
25351        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25352        window: &mut Window,
25353        cx: &mut Context<Self>,
25354    ) {
25355        self.buffer().update(cx, |multi_buffer, cx| {
25356            for (buffer_id, changes) in revert_changes {
25357                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25358                    buffer.update(cx, |buffer, cx| {
25359                        buffer.edit(
25360                            changes
25361                                .into_iter()
25362                                .map(|(range, text)| (range, text.to_string())),
25363                            None,
25364                            cx,
25365                        );
25366                    });
25367                }
25368            }
25369        });
25370        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
25371            selections.refresh()
25372        });
25373    }
25374
25375    pub fn to_pixel_point(
25376        &mut self,
25377        source: Anchor,
25378        editor_snapshot: &EditorSnapshot,
25379        window: &mut Window,
25380        cx: &mut App,
25381    ) -> Option<gpui::Point<Pixels>> {
25382        let source_point = source.to_display_point(editor_snapshot);
25383        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25384    }
25385
25386    pub fn display_to_pixel_point(
25387        &mut self,
25388        source: DisplayPoint,
25389        editor_snapshot: &EditorSnapshot,
25390        window: &mut Window,
25391        cx: &mut App,
25392    ) -> Option<gpui::Point<Pixels>> {
25393        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25394        let text_layout_details = self.text_layout_details(window, cx);
25395        let scroll_top = text_layout_details
25396            .scroll_anchor
25397            .scroll_position(editor_snapshot)
25398            .y;
25399
25400        if source.row().as_f64() < scroll_top.floor() {
25401            return None;
25402        }
25403        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25404        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25405        Some(gpui::Point::new(source_x, source_y))
25406    }
25407
25408    pub fn has_visible_completions_menu(&self) -> bool {
25409        !self.edit_prediction_preview_is_active()
25410            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25411                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25412            })
25413    }
25414
25415    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25416        if self.mode.is_minimap() {
25417            return;
25418        }
25419        self.addons
25420            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25421    }
25422
25423    pub fn unregister_addon<T: Addon>(&mut self) {
25424        self.addons.remove(&std::any::TypeId::of::<T>());
25425    }
25426
25427    pub fn addon<T: Addon>(&self) -> Option<&T> {
25428        let type_id = std::any::TypeId::of::<T>();
25429        self.addons
25430            .get(&type_id)
25431            .and_then(|item| item.to_any().downcast_ref::<T>())
25432    }
25433
25434    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25435        let type_id = std::any::TypeId::of::<T>();
25436        self.addons
25437            .get_mut(&type_id)
25438            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25439    }
25440
25441    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25442        let text_layout_details = self.text_layout_details(window, cx);
25443        let style = &text_layout_details.editor_style;
25444        let font_id = window.text_system().resolve_font(&style.text.font());
25445        let font_size = style.text.font_size.to_pixels(window.rem_size());
25446        let line_height = style.text.line_height_in_pixels(window.rem_size());
25447        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25448        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25449
25450        CharacterDimensions {
25451            em_width,
25452            em_advance,
25453            line_height,
25454        }
25455    }
25456
25457    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25458        self.load_diff_task.clone()
25459    }
25460
25461    fn read_metadata_from_db(
25462        &mut self,
25463        item_id: u64,
25464        workspace_id: WorkspaceId,
25465        window: &mut Window,
25466        cx: &mut Context<Editor>,
25467    ) {
25468        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25469            && !self.mode.is_minimap()
25470            && WorkspaceSettings::get(None, cx).restore_on_startup
25471                != RestoreOnStartupBehavior::EmptyTab
25472        {
25473            let buffer_snapshot = OnceCell::new();
25474
25475            // Get file path for path-based fold lookup
25476            let file_path: Option<Arc<Path>> =
25477                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25478                    project::File::from_dyn(buffer.read(cx).file())
25479                        .map(|file| Arc::from(file.abs_path(cx)))
25480                });
25481
25482            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25483            let db = EditorDb::global(cx);
25484            let (folds, needs_migration) = if let Some(ref path) = file_path {
25485                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25486                    && !folds.is_empty()
25487                {
25488                    (Some(folds), false)
25489                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25490                    && !folds.is_empty()
25491                {
25492                    // Found old editor_folds data, will migrate to file_folds
25493                    (Some(folds), true)
25494                } else {
25495                    (None, false)
25496                }
25497            } else {
25498                // No file path, try editor_folds as fallback
25499                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25500                (folds.filter(|f| !f.is_empty()), false)
25501            };
25502
25503            if let Some(folds) = folds {
25504                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25505                let snapshot_len = snapshot.len().0;
25506
25507                // Helper: search for fingerprint in buffer, return offset if found
25508                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25509                    // Ensure we start at a character boundary (defensive)
25510                    let search_start = snapshot
25511                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25512                        .0;
25513                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25514
25515                    let mut byte_offset = search_start;
25516                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25517                        if byte_offset > search_end {
25518                            break;
25519                        }
25520                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25521                            return Some(byte_offset);
25522                        }
25523                        byte_offset += ch.len_utf8();
25524                    }
25525                    None
25526                };
25527
25528                // Track search position to handle duplicate fingerprints correctly.
25529                // Folds are stored in document order, so we advance after each match.
25530                let mut search_start = 0usize;
25531
25532                // Collect db_folds for migration (only folds with valid fingerprints)
25533                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25534
25535                let valid_folds: Vec<_> = folds
25536                    .into_iter()
25537                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25538                        // Skip folds without fingerprints (old data before migration)
25539                        let sfp = start_fp?;
25540                        let efp = end_fp?;
25541                        let efp_len = efp.len();
25542
25543                        // Fast path: check if fingerprints match at stored offsets
25544                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25545                        let start_matches = stored_start < snapshot_len
25546                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25547                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25548                        let end_matches = efp_check_pos >= stored_start
25549                            && stored_end <= snapshot_len
25550                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25551
25552                        let (new_start, new_end) = if start_matches && end_matches {
25553                            // Offsets unchanged, use stored values
25554                            (stored_start, stored_end)
25555                        } else if sfp == efp {
25556                            // Short fold: identical fingerprints can only match once per search
25557                            // Use stored fold length to compute new_end
25558                            let new_start = find_fingerprint(&sfp, search_start)?;
25559                            let fold_len = stored_end - stored_start;
25560                            let new_end = new_start + fold_len;
25561                            (new_start, new_end)
25562                        } else {
25563                            // Slow path: search for fingerprints in buffer
25564                            let new_start = find_fingerprint(&sfp, search_start)?;
25565                            // Search for end_fp after start, then add efp_len to get actual fold end
25566                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25567                            let new_end = efp_pos + efp_len;
25568                            (new_start, new_end)
25569                        };
25570
25571                        // Advance search position for next fold
25572                        search_start = new_end;
25573
25574                        // Validate fold makes sense (end must be after start)
25575                        if new_end <= new_start {
25576                            return None;
25577                        }
25578
25579                        // Collect for migration if needed
25580                        if needs_migration {
25581                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25582                        }
25583
25584                        Some(
25585                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25586                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25587                        )
25588                    })
25589                    .collect();
25590
25591                if !valid_folds.is_empty() {
25592                    self.fold_ranges(valid_folds, false, window, cx);
25593
25594                    // Migrate from editor_folds to file_folds if we loaded from old table
25595                    if needs_migration {
25596                        if let Some(ref path) = file_path {
25597                            let path = path.clone();
25598                            let db = EditorDb::global(cx);
25599                            cx.spawn(async move |_, _| {
25600                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25601                                    .await
25602                                    .log_err();
25603                            })
25604                            .detach();
25605                        }
25606                    }
25607                }
25608            }
25609
25610            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25611                && !selections.is_empty()
25612            {
25613                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25614                // skip adding the initial selection to selection history
25615                self.selection_history.mode = SelectionHistoryMode::Skipping;
25616                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25617                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25618                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25619                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25620                    }));
25621                });
25622                self.selection_history.mode = SelectionHistoryMode::Normal;
25623            };
25624        }
25625
25626        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25627    }
25628
25629    /// Load folds from the file_folds database table by file path.
25630    /// Used when manually opening a file that was previously closed.
25631    fn load_folds_from_db(
25632        &mut self,
25633        workspace_id: WorkspaceId,
25634        file_path: PathBuf,
25635        window: &mut Window,
25636        cx: &mut Context<Editor>,
25637    ) {
25638        if self.mode.is_minimap()
25639            || WorkspaceSettings::get(None, cx).restore_on_startup
25640                == RestoreOnStartupBehavior::EmptyTab
25641        {
25642            return;
25643        }
25644
25645        let Some(folds) = EditorDb::global(cx)
25646            .get_file_folds(workspace_id, &file_path)
25647            .log_err()
25648        else {
25649            return;
25650        };
25651        if folds.is_empty() {
25652            return;
25653        }
25654
25655        let snapshot = self.buffer.read(cx).snapshot(cx);
25656        let snapshot_len = snapshot.len().0;
25657
25658        // Helper: search for fingerprint in buffer, return offset if found
25659        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25660            let search_start = snapshot
25661                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25662                .0;
25663            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25664
25665            let mut byte_offset = search_start;
25666            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25667                if byte_offset > search_end {
25668                    break;
25669                }
25670                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25671                    return Some(byte_offset);
25672                }
25673                byte_offset += ch.len_utf8();
25674            }
25675            None
25676        };
25677
25678        let mut search_start = 0usize;
25679
25680        let valid_folds: Vec<_> = folds
25681            .into_iter()
25682            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25683                let sfp = start_fp?;
25684                let efp = end_fp?;
25685                let efp_len = efp.len();
25686
25687                let start_matches = stored_start < snapshot_len
25688                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25689                let efp_check_pos = stored_end.saturating_sub(efp_len);
25690                let end_matches = efp_check_pos >= stored_start
25691                    && stored_end <= snapshot_len
25692                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25693
25694                let (new_start, new_end) = if start_matches && end_matches {
25695                    (stored_start, stored_end)
25696                } else if sfp == efp {
25697                    let new_start = find_fingerprint(&sfp, search_start)?;
25698                    let fold_len = stored_end - stored_start;
25699                    let new_end = new_start + fold_len;
25700                    (new_start, new_end)
25701                } else {
25702                    let new_start = find_fingerprint(&sfp, search_start)?;
25703                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25704                    let new_end = efp_pos + efp_len;
25705                    (new_start, new_end)
25706                };
25707
25708                search_start = new_end;
25709
25710                if new_end <= new_start {
25711                    return None;
25712                }
25713
25714                Some(
25715                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25716                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25717                )
25718            })
25719            .collect();
25720
25721        if !valid_folds.is_empty() {
25722            self.fold_ranges(valid_folds, false, window, cx);
25723        }
25724    }
25725
25726    fn lsp_data_enabled(&self) -> bool {
25727        self.enable_lsp_data && self.mode().is_full()
25728    }
25729
25730    fn update_lsp_data(
25731        &mut self,
25732        for_buffer: Option<BufferId>,
25733        window: &mut Window,
25734        cx: &mut Context<'_, Self>,
25735    ) {
25736        if !self.lsp_data_enabled() {
25737            return;
25738        }
25739
25740        if let Some(buffer_id) = for_buffer {
25741            self.pull_diagnostics(buffer_id, window, cx);
25742        }
25743        self.refresh_semantic_tokens(for_buffer, None, cx);
25744        self.refresh_document_colors(for_buffer, window, cx);
25745        self.refresh_folding_ranges(for_buffer, window, cx);
25746        self.refresh_document_symbols(for_buffer, cx);
25747    }
25748
25749    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25750        if !self.lsp_data_enabled() {
25751            return;
25752        }
25753        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
25754            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25755        }
25756    }
25757
25758    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25759        if !self.lsp_data_enabled() {
25760            return;
25761        }
25762
25763        if !self.registered_buffers.contains_key(&buffer_id)
25764            && let Some(project) = self.project.as_ref()
25765        {
25766            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25767                project.update(cx, |project, cx| {
25768                    self.registered_buffers.insert(
25769                        buffer_id,
25770                        project.register_buffer_with_language_servers(&buffer, cx),
25771                    );
25772                });
25773            } else {
25774                self.registered_buffers.remove(&buffer_id);
25775            }
25776        }
25777    }
25778
25779    fn create_style(&self, cx: &App) -> EditorStyle {
25780        let settings = ThemeSettings::get_global(cx);
25781
25782        let mut text_style = match self.mode {
25783            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25784                color: cx.theme().colors().editor_foreground,
25785                font_family: settings.ui_font.family.clone(),
25786                font_features: settings.ui_font.features.clone(),
25787                font_fallbacks: settings.ui_font.fallbacks.clone(),
25788                font_size: rems(0.875).into(),
25789                font_weight: settings.ui_font.weight,
25790                line_height: relative(settings.buffer_line_height.value()),
25791                ..Default::default()
25792            },
25793            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25794                color: cx.theme().colors().editor_foreground,
25795                font_family: settings.buffer_font.family.clone(),
25796                font_features: settings.buffer_font.features.clone(),
25797                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25798                font_size: settings.buffer_font_size(cx).into(),
25799                font_weight: settings.buffer_font.weight,
25800                line_height: relative(settings.buffer_line_height.value()),
25801                ..Default::default()
25802            },
25803        };
25804        if let Some(text_style_refinement) = &self.text_style_refinement {
25805            text_style.refine(text_style_refinement)
25806        }
25807
25808        let background = match self.mode {
25809            EditorMode::SingleLine => cx.theme().system().transparent,
25810            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25811            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25812            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25813        };
25814
25815        EditorStyle {
25816            background,
25817            border: cx.theme().colors().border,
25818            local_player: cx.theme().players().local(),
25819            text: text_style,
25820            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25821            syntax: cx.theme().syntax().clone(),
25822            status: cx.theme().status().clone(),
25823            inlay_hints_style: make_inlay_hints_style(cx),
25824            edit_prediction_styles: make_suggestion_styles(cx),
25825            unnecessary_code_fade: settings.unnecessary_code_fade,
25826            show_underlines: self.diagnostics_enabled(),
25827        }
25828    }
25829
25830    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25831        let multibuffer = self.buffer().read(cx);
25832        let is_singleton = multibuffer.is_singleton();
25833        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25834        let buffer = multibuffer.buffer(*buffer_id)?;
25835
25836        let buffer = buffer.read(cx);
25837        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25838        let mut breadcrumbs = if is_singleton {
25839            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25840                buffer
25841                    .snapshot()
25842                    .resolve_file_path(
25843                        self.project
25844                            .as_ref()
25845                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25846                            .unwrap_or_default(),
25847                        cx,
25848                    )
25849                    .unwrap_or_else(|| {
25850                        if multibuffer.is_singleton() {
25851                            multibuffer.title(cx).to_string()
25852                        } else {
25853                            "untitled".to_string()
25854                        }
25855                    })
25856            });
25857            vec![HighlightedText {
25858                text: text.into(),
25859                highlights: vec![],
25860            }]
25861        } else {
25862            vec![]
25863        };
25864
25865        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25866            text: symbol.text.clone().into(),
25867            highlights: symbol.highlight_ranges.clone(),
25868        }));
25869        Some(breadcrumbs)
25870    }
25871
25872    fn disable_lsp_data(&mut self) {
25873        self.enable_lsp_data = false;
25874    }
25875
25876    fn disable_runnables(&mut self) {
25877        self.enable_runnables = false;
25878    }
25879
25880    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25881        self.register_visible_buffers(cx);
25882        self.colorize_brackets(false, cx);
25883        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25884        if !self.buffer().read(cx).is_singleton() {
25885            self.update_lsp_data(None, window, cx);
25886            self.refresh_runnables(None, window, cx);
25887        }
25888    }
25889}
25890
25891fn edit_for_markdown_paste<'a>(
25892    buffer: &MultiBufferSnapshot,
25893    range: Range<MultiBufferOffset>,
25894    to_insert: &'a str,
25895    url: Option<url::Url>,
25896) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25897    if url.is_none() {
25898        return (range, Cow::Borrowed(to_insert));
25899    };
25900
25901    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25902
25903    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25904        Cow::Borrowed(to_insert)
25905    } else {
25906        Cow::Owned(format!("[{old_text}]({to_insert})"))
25907    };
25908    (range, new_text)
25909}
25910
25911fn process_completion_for_edit(
25912    completion: &Completion,
25913    intent: CompletionIntent,
25914    buffer: &Entity<Buffer>,
25915    cursor_position: &text::Anchor,
25916    cx: &mut Context<Editor>,
25917) -> CompletionEdit {
25918    let buffer = buffer.read(cx);
25919    let buffer_snapshot = buffer.snapshot();
25920    let (snippet, new_text) = if completion.is_snippet() {
25921        let mut snippet_source = completion.new_text.clone();
25922        // Workaround for typescript language server issues so that methods don't expand within
25923        // strings and functions with type expressions. The previous point is used because the query
25924        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25925        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25926        let previous_point = if previous_point.column > 0 {
25927            cursor_position.to_previous_offset(&buffer_snapshot)
25928        } else {
25929            cursor_position.to_offset(&buffer_snapshot)
25930        };
25931        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25932            && scope.prefers_label_for_snippet_in_completion()
25933            && let Some(label) = completion.label()
25934            && matches!(
25935                completion.kind(),
25936                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25937            )
25938        {
25939            snippet_source = label;
25940        }
25941        match Snippet::parse(&snippet_source).log_err() {
25942            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25943            None => (None, completion.new_text.clone()),
25944        }
25945    } else {
25946        (None, completion.new_text.clone())
25947    };
25948
25949    let mut range_to_replace = {
25950        let replace_range = &completion.replace_range;
25951        if let CompletionSource::Lsp {
25952            insert_range: Some(insert_range),
25953            ..
25954        } = &completion.source
25955        {
25956            debug_assert_eq!(
25957                insert_range.start, replace_range.start,
25958                "insert_range and replace_range should start at the same position"
25959            );
25960            debug_assert!(
25961                insert_range
25962                    .start
25963                    .cmp(cursor_position, &buffer_snapshot)
25964                    .is_le(),
25965                "insert_range should start before or at cursor position"
25966            );
25967            debug_assert!(
25968                replace_range
25969                    .start
25970                    .cmp(cursor_position, &buffer_snapshot)
25971                    .is_le(),
25972                "replace_range should start before or at cursor position"
25973            );
25974
25975            let should_replace = match intent {
25976                CompletionIntent::CompleteWithInsert => false,
25977                CompletionIntent::CompleteWithReplace => true,
25978                CompletionIntent::Complete | CompletionIntent::Compose => {
25979                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
25980                        .completions
25981                        .lsp_insert_mode;
25982                    match insert_mode {
25983                        LspInsertMode::Insert => false,
25984                        LspInsertMode::Replace => true,
25985                        LspInsertMode::ReplaceSubsequence => {
25986                            let mut text_to_replace = buffer.chars_for_range(
25987                                buffer.anchor_before(replace_range.start)
25988                                    ..buffer.anchor_after(replace_range.end),
25989                            );
25990                            let mut current_needle = text_to_replace.next();
25991                            for haystack_ch in completion.label.text.chars() {
25992                                if let Some(needle_ch) = current_needle
25993                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25994                                {
25995                                    current_needle = text_to_replace.next();
25996                                }
25997                            }
25998                            current_needle.is_none()
25999                        }
26000                        LspInsertMode::ReplaceSuffix => {
26001                            if replace_range
26002                                .end
26003                                .cmp(cursor_position, &buffer_snapshot)
26004                                .is_gt()
26005                            {
26006                                let range_after_cursor = *cursor_position..replace_range.end;
26007                                let text_after_cursor = buffer
26008                                    .text_for_range(
26009                                        buffer.anchor_before(range_after_cursor.start)
26010                                            ..buffer.anchor_after(range_after_cursor.end),
26011                                    )
26012                                    .collect::<String>()
26013                                    .to_ascii_lowercase();
26014                                completion
26015                                    .label
26016                                    .text
26017                                    .to_ascii_lowercase()
26018                                    .ends_with(&text_after_cursor)
26019                            } else {
26020                                true
26021                            }
26022                        }
26023                    }
26024                }
26025            };
26026
26027            if should_replace {
26028                replace_range.clone()
26029            } else {
26030                insert_range.clone()
26031            }
26032        } else {
26033            replace_range.clone()
26034        }
26035    };
26036
26037    if range_to_replace
26038        .end
26039        .cmp(cursor_position, &buffer_snapshot)
26040        .is_lt()
26041    {
26042        range_to_replace.end = *cursor_position;
26043    }
26044
26045    let replace_range = range_to_replace.to_offset(buffer);
26046    CompletionEdit {
26047        new_text,
26048        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
26049        snippet,
26050    }
26051}
26052
26053struct CompletionEdit {
26054    new_text: String,
26055    replace_range: Range<BufferOffset>,
26056    snippet: Option<Snippet>,
26057}
26058
26059fn comment_delimiter_for_newline(
26060    start_point: &Point,
26061    buffer: &MultiBufferSnapshot,
26062    language: &LanguageScope,
26063) -> Option<Arc<str>> {
26064    let delimiters = language.line_comment_prefixes();
26065    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26066    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26067
26068    let num_of_whitespaces = snapshot
26069        .chars_for_range(range.clone())
26070        .take_while(|c| c.is_whitespace())
26071        .count();
26072    let comment_candidate = snapshot
26073        .chars_for_range(range.clone())
26074        .skip(num_of_whitespaces)
26075        .take(max_len_of_delimiter + 2)
26076        .collect::<String>();
26077    let (delimiter, trimmed_len, is_repl) = delimiters
26078        .iter()
26079        .filter_map(|delimiter| {
26080            let prefix = delimiter.trim_end();
26081            if comment_candidate.starts_with(prefix) {
26082                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26083                {
26084                    stripped_comment.starts_with(" %%")
26085                } else {
26086                    false
26087                };
26088                Some((delimiter, prefix.len(), is_repl))
26089            } else {
26090                None
26091            }
26092        })
26093        .max_by_key(|(_, len, _)| *len)?;
26094
26095    if let Some(BlockCommentConfig {
26096        start: block_start, ..
26097    }) = language.block_comment()
26098    {
26099        let block_start_trimmed = block_start.trim_end();
26100        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26101            let line_content = snapshot
26102                .chars_for_range(range.clone())
26103                .skip(num_of_whitespaces)
26104                .take(block_start_trimmed.len())
26105                .collect::<String>();
26106
26107            if line_content.starts_with(block_start_trimmed) {
26108                return None;
26109            }
26110        }
26111    }
26112
26113    let cursor_is_placed_after_comment_marker =
26114        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26115    if cursor_is_placed_after_comment_marker {
26116        if !is_repl {
26117            return Some(delimiter.clone());
26118        }
26119
26120        let line_content_after_cursor: String = snapshot
26121            .chars_for_range(range)
26122            .skip(start_point.column as usize)
26123            .collect();
26124
26125        if line_content_after_cursor.trim().is_empty() {
26126            return None;
26127        } else {
26128            return Some(delimiter.clone());
26129        }
26130    } else {
26131        None
26132    }
26133}
26134
26135fn documentation_delimiter_for_newline(
26136    start_point: &Point,
26137    buffer: &MultiBufferSnapshot,
26138    language: &LanguageScope,
26139    newline_config: &mut NewlineConfig,
26140) -> Option<Arc<str>> {
26141    let BlockCommentConfig {
26142        start: start_tag,
26143        end: end_tag,
26144        prefix: delimiter,
26145        tab_size: len,
26146    } = language.documentation_comment()?;
26147    let is_within_block_comment = buffer
26148        .language_scope_at(*start_point)
26149        .is_some_and(|scope| scope.override_name() == Some("comment"));
26150    if !is_within_block_comment {
26151        return None;
26152    }
26153
26154    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26155
26156    let num_of_whitespaces = snapshot
26157        .chars_for_range(range.clone())
26158        .take_while(|c| c.is_whitespace())
26159        .count();
26160
26161    // 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.
26162    let column = start_point.column;
26163    let cursor_is_after_start_tag = {
26164        let start_tag_len = start_tag.len();
26165        let start_tag_line = snapshot
26166            .chars_for_range(range.clone())
26167            .skip(num_of_whitespaces)
26168            .take(start_tag_len)
26169            .collect::<String>();
26170        if start_tag_line.starts_with(start_tag.as_ref()) {
26171            num_of_whitespaces + start_tag_len <= column as usize
26172        } else {
26173            false
26174        }
26175    };
26176
26177    let cursor_is_after_delimiter = {
26178        let delimiter_trim = delimiter.trim_end();
26179        let delimiter_line = snapshot
26180            .chars_for_range(range.clone())
26181            .skip(num_of_whitespaces)
26182            .take(delimiter_trim.len())
26183            .collect::<String>();
26184        if delimiter_line.starts_with(delimiter_trim) {
26185            num_of_whitespaces + delimiter_trim.len() <= column as usize
26186        } else {
26187            false
26188        }
26189    };
26190
26191    let mut needs_extra_line = false;
26192    let mut extra_line_additional_indent = IndentSize::spaces(0);
26193
26194    let cursor_is_before_end_tag_if_exists = {
26195        let mut char_position = 0u32;
26196        let mut end_tag_offset = None;
26197
26198        'outer: for chunk in snapshot.text_for_range(range) {
26199            if let Some(byte_pos) = chunk.find(&**end_tag) {
26200                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26201                end_tag_offset = Some(char_position + chars_before_match);
26202                break 'outer;
26203            }
26204            char_position += chunk.chars().count() as u32;
26205        }
26206
26207        if let Some(end_tag_offset) = end_tag_offset {
26208            let cursor_is_before_end_tag = column <= end_tag_offset;
26209            if cursor_is_after_start_tag {
26210                if cursor_is_before_end_tag {
26211                    needs_extra_line = true;
26212                }
26213                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26214                if cursor_is_at_start_of_end_tag {
26215                    extra_line_additional_indent.len = *len;
26216                }
26217            }
26218            cursor_is_before_end_tag
26219        } else {
26220            true
26221        }
26222    };
26223
26224    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26225        && cursor_is_before_end_tag_if_exists
26226    {
26227        let additional_indent = if cursor_is_after_start_tag {
26228            IndentSize::spaces(*len)
26229        } else {
26230            IndentSize::spaces(0)
26231        };
26232
26233        *newline_config = NewlineConfig::Newline {
26234            additional_indent,
26235            extra_line_additional_indent: if needs_extra_line {
26236                Some(extra_line_additional_indent)
26237            } else {
26238                None
26239            },
26240            prevent_auto_indent: true,
26241        };
26242        Some(delimiter.clone())
26243    } else {
26244        None
26245    }
26246}
26247
26248const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26249
26250fn list_delimiter_for_newline(
26251    start_point: &Point,
26252    buffer: &MultiBufferSnapshot,
26253    language: &LanguageScope,
26254    newline_config: &mut NewlineConfig,
26255) -> Option<Arc<str>> {
26256    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26257
26258    let num_of_whitespaces = snapshot
26259        .chars_for_range(range.clone())
26260        .take_while(|c| c.is_whitespace())
26261        .count();
26262
26263    let task_list_entries: Vec<_> = language
26264        .task_list()
26265        .into_iter()
26266        .flat_map(|config| {
26267            config
26268                .prefixes
26269                .iter()
26270                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26271        })
26272        .collect();
26273    let unordered_list_entries: Vec<_> = language
26274        .unordered_list()
26275        .iter()
26276        .map(|marker| (marker.as_ref(), marker.as_ref()))
26277        .collect();
26278
26279    let all_entries: Vec<_> = task_list_entries
26280        .into_iter()
26281        .chain(unordered_list_entries)
26282        .collect();
26283
26284    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26285        let candidate: String = snapshot
26286            .chars_for_range(range.clone())
26287            .skip(num_of_whitespaces)
26288            .take(max_prefix_len)
26289            .collect();
26290
26291        if let Some((prefix, continuation)) = all_entries
26292            .iter()
26293            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26294            .max_by_key(|(prefix, _)| prefix.len())
26295        {
26296            let end_of_prefix = num_of_whitespaces + prefix.len();
26297            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26298            let has_content_after_marker = snapshot
26299                .chars_for_range(range)
26300                .skip(end_of_prefix)
26301                .any(|c| !c.is_whitespace());
26302
26303            if has_content_after_marker && cursor_is_after_prefix {
26304                return Some((*continuation).into());
26305            }
26306
26307            if start_point.column as usize == end_of_prefix {
26308                if num_of_whitespaces == 0 {
26309                    *newline_config = NewlineConfig::ClearCurrentLine;
26310                } else {
26311                    *newline_config = NewlineConfig::UnindentCurrentLine {
26312                        continuation: (*continuation).into(),
26313                    };
26314                }
26315            }
26316
26317            return None;
26318        }
26319    }
26320
26321    let candidate: String = snapshot
26322        .chars_for_range(range.clone())
26323        .skip(num_of_whitespaces)
26324        .take(ORDERED_LIST_MAX_MARKER_LEN)
26325        .collect();
26326
26327    for ordered_config in language.ordered_list() {
26328        let regex = match Regex::new(&ordered_config.pattern) {
26329            Ok(r) => r,
26330            Err(_) => continue,
26331        };
26332
26333        if let Some(captures) = regex.captures(&candidate) {
26334            let full_match = captures.get(0)?;
26335            let marker_len = full_match.len();
26336            let end_of_prefix = num_of_whitespaces + marker_len;
26337            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26338
26339            let has_content_after_marker = snapshot
26340                .chars_for_range(range)
26341                .skip(end_of_prefix)
26342                .any(|c| !c.is_whitespace());
26343
26344            if has_content_after_marker && cursor_is_after_prefix {
26345                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26346                let continuation = ordered_config
26347                    .format
26348                    .replace("{1}", &(number + 1).to_string());
26349                return Some(continuation.into());
26350            }
26351
26352            if start_point.column as usize == end_of_prefix {
26353                let continuation = ordered_config.format.replace("{1}", "1");
26354                if num_of_whitespaces == 0 {
26355                    *newline_config = NewlineConfig::ClearCurrentLine;
26356                } else {
26357                    *newline_config = NewlineConfig::UnindentCurrentLine {
26358                        continuation: continuation.into(),
26359                    };
26360                }
26361            }
26362
26363            return None;
26364        }
26365    }
26366
26367    None
26368}
26369
26370fn is_list_prefix_row(
26371    row: MultiBufferRow,
26372    buffer: &MultiBufferSnapshot,
26373    language: &LanguageScope,
26374) -> bool {
26375    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26376        return false;
26377    };
26378
26379    let num_of_whitespaces = snapshot
26380        .chars_for_range(range.clone())
26381        .take_while(|c| c.is_whitespace())
26382        .count();
26383
26384    let task_list_prefixes: Vec<_> = language
26385        .task_list()
26386        .into_iter()
26387        .flat_map(|config| {
26388            config
26389                .prefixes
26390                .iter()
26391                .map(|p| p.as_ref())
26392                .collect::<Vec<_>>()
26393        })
26394        .collect();
26395    let unordered_list_markers: Vec<_> = language
26396        .unordered_list()
26397        .iter()
26398        .map(|marker| marker.as_ref())
26399        .collect();
26400    let all_prefixes: Vec<_> = task_list_prefixes
26401        .into_iter()
26402        .chain(unordered_list_markers)
26403        .collect();
26404    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26405        let candidate: String = snapshot
26406            .chars_for_range(range.clone())
26407            .skip(num_of_whitespaces)
26408            .take(max_prefix_len)
26409            .collect();
26410        if all_prefixes
26411            .iter()
26412            .any(|prefix| candidate.starts_with(*prefix))
26413        {
26414            return true;
26415        }
26416    }
26417
26418    let ordered_list_candidate: String = snapshot
26419        .chars_for_range(range)
26420        .skip(num_of_whitespaces)
26421        .take(ORDERED_LIST_MAX_MARKER_LEN)
26422        .collect();
26423    for ordered_config in language.ordered_list() {
26424        let regex = match Regex::new(&ordered_config.pattern) {
26425            Ok(r) => r,
26426            Err(_) => continue,
26427        };
26428        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26429            return captures.get(0).is_some();
26430        }
26431    }
26432
26433    false
26434}
26435
26436#[derive(Debug)]
26437enum NewlineConfig {
26438    /// Insert newline with optional additional indent and optional extra blank line
26439    Newline {
26440        additional_indent: IndentSize,
26441        extra_line_additional_indent: Option<IndentSize>,
26442        prevent_auto_indent: bool,
26443    },
26444    /// Clear the current line
26445    ClearCurrentLine,
26446    /// Unindent the current line and add continuation
26447    UnindentCurrentLine { continuation: Arc<str> },
26448}
26449
26450impl NewlineConfig {
26451    fn has_extra_line(&self) -> bool {
26452        matches!(
26453            self,
26454            Self::Newline {
26455                extra_line_additional_indent: Some(_),
26456                ..
26457            }
26458        )
26459    }
26460
26461    fn insert_extra_newline_brackets(
26462        buffer: &MultiBufferSnapshot,
26463        range: Range<MultiBufferOffset>,
26464        language: &language::LanguageScope,
26465    ) -> bool {
26466        let leading_whitespace_len = buffer
26467            .reversed_chars_at(range.start)
26468            .take_while(|c| c.is_whitespace() && *c != '\n')
26469            .map(|c| c.len_utf8())
26470            .sum::<usize>();
26471        let trailing_whitespace_len = buffer
26472            .chars_at(range.end)
26473            .take_while(|c| c.is_whitespace() && *c != '\n')
26474            .map(|c| c.len_utf8())
26475            .sum::<usize>();
26476        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26477
26478        language.brackets().any(|(pair, enabled)| {
26479            let pair_start = pair.start.trim_end();
26480            let pair_end = pair.end.trim_start();
26481
26482            enabled
26483                && pair.newline
26484                && buffer.contains_str_at(range.end, pair_end)
26485                && buffer.contains_str_at(
26486                    range.start.saturating_sub_usize(pair_start.len()),
26487                    pair_start,
26488                )
26489        })
26490    }
26491
26492    fn insert_extra_newline_tree_sitter(
26493        buffer: &MultiBufferSnapshot,
26494        range: Range<MultiBufferOffset>,
26495    ) -> bool {
26496        let (buffer, range) = match buffer
26497            .range_to_buffer_ranges(range.start..=range.end)
26498            .as_slice()
26499        {
26500            [(buffer, range, _)] => (*buffer, range.clone()),
26501            _ => return false,
26502        };
26503        let pair = {
26504            let mut result: Option<BracketMatch<usize>> = None;
26505
26506            for pair in buffer
26507                .all_bracket_ranges(range.start.0..range.end.0)
26508                .filter(move |pair| {
26509                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26510                })
26511            {
26512                let len = pair.close_range.end - pair.open_range.start;
26513
26514                if let Some(existing) = &result {
26515                    let existing_len = existing.close_range.end - existing.open_range.start;
26516                    if len > existing_len {
26517                        continue;
26518                    }
26519                }
26520
26521                result = Some(pair);
26522            }
26523
26524            result
26525        };
26526        let Some(pair) = pair else {
26527            return false;
26528        };
26529        pair.newline_only
26530            && buffer
26531                .chars_for_range(pair.open_range.end..range.start.0)
26532                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26533                .all(|c| c.is_whitespace() && c != '\n')
26534    }
26535}
26536
26537fn update_uncommitted_diff_for_buffer(
26538    editor: Entity<Editor>,
26539    project: &Entity<Project>,
26540    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26541    buffer: Entity<MultiBuffer>,
26542    cx: &mut App,
26543) -> Task<()> {
26544    let mut tasks = Vec::new();
26545    project.update(cx, |project, cx| {
26546        for buffer in buffers {
26547            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26548                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26549            }
26550        }
26551    });
26552    cx.spawn(async move |cx| {
26553        let diffs = future::join_all(tasks).await;
26554        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26555            return;
26556        }
26557
26558        buffer.update(cx, |buffer, cx| {
26559            for diff in diffs.into_iter().flatten() {
26560                buffer.add_diff(diff, cx);
26561            }
26562        });
26563    })
26564}
26565
26566fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26567    let tab_size = tab_size.get() as usize;
26568    let mut width = offset;
26569
26570    for ch in text.chars() {
26571        width += if ch == '\t' {
26572            tab_size - (width % tab_size)
26573        } else {
26574            1
26575        };
26576    }
26577
26578    width - offset
26579}
26580
26581#[cfg(test)]
26582mod tests {
26583    use super::*;
26584
26585    #[test]
26586    fn test_string_size_with_expanded_tabs() {
26587        let nz = |val| NonZeroU32::new(val).unwrap();
26588        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26589        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26590        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26591        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26592        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26593        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26594        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26595        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26596    }
26597}
26598
26599/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26600struct WordBreakingTokenizer<'a> {
26601    input: &'a str,
26602}
26603
26604impl<'a> WordBreakingTokenizer<'a> {
26605    fn new(input: &'a str) -> Self {
26606        Self { input }
26607    }
26608}
26609
26610fn is_char_ideographic(ch: char) -> bool {
26611    use unicode_script::Script::*;
26612    use unicode_script::UnicodeScript;
26613    matches!(ch.script(), Han | Tangut | Yi)
26614}
26615
26616fn is_grapheme_ideographic(text: &str) -> bool {
26617    text.chars().any(is_char_ideographic)
26618}
26619
26620fn is_grapheme_whitespace(text: &str) -> bool {
26621    text.chars().any(|x| x.is_whitespace())
26622}
26623
26624fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26625    text.chars()
26626        .next()
26627        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26628}
26629
26630#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26631enum WordBreakToken<'a> {
26632    Word { token: &'a str, grapheme_len: usize },
26633    InlineWhitespace { token: &'a str, grapheme_len: usize },
26634    Newline,
26635}
26636
26637impl<'a> Iterator for WordBreakingTokenizer<'a> {
26638    /// Yields a span, the count of graphemes in the token, and whether it was
26639    /// whitespace. Note that it also breaks at word boundaries.
26640    type Item = WordBreakToken<'a>;
26641
26642    fn next(&mut self) -> Option<Self::Item> {
26643        use unicode_segmentation::UnicodeSegmentation;
26644        if self.input.is_empty() {
26645            return None;
26646        }
26647
26648        let mut iter = self.input.graphemes(true).peekable();
26649        let mut offset = 0;
26650        let mut grapheme_len = 0;
26651        if let Some(first_grapheme) = iter.next() {
26652            let is_newline = first_grapheme == "\n";
26653            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26654            offset += first_grapheme.len();
26655            grapheme_len += 1;
26656            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26657                if let Some(grapheme) = iter.peek().copied()
26658                    && should_stay_with_preceding_ideograph(grapheme)
26659                {
26660                    offset += grapheme.len();
26661                    grapheme_len += 1;
26662                }
26663            } else {
26664                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26665                let mut next_word_bound = words.peek().copied();
26666                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26667                    next_word_bound = words.next();
26668                }
26669                while let Some(grapheme) = iter.peek().copied() {
26670                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26671                        break;
26672                    };
26673                    if is_grapheme_whitespace(grapheme) != is_whitespace
26674                        || (grapheme == "\n") != is_newline
26675                    {
26676                        break;
26677                    };
26678                    offset += grapheme.len();
26679                    grapheme_len += 1;
26680                    iter.next();
26681                }
26682            }
26683            let token = &self.input[..offset];
26684            self.input = &self.input[offset..];
26685            if token == "\n" {
26686                Some(WordBreakToken::Newline)
26687            } else if is_whitespace {
26688                Some(WordBreakToken::InlineWhitespace {
26689                    token,
26690                    grapheme_len,
26691                })
26692            } else {
26693                Some(WordBreakToken::Word {
26694                    token,
26695                    grapheme_len,
26696                })
26697            }
26698        } else {
26699            None
26700        }
26701    }
26702}
26703
26704#[test]
26705fn test_word_breaking_tokenizer() {
26706    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26707        ("", &[]),
26708        ("  ", &[whitespace("  ", 2)]),
26709        ("Ʒ", &[word("Ʒ", 1)]),
26710        ("Ǽ", &[word("Ǽ", 1)]),
26711        ("", &[word("", 1)]),
26712        ("⋑⋑", &[word("⋑⋑", 2)]),
26713        (
26714            "原理,进而",
26715            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26716        ),
26717        (
26718            "hello world",
26719            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26720        ),
26721        (
26722            "hello, world",
26723            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26724        ),
26725        (
26726            "  hello world",
26727            &[
26728                whitespace("  ", 2),
26729                word("hello", 5),
26730                whitespace(" ", 1),
26731                word("world", 5),
26732            ],
26733        ),
26734        (
26735            "这是什么 \n 钢笔",
26736            &[
26737                word("", 1),
26738                word("", 1),
26739                word("", 1),
26740                word("", 1),
26741                whitespace(" ", 1),
26742                newline(),
26743                whitespace(" ", 1),
26744                word("", 1),
26745                word("", 1),
26746            ],
26747        ),
26748        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26749    ];
26750
26751    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26752        WordBreakToken::Word {
26753            token,
26754            grapheme_len,
26755        }
26756    }
26757
26758    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26759        WordBreakToken::InlineWhitespace {
26760            token,
26761            grapheme_len,
26762        }
26763    }
26764
26765    fn newline() -> WordBreakToken<'static> {
26766        WordBreakToken::Newline
26767    }
26768
26769    for (input, result) in tests {
26770        assert_eq!(
26771            WordBreakingTokenizer::new(input)
26772                .collect::<Vec<_>>()
26773                .as_slice(),
26774            *result,
26775        );
26776    }
26777}
26778
26779fn wrap_with_prefix(
26780    first_line_prefix: String,
26781    subsequent_lines_prefix: String,
26782    unwrapped_text: String,
26783    wrap_column: usize,
26784    tab_size: NonZeroU32,
26785    preserve_existing_whitespace: bool,
26786) -> String {
26787    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26788    let subsequent_lines_prefix_len =
26789        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26790    let mut wrapped_text = String::new();
26791    let mut current_line = first_line_prefix;
26792    let mut is_first_line = true;
26793
26794    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26795    let mut current_line_len = first_line_prefix_len;
26796    let mut in_whitespace = false;
26797    for token in tokenizer {
26798        let have_preceding_whitespace = in_whitespace;
26799        match token {
26800            WordBreakToken::Word {
26801                token,
26802                grapheme_len,
26803            } => {
26804                in_whitespace = false;
26805                let current_prefix_len = if is_first_line {
26806                    first_line_prefix_len
26807                } else {
26808                    subsequent_lines_prefix_len
26809                };
26810                if current_line_len + grapheme_len > wrap_column
26811                    && current_line_len != current_prefix_len
26812                {
26813                    wrapped_text.push_str(current_line.trim_end());
26814                    wrapped_text.push('\n');
26815                    is_first_line = false;
26816                    current_line = subsequent_lines_prefix.clone();
26817                    current_line_len = subsequent_lines_prefix_len;
26818                }
26819                current_line.push_str(token);
26820                current_line_len += grapheme_len;
26821            }
26822            WordBreakToken::InlineWhitespace {
26823                mut token,
26824                mut grapheme_len,
26825            } => {
26826                in_whitespace = true;
26827                if have_preceding_whitespace && !preserve_existing_whitespace {
26828                    continue;
26829                }
26830                if !preserve_existing_whitespace {
26831                    // Keep a single whitespace grapheme as-is
26832                    if let Some(first) =
26833                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26834                    {
26835                        token = first;
26836                    } else {
26837                        token = " ";
26838                    }
26839                    grapheme_len = 1;
26840                }
26841                let current_prefix_len = if is_first_line {
26842                    first_line_prefix_len
26843                } else {
26844                    subsequent_lines_prefix_len
26845                };
26846                if current_line_len + grapheme_len > wrap_column {
26847                    wrapped_text.push_str(current_line.trim_end());
26848                    wrapped_text.push('\n');
26849                    is_first_line = false;
26850                    current_line = subsequent_lines_prefix.clone();
26851                    current_line_len = subsequent_lines_prefix_len;
26852                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26853                    current_line.push_str(token);
26854                    current_line_len += grapheme_len;
26855                }
26856            }
26857            WordBreakToken::Newline => {
26858                in_whitespace = true;
26859                let current_prefix_len = if is_first_line {
26860                    first_line_prefix_len
26861                } else {
26862                    subsequent_lines_prefix_len
26863                };
26864                if preserve_existing_whitespace {
26865                    wrapped_text.push_str(current_line.trim_end());
26866                    wrapped_text.push('\n');
26867                    is_first_line = false;
26868                    current_line = subsequent_lines_prefix.clone();
26869                    current_line_len = subsequent_lines_prefix_len;
26870                } else if have_preceding_whitespace {
26871                    continue;
26872                } else if current_line_len + 1 > wrap_column
26873                    && current_line_len != current_prefix_len
26874                {
26875                    wrapped_text.push_str(current_line.trim_end());
26876                    wrapped_text.push('\n');
26877                    is_first_line = false;
26878                    current_line = subsequent_lines_prefix.clone();
26879                    current_line_len = subsequent_lines_prefix_len;
26880                } else if current_line_len != current_prefix_len {
26881                    current_line.push(' ');
26882                    current_line_len += 1;
26883                }
26884            }
26885        }
26886    }
26887
26888    if !current_line.is_empty() {
26889        wrapped_text.push_str(&current_line);
26890    }
26891    wrapped_text
26892}
26893
26894#[test]
26895fn test_wrap_with_prefix() {
26896    assert_eq!(
26897        wrap_with_prefix(
26898            "# ".to_string(),
26899            "# ".to_string(),
26900            "abcdefg".to_string(),
26901            4,
26902            NonZeroU32::new(4).unwrap(),
26903            false,
26904        ),
26905        "# abcdefg"
26906    );
26907    assert_eq!(
26908        wrap_with_prefix(
26909            "".to_string(),
26910            "".to_string(),
26911            "\thello world".to_string(),
26912            8,
26913            NonZeroU32::new(4).unwrap(),
26914            false,
26915        ),
26916        "hello\nworld"
26917    );
26918    assert_eq!(
26919        wrap_with_prefix(
26920            "// ".to_string(),
26921            "// ".to_string(),
26922            "xx \nyy zz aa bb cc".to_string(),
26923            12,
26924            NonZeroU32::new(4).unwrap(),
26925            false,
26926        ),
26927        "// xx yy zz\n// aa bb cc"
26928    );
26929    assert_eq!(
26930        wrap_with_prefix(
26931            String::new(),
26932            String::new(),
26933            "这是什么 \n 钢笔".to_string(),
26934            3,
26935            NonZeroU32::new(4).unwrap(),
26936            false,
26937        ),
26938        "这是什\n么 钢\n"
26939    );
26940    assert_eq!(
26941        wrap_with_prefix(
26942            String::new(),
26943            String::new(),
26944            format!("foo{}bar", '\u{2009}'), // thin space
26945            80,
26946            NonZeroU32::new(4).unwrap(),
26947            false,
26948        ),
26949        format!("foo{}bar", '\u{2009}')
26950    );
26951}
26952
26953pub trait CollaborationHub {
26954    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26955    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26956    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26957}
26958
26959impl CollaborationHub for Entity<Project> {
26960    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26961        self.read(cx).collaborators()
26962    }
26963
26964    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26965        self.read(cx).user_store().read(cx).participant_indices()
26966    }
26967
26968    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26969        let this = self.read(cx);
26970        let user_ids = this.collaborators().values().map(|c| c.user_id);
26971        this.user_store().read(cx).participant_names(user_ids, cx)
26972    }
26973}
26974
26975pub trait SemanticsProvider {
26976    fn hover(
26977        &self,
26978        buffer: &Entity<Buffer>,
26979        position: text::Anchor,
26980        cx: &mut App,
26981    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26982
26983    fn inline_values(
26984        &self,
26985        buffer_handle: Entity<Buffer>,
26986        range: Range<text::Anchor>,
26987        cx: &mut App,
26988    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26989
26990    fn applicable_inlay_chunks(
26991        &self,
26992        buffer: &Entity<Buffer>,
26993        ranges: &[Range<text::Anchor>],
26994        cx: &mut App,
26995    ) -> Vec<Range<BufferRow>>;
26996
26997    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26998
26999    fn inlay_hints(
27000        &self,
27001        invalidate: InvalidationStrategy,
27002        buffer: Entity<Buffer>,
27003        ranges: Vec<Range<text::Anchor>>,
27004        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27005        cx: &mut App,
27006    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27007
27008    fn semantic_tokens(
27009        &self,
27010        buffer: Entity<Buffer>,
27011        refresh: Option<RefreshForServer>,
27012        cx: &mut App,
27013    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27014
27015    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27016
27017    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27018
27019    fn document_highlights(
27020        &self,
27021        buffer: &Entity<Buffer>,
27022        position: text::Anchor,
27023        cx: &mut App,
27024    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27025
27026    fn definitions(
27027        &self,
27028        buffer: &Entity<Buffer>,
27029        position: text::Anchor,
27030        kind: GotoDefinitionKind,
27031        cx: &mut App,
27032    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27033
27034    fn range_for_rename(
27035        &self,
27036        buffer: &Entity<Buffer>,
27037        position: text::Anchor,
27038        cx: &mut App,
27039    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
27040
27041    fn perform_rename(
27042        &self,
27043        buffer: &Entity<Buffer>,
27044        position: text::Anchor,
27045        new_name: String,
27046        cx: &mut App,
27047    ) -> Option<Task<Result<ProjectTransaction>>>;
27048}
27049
27050pub trait CompletionProvider {
27051    fn completions(
27052        &self,
27053        excerpt_id: ExcerptId,
27054        buffer: &Entity<Buffer>,
27055        buffer_position: text::Anchor,
27056        trigger: CompletionContext,
27057        window: &mut Window,
27058        cx: &mut Context<Editor>,
27059    ) -> Task<Result<Vec<CompletionResponse>>>;
27060
27061    fn resolve_completions(
27062        &self,
27063        _buffer: Entity<Buffer>,
27064        _completion_indices: Vec<usize>,
27065        _completions: Rc<RefCell<Box<[Completion]>>>,
27066        _cx: &mut Context<Editor>,
27067    ) -> Task<Result<bool>> {
27068        Task::ready(Ok(false))
27069    }
27070
27071    fn apply_additional_edits_for_completion(
27072        &self,
27073        _buffer: Entity<Buffer>,
27074        _completions: Rc<RefCell<Box<[Completion]>>>,
27075        _completion_index: usize,
27076        _push_to_history: bool,
27077        _all_commit_ranges: Vec<Range<language::Anchor>>,
27078        _cx: &mut Context<Editor>,
27079    ) -> Task<Result<Option<language::Transaction>>> {
27080        Task::ready(Ok(None))
27081    }
27082
27083    fn is_completion_trigger(
27084        &self,
27085        buffer: &Entity<Buffer>,
27086        position: language::Anchor,
27087        text: &str,
27088        trigger_in_words: bool,
27089        cx: &mut Context<Editor>,
27090    ) -> bool;
27091
27092    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27093
27094    fn sort_completions(&self) -> bool {
27095        true
27096    }
27097
27098    fn filter_completions(&self) -> bool {
27099        true
27100    }
27101
27102    fn show_snippets(&self) -> bool {
27103        false
27104    }
27105}
27106
27107pub trait CodeActionProvider {
27108    fn id(&self) -> Arc<str>;
27109
27110    fn code_actions(
27111        &self,
27112        buffer: &Entity<Buffer>,
27113        range: Range<text::Anchor>,
27114        window: &mut Window,
27115        cx: &mut App,
27116    ) -> Task<Result<Vec<CodeAction>>>;
27117
27118    fn apply_code_action(
27119        &self,
27120        buffer_handle: Entity<Buffer>,
27121        action: CodeAction,
27122        excerpt_id: ExcerptId,
27123        push_to_history: bool,
27124        window: &mut Window,
27125        cx: &mut App,
27126    ) -> Task<Result<ProjectTransaction>>;
27127}
27128
27129impl CodeActionProvider for Entity<Project> {
27130    fn id(&self) -> Arc<str> {
27131        "project".into()
27132    }
27133
27134    fn code_actions(
27135        &self,
27136        buffer: &Entity<Buffer>,
27137        range: Range<text::Anchor>,
27138        _window: &mut Window,
27139        cx: &mut App,
27140    ) -> Task<Result<Vec<CodeAction>>> {
27141        self.update(cx, |project, cx| {
27142            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27143            let code_actions = project.code_actions(buffer, range, None, cx);
27144            cx.background_spawn(async move {
27145                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27146                Ok(code_lens_actions
27147                    .context("code lens fetch")?
27148                    .into_iter()
27149                    .flatten()
27150                    .chain(
27151                        code_actions
27152                            .context("code action fetch")?
27153                            .into_iter()
27154                            .flatten(),
27155                    )
27156                    .collect())
27157            })
27158        })
27159    }
27160
27161    fn apply_code_action(
27162        &self,
27163        buffer_handle: Entity<Buffer>,
27164        action: CodeAction,
27165        _excerpt_id: ExcerptId,
27166        push_to_history: bool,
27167        _window: &mut Window,
27168        cx: &mut App,
27169    ) -> Task<Result<ProjectTransaction>> {
27170        self.update(cx, |project, cx| {
27171            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27172        })
27173    }
27174}
27175
27176fn snippet_completions(
27177    project: &Project,
27178    buffer: &Entity<Buffer>,
27179    buffer_anchor: text::Anchor,
27180    classifier: CharClassifier,
27181    cx: &mut App,
27182) -> Task<Result<CompletionResponse>> {
27183    let languages = buffer.read(cx).languages_at(buffer_anchor);
27184    let snippet_store = project.snippets().read(cx);
27185
27186    let scopes: Vec<_> = languages
27187        .iter()
27188        .filter_map(|language| {
27189            let language_name = language.lsp_id();
27190            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27191
27192            if snippets.is_empty() {
27193                None
27194            } else {
27195                Some((language.default_scope(), snippets))
27196            }
27197        })
27198        .collect();
27199
27200    if scopes.is_empty() {
27201        return Task::ready(Ok(CompletionResponse {
27202            completions: vec![],
27203            display_options: CompletionDisplayOptions::default(),
27204            is_incomplete: false,
27205        }));
27206    }
27207
27208    let snapshot = buffer.read(cx).text_snapshot();
27209    let executor = cx.background_executor().clone();
27210
27211    cx.background_spawn(async move {
27212        let is_word_char = |c| classifier.is_word(c);
27213
27214        let mut is_incomplete = false;
27215        let mut completions: Vec<Completion> = Vec::new();
27216
27217        const MAX_PREFIX_LEN: usize = 128;
27218        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27219        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27220        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27221
27222        let max_buffer_window: String = snapshot
27223            .text_for_range(window_start..buffer_offset)
27224            .collect();
27225
27226        if max_buffer_window.is_empty() {
27227            return Ok(CompletionResponse {
27228                completions: vec![],
27229                display_options: CompletionDisplayOptions::default(),
27230                is_incomplete: true,
27231            });
27232        }
27233
27234        for (_scope, snippets) in scopes.into_iter() {
27235            // Sort snippets by word count to match longer snippet prefixes first.
27236            let mut sorted_snippet_candidates = snippets
27237                .iter()
27238                .enumerate()
27239                .flat_map(|(snippet_ix, snippet)| {
27240                    snippet
27241                        .prefix
27242                        .iter()
27243                        .enumerate()
27244                        .map(move |(prefix_ix, prefix)| {
27245                            let word_count =
27246                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27247                            ((snippet_ix, prefix_ix), prefix, word_count)
27248                        })
27249                })
27250                .collect_vec();
27251            sorted_snippet_candidates
27252                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27253
27254            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27255
27256            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27257                .take(
27258                    sorted_snippet_candidates
27259                        .first()
27260                        .map(|(_, _, word_count)| *word_count)
27261                        .unwrap_or_default(),
27262                )
27263                .collect_vec();
27264
27265            const MAX_RESULTS: usize = 100;
27266            // Each match also remembers how many characters from the buffer it consumed
27267            let mut matches: Vec<(StringMatch, usize)> = vec![];
27268
27269            let mut snippet_list_cutoff_index = 0;
27270            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27271                let word_count = buffer_index + 1;
27272                // Increase `snippet_list_cutoff_index` until we have all of the
27273                // snippets with sufficiently many words.
27274                while sorted_snippet_candidates
27275                    .get(snippet_list_cutoff_index)
27276                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27277                        *snippet_word_count >= word_count
27278                    })
27279                {
27280                    snippet_list_cutoff_index += 1;
27281                }
27282
27283                // Take only the candidates with at least `word_count` many words
27284                let snippet_candidates_at_word_len =
27285                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27286
27287                let candidates = snippet_candidates_at_word_len
27288                    .iter()
27289                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27290                    .enumerate() // index in `sorted_snippet_candidates`
27291                    // First char must match
27292                    .filter(|(_ix, prefix)| {
27293                        itertools::equal(
27294                            prefix
27295                                .chars()
27296                                .next()
27297                                .into_iter()
27298                                .flat_map(|c| c.to_lowercase()),
27299                            buffer_window
27300                                .chars()
27301                                .next()
27302                                .into_iter()
27303                                .flat_map(|c| c.to_lowercase()),
27304                        )
27305                    })
27306                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27307                    .collect::<Vec<StringMatchCandidate>>();
27308
27309                matches.extend(
27310                    fuzzy::match_strings(
27311                        &candidates,
27312                        &buffer_window,
27313                        buffer_window.chars().any(|c| c.is_uppercase()),
27314                        true,
27315                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27316                        &Default::default(),
27317                        executor.clone(),
27318                    )
27319                    .await
27320                    .into_iter()
27321                    .map(|string_match| (string_match, buffer_window.len())),
27322                );
27323
27324                if matches.len() >= MAX_RESULTS {
27325                    break;
27326                }
27327            }
27328
27329            let to_lsp = |point: &text::Anchor| {
27330                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27331                point_to_lsp(end)
27332            };
27333            let lsp_end = to_lsp(&buffer_anchor);
27334
27335            if matches.len() >= MAX_RESULTS {
27336                is_incomplete = true;
27337            }
27338
27339            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27340                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27341                    sorted_snippet_candidates[string_match.candidate_id];
27342                let snippet = &snippets[snippet_index];
27343                let start = buffer_offset - buffer_window_len;
27344                let start = snapshot.anchor_before(start);
27345                let range = start..buffer_anchor;
27346                let lsp_start = to_lsp(&start);
27347                let lsp_range = lsp::Range {
27348                    start: lsp_start,
27349                    end: lsp_end,
27350                };
27351                Completion {
27352                    replace_range: range,
27353                    new_text: snippet.body.clone(),
27354                    source: CompletionSource::Lsp {
27355                        insert_range: None,
27356                        server_id: LanguageServerId(usize::MAX),
27357                        resolved: true,
27358                        lsp_completion: Box::new(lsp::CompletionItem {
27359                            label: snippet.prefix.first().unwrap().clone(),
27360                            kind: Some(CompletionItemKind::SNIPPET),
27361                            label_details: snippet.description.as_ref().map(|description| {
27362                                lsp::CompletionItemLabelDetails {
27363                                    detail: Some(description.clone()),
27364                                    description: None,
27365                                }
27366                            }),
27367                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27368                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27369                                lsp::InsertReplaceEdit {
27370                                    new_text: snippet.body.clone(),
27371                                    insert: lsp_range,
27372                                    replace: lsp_range,
27373                                },
27374                            )),
27375                            filter_text: Some(snippet.body.clone()),
27376                            sort_text: Some(char::MAX.to_string()),
27377                            ..lsp::CompletionItem::default()
27378                        }),
27379                        lsp_defaults: None,
27380                    },
27381                    label: CodeLabel {
27382                        text: matching_prefix.clone(),
27383                        runs: Vec::new(),
27384                        filter_range: 0..matching_prefix.len(),
27385                    },
27386                    icon_path: None,
27387                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27388                        single_line: snippet.name.clone().into(),
27389                        plain_text: snippet
27390                            .description
27391                            .clone()
27392                            .map(|description| description.into()),
27393                    }),
27394                    insert_text_mode: None,
27395                    confirm: None,
27396                    match_start: Some(start),
27397                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27398                }
27399            }));
27400        }
27401
27402        Ok(CompletionResponse {
27403            completions,
27404            display_options: CompletionDisplayOptions::default(),
27405            is_incomplete,
27406        })
27407    })
27408}
27409
27410impl CompletionProvider for Entity<Project> {
27411    fn completions(
27412        &self,
27413        _excerpt_id: ExcerptId,
27414        buffer: &Entity<Buffer>,
27415        buffer_position: text::Anchor,
27416        options: CompletionContext,
27417        _window: &mut Window,
27418        cx: &mut Context<Editor>,
27419    ) -> Task<Result<Vec<CompletionResponse>>> {
27420        self.update(cx, |project, cx| {
27421            let task = project.completions(buffer, buffer_position, options, cx);
27422            cx.background_spawn(task)
27423        })
27424    }
27425
27426    fn resolve_completions(
27427        &self,
27428        buffer: Entity<Buffer>,
27429        completion_indices: Vec<usize>,
27430        completions: Rc<RefCell<Box<[Completion]>>>,
27431        cx: &mut Context<Editor>,
27432    ) -> Task<Result<bool>> {
27433        self.update(cx, |project, cx| {
27434            project.lsp_store().update(cx, |lsp_store, cx| {
27435                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27436            })
27437        })
27438    }
27439
27440    fn apply_additional_edits_for_completion(
27441        &self,
27442        buffer: Entity<Buffer>,
27443        completions: Rc<RefCell<Box<[Completion]>>>,
27444        completion_index: usize,
27445        push_to_history: bool,
27446        all_commit_ranges: Vec<Range<language::Anchor>>,
27447        cx: &mut Context<Editor>,
27448    ) -> Task<Result<Option<language::Transaction>>> {
27449        self.update(cx, |project, cx| {
27450            project.lsp_store().update(cx, |lsp_store, cx| {
27451                lsp_store.apply_additional_edits_for_completion(
27452                    buffer,
27453                    completions,
27454                    completion_index,
27455                    push_to_history,
27456                    all_commit_ranges,
27457                    cx,
27458                )
27459            })
27460        })
27461    }
27462
27463    fn is_completion_trigger(
27464        &self,
27465        buffer: &Entity<Buffer>,
27466        position: language::Anchor,
27467        text: &str,
27468        trigger_in_words: bool,
27469        cx: &mut Context<Editor>,
27470    ) -> bool {
27471        let mut chars = text.chars();
27472        let char = if let Some(char) = chars.next() {
27473            char
27474        } else {
27475            return false;
27476        };
27477        if chars.next().is_some() {
27478            return false;
27479        }
27480
27481        let buffer = buffer.read(cx);
27482        let snapshot = buffer.snapshot();
27483        let classifier = snapshot
27484            .char_classifier_at(position)
27485            .scope_context(Some(CharScopeContext::Completion));
27486        if trigger_in_words && classifier.is_word(char) {
27487            return true;
27488        }
27489
27490        buffer.completion_triggers().contains(text)
27491    }
27492
27493    fn show_snippets(&self) -> bool {
27494        true
27495    }
27496}
27497
27498impl SemanticsProvider for WeakEntity<Project> {
27499    fn hover(
27500        &self,
27501        buffer: &Entity<Buffer>,
27502        position: text::Anchor,
27503        cx: &mut App,
27504    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27505        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27506            .ok()
27507    }
27508
27509    fn document_highlights(
27510        &self,
27511        buffer: &Entity<Buffer>,
27512        position: text::Anchor,
27513        cx: &mut App,
27514    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27515        self.update(cx, |project, cx| {
27516            project.document_highlights(buffer, position, cx)
27517        })
27518        .ok()
27519    }
27520
27521    fn definitions(
27522        &self,
27523        buffer: &Entity<Buffer>,
27524        position: text::Anchor,
27525        kind: GotoDefinitionKind,
27526        cx: &mut App,
27527    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27528        self.update(cx, |project, cx| match kind {
27529            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27530            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27531            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27532            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27533        })
27534        .ok()
27535    }
27536
27537    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27538        self.update(cx, |project, cx| {
27539            if project
27540                .active_debug_session(cx)
27541                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27542            {
27543                return true;
27544            }
27545
27546            buffer.update(cx, |buffer, cx| {
27547                project.any_language_server_supports_inlay_hints(buffer, cx)
27548            })
27549        })
27550        .unwrap_or(false)
27551    }
27552
27553    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27554        self.update(cx, |project, cx| {
27555            buffer.update(cx, |buffer, cx| {
27556                project.any_language_server_supports_semantic_tokens(buffer, cx)
27557            })
27558        })
27559        .unwrap_or(false)
27560    }
27561
27562    fn inline_values(
27563        &self,
27564        buffer_handle: Entity<Buffer>,
27565        range: Range<text::Anchor>,
27566        cx: &mut App,
27567    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27568        self.update(cx, |project, cx| {
27569            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27570
27571            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27572        })
27573        .ok()
27574        .flatten()
27575    }
27576
27577    fn applicable_inlay_chunks(
27578        &self,
27579        buffer: &Entity<Buffer>,
27580        ranges: &[Range<text::Anchor>],
27581        cx: &mut App,
27582    ) -> Vec<Range<BufferRow>> {
27583        self.update(cx, |project, cx| {
27584            project.lsp_store().update(cx, |lsp_store, cx| {
27585                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27586            })
27587        })
27588        .unwrap_or_default()
27589    }
27590
27591    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27592        self.update(cx, |project, cx| {
27593            project.lsp_store().update(cx, |lsp_store, _| {
27594                lsp_store.invalidate_inlay_hints(for_buffers)
27595            })
27596        })
27597        .ok();
27598    }
27599
27600    fn inlay_hints(
27601        &self,
27602        invalidate: InvalidationStrategy,
27603        buffer: Entity<Buffer>,
27604        ranges: Vec<Range<text::Anchor>>,
27605        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27606        cx: &mut App,
27607    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27608        self.update(cx, |project, cx| {
27609            project.lsp_store().update(cx, |lsp_store, cx| {
27610                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27611            })
27612        })
27613        .ok()
27614    }
27615
27616    fn semantic_tokens(
27617        &self,
27618        buffer: Entity<Buffer>,
27619        refresh: Option<RefreshForServer>,
27620        cx: &mut App,
27621    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27622        self.update(cx, |this, cx| {
27623            this.lsp_store().update(cx, |lsp_store, cx| {
27624                lsp_store.semantic_tokens(buffer, refresh, cx)
27625            })
27626        })
27627        .ok()
27628    }
27629
27630    fn range_for_rename(
27631        &self,
27632        buffer: &Entity<Buffer>,
27633        position: text::Anchor,
27634        cx: &mut App,
27635    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
27636        self.update(cx, |project, cx| {
27637            let buffer = buffer.clone();
27638            let task = project.prepare_rename(buffer.clone(), position, cx);
27639            cx.spawn(async move |_, cx| {
27640                Ok(match task.await? {
27641                    PrepareRenameResponse::Success(range) => Some(range),
27642                    PrepareRenameResponse::InvalidPosition => None,
27643                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27644                        // Fallback on using TreeSitter info to determine identifier range
27645                        buffer.read_with(cx, |buffer, _| {
27646                            let snapshot = buffer.snapshot();
27647                            let (range, kind) = snapshot.surrounding_word(position, None);
27648                            if kind != Some(CharKind::Word) {
27649                                return None;
27650                            }
27651                            Some(
27652                                snapshot.anchor_before(range.start)
27653                                    ..snapshot.anchor_after(range.end),
27654                            )
27655                        })
27656                    }
27657                })
27658            })
27659        })
27660        .ok()
27661    }
27662
27663    fn perform_rename(
27664        &self,
27665        buffer: &Entity<Buffer>,
27666        position: text::Anchor,
27667        new_name: String,
27668        cx: &mut App,
27669    ) -> Option<Task<Result<ProjectTransaction>>> {
27670        self.update(cx, |project, cx| {
27671            project.perform_rename(buffer.clone(), position, new_name, cx)
27672        })
27673        .ok()
27674    }
27675}
27676
27677fn consume_contiguous_rows(
27678    contiguous_row_selections: &mut Vec<Selection<Point>>,
27679    selection: &Selection<Point>,
27680    display_map: &DisplaySnapshot,
27681    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27682) -> (MultiBufferRow, MultiBufferRow) {
27683    contiguous_row_selections.push(selection.clone());
27684    let start_row = starting_row(selection, display_map);
27685    let mut end_row = ending_row(selection, display_map);
27686
27687    while let Some(next_selection) = selections.peek() {
27688        if next_selection.start.row <= end_row.0 {
27689            end_row = ending_row(next_selection, display_map);
27690            contiguous_row_selections.push(selections.next().unwrap().clone());
27691        } else {
27692            break;
27693        }
27694    }
27695    (start_row, end_row)
27696}
27697
27698fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27699    if selection.start.column > 0 {
27700        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27701    } else {
27702        MultiBufferRow(selection.start.row)
27703    }
27704}
27705
27706fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27707    if next_selection.end.column > 0 || next_selection.is_empty() {
27708        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27709    } else {
27710        MultiBufferRow(next_selection.end.row)
27711    }
27712}
27713
27714impl EditorSnapshot {
27715    pub fn remote_selections_in_range<'a>(
27716        &'a self,
27717        range: &'a Range<Anchor>,
27718        collaboration_hub: &dyn CollaborationHub,
27719        cx: &'a App,
27720    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27721        let participant_names = collaboration_hub.user_names(cx);
27722        let participant_indices = collaboration_hub.user_participant_indices(cx);
27723        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27724        let collaborators_by_replica_id = collaborators_by_peer_id
27725            .values()
27726            .map(|collaborator| (collaborator.replica_id, collaborator))
27727            .collect::<HashMap<_, _>>();
27728        self.buffer_snapshot()
27729            .selections_in_range(range, false)
27730            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27731                if replica_id == ReplicaId::AGENT {
27732                    Some(RemoteSelection {
27733                        replica_id,
27734                        selection,
27735                        cursor_shape,
27736                        line_mode,
27737                        collaborator_id: CollaboratorId::Agent,
27738                        user_name: Some("Agent".into()),
27739                        color: cx.theme().players().agent(),
27740                    })
27741                } else {
27742                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27743                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27744                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27745                    Some(RemoteSelection {
27746                        replica_id,
27747                        selection,
27748                        cursor_shape,
27749                        line_mode,
27750                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27751                        user_name,
27752                        color: if let Some(index) = participant_index {
27753                            cx.theme().players().color_for_participant(index.0)
27754                        } else {
27755                            cx.theme().players().absent()
27756                        },
27757                    })
27758                }
27759            })
27760    }
27761
27762    pub fn hunks_for_ranges(
27763        &self,
27764        ranges: impl IntoIterator<Item = Range<Point>>,
27765    ) -> Vec<MultiBufferDiffHunk> {
27766        let mut hunks = Vec::new();
27767        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27768            HashMap::default();
27769        for query_range in ranges {
27770            let query_rows =
27771                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27772            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27773                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27774            ) {
27775                // Include deleted hunks that are adjacent to the query range, because
27776                // otherwise they would be missed.
27777                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27778                if hunk.status().is_deleted() {
27779                    intersects_range |= hunk.row_range.start == query_rows.end;
27780                    intersects_range |= hunk.row_range.end == query_rows.start;
27781                }
27782                if intersects_range {
27783                    if !processed_buffer_rows
27784                        .entry(hunk.buffer_id)
27785                        .or_default()
27786                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27787                    {
27788                        continue;
27789                    }
27790                    hunks.push(hunk);
27791                }
27792            }
27793        }
27794
27795        hunks
27796    }
27797
27798    fn display_diff_hunks_for_rows<'a>(
27799        &'a self,
27800        display_rows: Range<DisplayRow>,
27801        folded_buffers: &'a HashSet<BufferId>,
27802    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27803        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27804        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27805
27806        self.buffer_snapshot()
27807            .diff_hunks_in_range(buffer_start..buffer_end)
27808            .filter_map(|hunk| {
27809                if folded_buffers.contains(&hunk.buffer_id)
27810                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27811                {
27812                    return None;
27813                }
27814
27815                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27816                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27817                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27818                    let line_len = self.buffer_snapshot().line_len(last_row);
27819                    Point::new(last_row.0, line_len)
27820                } else {
27821                    Point::new(hunk.row_range.end.0, 0)
27822                };
27823
27824                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27825                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27826
27827                let display_hunk = if hunk_display_start.column() != 0 {
27828                    DisplayDiffHunk::Folded {
27829                        display_row: hunk_display_start.row(),
27830                    }
27831                } else {
27832                    let mut end_row = hunk_display_end.row();
27833                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27834                        end_row.0 += 1;
27835                    }
27836                    let is_created_file = hunk.is_created_file();
27837
27838                    DisplayDiffHunk::Unfolded {
27839                        status: hunk.status(),
27840                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27841                            ..hunk.diff_base_byte_range.end.0,
27842                        word_diffs: hunk.word_diffs,
27843                        display_row_range: hunk_display_start.row()..end_row,
27844                        multi_buffer_range: Anchor::range_in_buffer(
27845                            hunk.excerpt_id,
27846                            hunk.buffer_range,
27847                        ),
27848                        is_created_file,
27849                    }
27850                };
27851
27852                Some(display_hunk)
27853            })
27854    }
27855
27856    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27857        self.display_snapshot
27858            .buffer_snapshot()
27859            .language_at(position)
27860    }
27861
27862    pub fn is_focused(&self) -> bool {
27863        self.is_focused
27864    }
27865
27866    pub fn placeholder_text(&self) -> Option<String> {
27867        self.placeholder_display_snapshot
27868            .as_ref()
27869            .map(|display_map| display_map.text())
27870    }
27871
27872    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27873        self.scroll_anchor.scroll_position(&self.display_snapshot)
27874    }
27875
27876    pub fn gutter_dimensions(
27877        &self,
27878        font_id: FontId,
27879        font_size: Pixels,
27880        style: &EditorStyle,
27881        window: &mut Window,
27882        cx: &App,
27883    ) -> GutterDimensions {
27884        if self.show_gutter
27885            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27886            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27887        {
27888            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27889                matches!(
27890                    ProjectSettings::get_global(cx).git.git_gutter,
27891                    GitGutterSetting::TrackedFiles
27892                )
27893            });
27894            let gutter_settings = EditorSettings::get_global(cx).gutter;
27895            let show_line_numbers = self
27896                .show_line_numbers
27897                .unwrap_or(gutter_settings.line_numbers);
27898            let line_gutter_width = if show_line_numbers {
27899                // Avoid flicker-like gutter resizes when the line number gains another digit by
27900                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27901                let min_width_for_number_on_gutter =
27902                    ch_advance * gutter_settings.min_line_number_digits as f32;
27903                self.max_line_number_width(style, window)
27904                    .max(min_width_for_number_on_gutter)
27905            } else {
27906                0.0.into()
27907            };
27908
27909            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27910            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27911
27912            let git_blame_entries_width =
27913                self.git_blame_gutter_max_author_length
27914                    .map(|max_author_length| {
27915                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27916                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27917
27918                        /// The number of characters to dedicate to gaps and margins.
27919                        const SPACING_WIDTH: usize = 4;
27920
27921                        let max_char_count = max_author_length.min(renderer.max_author_length())
27922                            + ::git::SHORT_SHA_LENGTH
27923                            + MAX_RELATIVE_TIMESTAMP.len()
27924                            + SPACING_WIDTH;
27925
27926                        ch_advance * max_char_count
27927                    });
27928
27929            let is_singleton = self.buffer_snapshot().is_singleton();
27930
27931            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27932            left_padding += if !is_singleton {
27933                ch_width * 4.0
27934            } else if show_runnables || show_breakpoints {
27935                ch_width * 3.0
27936            } else if show_git_gutter && show_line_numbers {
27937                ch_width * 2.0
27938            } else if show_git_gutter || show_line_numbers {
27939                ch_width
27940            } else {
27941                px(0.)
27942            };
27943
27944            let shows_folds = is_singleton && gutter_settings.folds;
27945
27946            let right_padding = if shows_folds && show_line_numbers {
27947                ch_width * 4.0
27948            } else if shows_folds || (!is_singleton && show_line_numbers) {
27949                ch_width * 3.0
27950            } else if show_line_numbers {
27951                ch_width
27952            } else {
27953                px(0.)
27954            };
27955
27956            GutterDimensions {
27957                left_padding,
27958                right_padding,
27959                width: line_gutter_width + left_padding + right_padding,
27960                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27961                git_blame_entries_width,
27962            }
27963        } else if self.offset_content {
27964            GutterDimensions::default_with_margin(font_id, font_size, cx)
27965        } else {
27966            GutterDimensions::default()
27967        }
27968    }
27969
27970    pub fn render_crease_toggle(
27971        &self,
27972        buffer_row: MultiBufferRow,
27973        row_contains_cursor: bool,
27974        editor: Entity<Editor>,
27975        window: &mut Window,
27976        cx: &mut App,
27977    ) -> Option<AnyElement> {
27978        let folded = self.is_line_folded(buffer_row);
27979        let mut is_foldable = false;
27980
27981        if let Some(crease) = self
27982            .crease_snapshot
27983            .query_row(buffer_row, self.buffer_snapshot())
27984        {
27985            is_foldable = true;
27986            match crease {
27987                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27988                    if let Some(render_toggle) = render_toggle {
27989                        let toggle_callback =
27990                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27991                                if folded {
27992                                    editor.update(cx, |editor, cx| {
27993                                        editor.fold_at(buffer_row, window, cx)
27994                                    });
27995                                } else {
27996                                    editor.update(cx, |editor, cx| {
27997                                        editor.unfold_at(buffer_row, window, cx)
27998                                    });
27999                                }
28000                            });
28001                        return Some((render_toggle)(
28002                            buffer_row,
28003                            folded,
28004                            toggle_callback,
28005                            window,
28006                            cx,
28007                        ));
28008                    }
28009                }
28010            }
28011        }
28012
28013        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28014
28015        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28016            Some(
28017                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28018                    .toggle_state(folded)
28019                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28020                        if folded {
28021                            this.unfold_at(buffer_row, window, cx);
28022                        } else {
28023                            this.fold_at(buffer_row, window, cx);
28024                        }
28025                    }))
28026                    .into_any_element(),
28027            )
28028        } else {
28029            None
28030        }
28031    }
28032
28033    pub fn render_crease_trailer(
28034        &self,
28035        buffer_row: MultiBufferRow,
28036        window: &mut Window,
28037        cx: &mut App,
28038    ) -> Option<AnyElement> {
28039        let folded = self.is_line_folded(buffer_row);
28040        if let Crease::Inline { render_trailer, .. } = self
28041            .crease_snapshot
28042            .query_row(buffer_row, self.buffer_snapshot())?
28043        {
28044            let render_trailer = render_trailer.as_ref()?;
28045            Some(render_trailer(buffer_row, folded, window, cx))
28046        } else {
28047            None
28048        }
28049    }
28050
28051    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28052        let digit_count = self.widest_line_number().ilog10() + 1;
28053        column_pixels(style, digit_count as usize, window)
28054    }
28055
28056    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28057    ///
28058    /// This is positive if `base` is before `line`.
28059    fn relative_line_delta(
28060        &self,
28061        current_selection_head: DisplayRow,
28062        first_visible_row: DisplayRow,
28063        consider_wrapped_lines: bool,
28064    ) -> i64 {
28065        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28066        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28067
28068        if consider_wrapped_lines {
28069            let wrap_snapshot = self.wrap_snapshot();
28070            let base_wrap_row = wrap_snapshot
28071                .make_wrap_point(current_selection_head, Bias::Left)
28072                .row();
28073            let wrap_row = wrap_snapshot
28074                .make_wrap_point(first_visible_row, Bias::Left)
28075                .row();
28076
28077            wrap_row.0 as i64 - base_wrap_row.0 as i64
28078        } else {
28079            let fold_snapshot = self.fold_snapshot();
28080            let base_fold_row = fold_snapshot
28081                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28082                .row();
28083            let fold_row = fold_snapshot
28084                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28085                .row();
28086
28087            fold_row as i64 - base_fold_row as i64
28088        }
28089    }
28090
28091    /// Returns the unsigned relative line number to display for each row in `rows`.
28092    ///
28093    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28094    pub fn calculate_relative_line_numbers(
28095        &self,
28096        rows: &Range<DisplayRow>,
28097        current_selection_head: DisplayRow,
28098        count_wrapped_lines: bool,
28099    ) -> HashMap<DisplayRow, u32> {
28100        let initial_offset =
28101            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28102
28103        self.row_infos(rows.start)
28104            .take(rows.len())
28105            .enumerate()
28106            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28107            .filter(|(_row, row_info)| {
28108                row_info.buffer_row.is_some()
28109                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28110            })
28111            .enumerate()
28112            .filter_map(|(i, (row, row_info))| {
28113                // We want to ensure here that the current line has absolute
28114                // numbering, even if we are in a soft-wrapped line. With the
28115                // exception that if we are in a deleted line, we should number this
28116                // relative with 0, as otherwise it would have no line number at all
28117                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28118
28119                (relative_line_number != 0
28120                    || row_info
28121                        .diff_status
28122                        .is_some_and(|status| status.is_deleted()))
28123                .then_some((row, relative_line_number))
28124            })
28125            .collect()
28126    }
28127}
28128
28129pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28130    let font_size = style.text.font_size.to_pixels(window.rem_size());
28131    let layout = window.text_system().shape_line(
28132        SharedString::from(" ".repeat(column)),
28133        font_size,
28134        &[TextRun {
28135            len: column,
28136            font: style.text.font(),
28137            color: Hsla::default(),
28138            ..Default::default()
28139        }],
28140        None,
28141    );
28142
28143    layout.width
28144}
28145
28146impl Deref for EditorSnapshot {
28147    type Target = DisplaySnapshot;
28148
28149    fn deref(&self) -> &Self::Target {
28150        &self.display_snapshot
28151    }
28152}
28153
28154#[derive(Clone, Debug, PartialEq, Eq)]
28155pub enum EditorEvent {
28156    /// Emitted when the stored review comments change (added, removed, or updated).
28157    ReviewCommentsChanged {
28158        /// The new total count of review comments.
28159        total_count: usize,
28160    },
28161    InputIgnored {
28162        text: Arc<str>,
28163    },
28164    InputHandled {
28165        utf16_range_to_replace: Option<Range<isize>>,
28166        text: Arc<str>,
28167    },
28168    ExcerptsAdded {
28169        buffer: Entity<Buffer>,
28170        predecessor: ExcerptId,
28171        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
28172    },
28173    ExcerptsRemoved {
28174        ids: Vec<ExcerptId>,
28175        removed_buffer_ids: Vec<BufferId>,
28176    },
28177    BufferFoldToggled {
28178        ids: Vec<ExcerptId>,
28179        folded: bool,
28180    },
28181    ExcerptsEdited {
28182        ids: Vec<ExcerptId>,
28183    },
28184    ExcerptsExpanded {
28185        ids: Vec<ExcerptId>,
28186    },
28187    ExpandExcerptsRequested {
28188        excerpt_ids: Vec<ExcerptId>,
28189        lines: u32,
28190        direction: ExpandExcerptDirection,
28191    },
28192    StageOrUnstageRequested {
28193        stage: bool,
28194        hunks: Vec<MultiBufferDiffHunk>,
28195    },
28196    OpenExcerptsRequested {
28197        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28198        split: bool,
28199    },
28200    RestoreRequested {
28201        hunks: Vec<MultiBufferDiffHunk>,
28202    },
28203    BufferEdited,
28204    Edited {
28205        transaction_id: clock::Lamport,
28206    },
28207    Reparsed(BufferId),
28208    Focused,
28209    FocusedIn,
28210    Blurred,
28211    DirtyChanged,
28212    Saved,
28213    TitleChanged,
28214    SelectionsChanged {
28215        local: bool,
28216    },
28217    ScrollPositionChanged {
28218        local: bool,
28219        autoscroll: bool,
28220    },
28221    TransactionUndone {
28222        transaction_id: clock::Lamport,
28223    },
28224    TransactionBegun {
28225        transaction_id: clock::Lamport,
28226    },
28227    CursorShapeChanged,
28228    BreadcrumbsChanged,
28229    OutlineSymbolsChanged,
28230    PushedToNavHistory {
28231        anchor: Anchor,
28232        is_deactivate: bool,
28233    },
28234}
28235
28236impl EventEmitter<EditorEvent> for Editor {}
28237
28238impl Focusable for Editor {
28239    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28240        self.focus_handle.clone()
28241    }
28242}
28243
28244impl Render for Editor {
28245    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28246        EditorElement::new(&cx.entity(), self.create_style(cx))
28247    }
28248}
28249
28250impl EntityInputHandler for Editor {
28251    fn text_for_range(
28252        &mut self,
28253        range_utf16: Range<usize>,
28254        adjusted_range: &mut Option<Range<usize>>,
28255        _: &mut Window,
28256        cx: &mut Context<Self>,
28257    ) -> Option<String> {
28258        let snapshot = self.buffer.read(cx).read(cx);
28259        let start = snapshot.clip_offset_utf16(
28260            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28261            Bias::Left,
28262        );
28263        let end = snapshot.clip_offset_utf16(
28264            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28265            Bias::Right,
28266        );
28267        if (start.0.0..end.0.0) != range_utf16 {
28268            adjusted_range.replace(start.0.0..end.0.0);
28269        }
28270        Some(snapshot.text_for_range(start..end).collect())
28271    }
28272
28273    fn selected_text_range(
28274        &mut self,
28275        ignore_disabled_input: bool,
28276        _: &mut Window,
28277        cx: &mut Context<Self>,
28278    ) -> Option<UTF16Selection> {
28279        // Prevent the IME menu from appearing when holding down an alphabetic key
28280        // while input is disabled.
28281        if !ignore_disabled_input && !self.input_enabled {
28282            return None;
28283        }
28284
28285        let selection = self
28286            .selections
28287            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28288        let range = selection.range();
28289
28290        Some(UTF16Selection {
28291            range: range.start.0.0..range.end.0.0,
28292            reversed: selection.reversed,
28293        })
28294    }
28295
28296    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28297        let snapshot = self.buffer.read(cx).read(cx);
28298        let range = self
28299            .text_highlights(HighlightKey::InputComposition, cx)?
28300            .1
28301            .first()?;
28302        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28303    }
28304
28305    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28306        self.clear_highlights(HighlightKey::InputComposition, cx);
28307        self.ime_transaction.take();
28308    }
28309
28310    fn replace_text_in_range(
28311        &mut self,
28312        range_utf16: Option<Range<usize>>,
28313        text: &str,
28314        window: &mut Window,
28315        cx: &mut Context<Self>,
28316    ) {
28317        if !self.input_enabled {
28318            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28319            return;
28320        }
28321
28322        self.transact(window, cx, |this, window, cx| {
28323            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28324                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28325                    // During IME composition, macOS reports the replacement range
28326                    // relative to the first marked region (the only one visible via
28327                    // marked_text_range). The correct targets for replacement are the
28328                    // marked ranges themselves — one per cursor — so use them directly.
28329                    Some(marked_ranges)
28330                } else if range_utf16.start == range_utf16.end {
28331                    // An empty replacement range means "insert at cursor" with no text
28332                    // to replace. macOS reports the cursor position from its own
28333                    // (single-cursor) view of the buffer, which diverges from our actual
28334                    // cursor positions after multi-cursor edits have shifted offsets.
28335                    // Treating this as range_utf16=None lets each cursor insert in place.
28336                    None
28337                } else {
28338                    // Outside of IME composition (e.g. Accessibility Keyboard word
28339                    // completion), the range is an absolute document offset for the
28340                    // newest cursor. Fan it out to all cursors via
28341                    // selection_replacement_ranges, which applies the delta relative
28342                    // to the newest selection to every cursor.
28343                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28344                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28345                    Some(this.selection_replacement_ranges(range_utf16, cx))
28346                }
28347            } else {
28348                this.marked_text_ranges(cx)
28349            };
28350
28351            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28352                let newest_selection_id = this.selections.newest_anchor().id;
28353                this.selections
28354                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28355                    .iter()
28356                    .zip(ranges_to_replace.iter())
28357                    .find_map(|(selection, range)| {
28358                        if selection.id == newest_selection_id {
28359                            Some(
28360                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28361                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28362                            )
28363                        } else {
28364                            None
28365                        }
28366                    })
28367            });
28368
28369            cx.emit(EditorEvent::InputHandled {
28370                utf16_range_to_replace: range_to_replace,
28371                text: text.into(),
28372            });
28373
28374            if let Some(new_selected_ranges) = new_selected_ranges {
28375                // Only backspace if at least one range covers actual text. When all
28376                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28377                // Keyboard sends replacementRange=cursor..cursor), backspace would
28378                // incorrectly delete the character just before the cursor.
28379                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28380                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28381                    selections.select_ranges(new_selected_ranges)
28382                });
28383                if should_backspace {
28384                    this.backspace(&Default::default(), window, cx);
28385                }
28386            }
28387
28388            this.handle_input(text, window, cx);
28389        });
28390
28391        if let Some(transaction) = self.ime_transaction {
28392            self.buffer.update(cx, |buffer, cx| {
28393                buffer.group_until_transaction(transaction, cx);
28394            });
28395        }
28396
28397        self.unmark_text(window, cx);
28398    }
28399
28400    fn replace_and_mark_text_in_range(
28401        &mut self,
28402        range_utf16: Option<Range<usize>>,
28403        text: &str,
28404        new_selected_range_utf16: Option<Range<usize>>,
28405        window: &mut Window,
28406        cx: &mut Context<Self>,
28407    ) {
28408        if !self.input_enabled {
28409            return;
28410        }
28411
28412        let transaction = self.transact(window, cx, |this, window, cx| {
28413            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28414                let snapshot = this.buffer.read(cx).read(cx);
28415                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28416                    for marked_range in &mut marked_ranges {
28417                        marked_range.end = marked_range.start + relative_range_utf16.end;
28418                        marked_range.start += relative_range_utf16.start;
28419                        marked_range.start =
28420                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28421                        marked_range.end =
28422                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28423                    }
28424                }
28425                Some(marked_ranges)
28426            } else if let Some(range_utf16) = range_utf16 {
28427                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28428                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28429                Some(this.selection_replacement_ranges(range_utf16, cx))
28430            } else {
28431                None
28432            };
28433
28434            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28435                let newest_selection_id = this.selections.newest_anchor().id;
28436                this.selections
28437                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28438                    .iter()
28439                    .zip(ranges_to_replace.iter())
28440                    .find_map(|(selection, range)| {
28441                        if selection.id == newest_selection_id {
28442                            Some(
28443                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28444                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28445                            )
28446                        } else {
28447                            None
28448                        }
28449                    })
28450            });
28451
28452            cx.emit(EditorEvent::InputHandled {
28453                utf16_range_to_replace: range_to_replace,
28454                text: text.into(),
28455            });
28456
28457            if let Some(ranges) = ranges_to_replace {
28458                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28459                    s.select_ranges(ranges)
28460                });
28461            }
28462
28463            let marked_ranges = {
28464                let snapshot = this.buffer.read(cx).read(cx);
28465                this.selections
28466                    .disjoint_anchors_arc()
28467                    .iter()
28468                    .map(|selection| {
28469                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28470                    })
28471                    .collect::<Vec<_>>()
28472            };
28473
28474            if text.is_empty() {
28475                this.unmark_text(window, cx);
28476            } else {
28477                this.highlight_text(
28478                    HighlightKey::InputComposition,
28479                    marked_ranges.clone(),
28480                    HighlightStyle {
28481                        underline: Some(UnderlineStyle {
28482                            thickness: px(1.),
28483                            color: None,
28484                            wavy: false,
28485                        }),
28486                        ..Default::default()
28487                    },
28488                    cx,
28489                );
28490            }
28491
28492            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28493            let use_autoclose = this.use_autoclose;
28494            let use_auto_surround = this.use_auto_surround;
28495            this.set_use_autoclose(false);
28496            this.set_use_auto_surround(false);
28497            this.handle_input(text, window, cx);
28498            this.set_use_autoclose(use_autoclose);
28499            this.set_use_auto_surround(use_auto_surround);
28500
28501            if let Some(new_selected_range) = new_selected_range_utf16 {
28502                let snapshot = this.buffer.read(cx).read(cx);
28503                let new_selected_ranges = marked_ranges
28504                    .into_iter()
28505                    .map(|marked_range| {
28506                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28507                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28508                            insertion_start.0 + new_selected_range.start,
28509                        ));
28510                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28511                            insertion_start.0 + new_selected_range.end,
28512                        ));
28513                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28514                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28515                    })
28516                    .collect::<Vec<_>>();
28517
28518                drop(snapshot);
28519                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28520                    selections.select_ranges(new_selected_ranges)
28521                });
28522            }
28523        });
28524
28525        self.ime_transaction = self.ime_transaction.or(transaction);
28526        if let Some(transaction) = self.ime_transaction {
28527            self.buffer.update(cx, |buffer, cx| {
28528                buffer.group_until_transaction(transaction, cx);
28529            });
28530        }
28531
28532        if self
28533            .text_highlights(HighlightKey::InputComposition, cx)
28534            .is_none()
28535        {
28536            self.ime_transaction.take();
28537        }
28538    }
28539
28540    fn bounds_for_range(
28541        &mut self,
28542        range_utf16: Range<usize>,
28543        element_bounds: gpui::Bounds<Pixels>,
28544        window: &mut Window,
28545        cx: &mut Context<Self>,
28546    ) -> Option<gpui::Bounds<Pixels>> {
28547        let text_layout_details = self.text_layout_details(window, cx);
28548        let CharacterDimensions {
28549            em_width,
28550            em_advance,
28551            line_height,
28552        } = self.character_dimensions(window, cx);
28553
28554        let snapshot = self.snapshot(window, cx);
28555        let scroll_position = snapshot.scroll_position();
28556        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28557
28558        let start =
28559            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28560        let x = Pixels::from(
28561            ScrollOffset::from(
28562                snapshot.x_for_display_point(start, &text_layout_details)
28563                    + self.gutter_dimensions.full_width(),
28564            ) - scroll_left,
28565        );
28566        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28567
28568        Some(Bounds {
28569            origin: element_bounds.origin + point(x, y),
28570            size: size(em_width, line_height),
28571        })
28572    }
28573
28574    fn character_index_for_point(
28575        &mut self,
28576        point: gpui::Point<Pixels>,
28577        _window: &mut Window,
28578        _cx: &mut Context<Self>,
28579    ) -> Option<usize> {
28580        let position_map = self.last_position_map.as_ref()?;
28581        if !position_map.text_hitbox.contains(&point) {
28582            return None;
28583        }
28584        let display_point = position_map.point_for_position(point).previous_valid;
28585        let anchor = position_map
28586            .snapshot
28587            .display_point_to_anchor(display_point, Bias::Left);
28588        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28589        Some(utf16_offset.0.0)
28590    }
28591
28592    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28593        self.expects_character_input
28594    }
28595}
28596
28597trait SelectionExt {
28598    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28599    fn spanned_rows(
28600        &self,
28601        include_end_if_at_line_start: bool,
28602        map: &DisplaySnapshot,
28603    ) -> Range<MultiBufferRow>;
28604}
28605
28606impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28607    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28608        let start = self
28609            .start
28610            .to_point(map.buffer_snapshot())
28611            .to_display_point(map);
28612        let end = self
28613            .end
28614            .to_point(map.buffer_snapshot())
28615            .to_display_point(map);
28616        if self.reversed {
28617            end..start
28618        } else {
28619            start..end
28620        }
28621    }
28622
28623    fn spanned_rows(
28624        &self,
28625        include_end_if_at_line_start: bool,
28626        map: &DisplaySnapshot,
28627    ) -> Range<MultiBufferRow> {
28628        let start = self.start.to_point(map.buffer_snapshot());
28629        let mut end = self.end.to_point(map.buffer_snapshot());
28630        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28631            end.row -= 1;
28632        }
28633
28634        let buffer_start = map.prev_line_boundary(start).0;
28635        let buffer_end = map.next_line_boundary(end).0;
28636        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28637    }
28638}
28639
28640impl<T: InvalidationRegion> InvalidationStack<T> {
28641    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28642    where
28643        S: Clone + ToOffset,
28644    {
28645        while let Some(region) = self.last() {
28646            let all_selections_inside_invalidation_ranges =
28647                if selections.len() == region.ranges().len() {
28648                    selections
28649                        .iter()
28650                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28651                        .all(|(selection, invalidation_range)| {
28652                            let head = selection.head().to_offset(buffer);
28653                            invalidation_range.start <= head && invalidation_range.end >= head
28654                        })
28655                } else {
28656                    false
28657                };
28658
28659            if all_selections_inside_invalidation_ranges {
28660                break;
28661            } else {
28662                self.pop();
28663            }
28664        }
28665    }
28666}
28667
28668#[derive(Clone)]
28669struct ErasedEditorImpl(Entity<Editor>);
28670
28671impl ui_input::ErasedEditor for ErasedEditorImpl {
28672    fn text(&self, cx: &App) -> String {
28673        self.0.read(cx).text(cx)
28674    }
28675
28676    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28677        self.0.update(cx, |this, cx| {
28678            this.set_text(text, window, cx);
28679        })
28680    }
28681
28682    fn clear(&self, window: &mut Window, cx: &mut App) {
28683        self.0.update(cx, |this, cx| this.clear(window, cx));
28684    }
28685
28686    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28687        self.0.update(cx, |this, cx| {
28688            this.set_placeholder_text(text, window, cx);
28689        });
28690    }
28691
28692    fn focus_handle(&self, cx: &App) -> FocusHandle {
28693        self.0.read(cx).focus_handle(cx)
28694    }
28695
28696    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28697        let settings = ThemeSettings::get_global(cx);
28698        let theme_color = cx.theme().colors();
28699
28700        let text_style = TextStyle {
28701            font_family: settings.ui_font.family.clone(),
28702            font_features: settings.ui_font.features.clone(),
28703            font_size: rems(0.875).into(),
28704            font_weight: settings.ui_font.weight,
28705            font_style: FontStyle::Normal,
28706            line_height: relative(1.2),
28707            color: theme_color.text,
28708            ..Default::default()
28709        };
28710        let editor_style = EditorStyle {
28711            background: theme_color.ghost_element_background,
28712            local_player: cx.theme().players().local(),
28713            syntax: cx.theme().syntax().clone(),
28714            text: text_style,
28715            ..Default::default()
28716        };
28717        EditorElement::new(&self.0, editor_style).into_any()
28718    }
28719
28720    fn as_any(&self) -> &dyn Any {
28721        &self.0
28722    }
28723
28724    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28725        self.0.update(cx, |editor, cx| {
28726            let editor_offset = editor.buffer().read(cx).len(cx);
28727            editor.change_selections(
28728                SelectionEffects::scroll(Autoscroll::Next),
28729                window,
28730                cx,
28731                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28732            );
28733        });
28734    }
28735
28736    fn subscribe(
28737        &self,
28738        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28739        window: &mut Window,
28740        cx: &mut App,
28741    ) -> Subscription {
28742        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28743            let event = match event {
28744                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28745                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28746                _ => return,
28747            };
28748            (callback)(event, window, cx);
28749        })
28750    }
28751
28752    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28753        self.0.update(cx, |editor, cx| {
28754            editor.set_masked(masked, cx);
28755        });
28756    }
28757}
28758impl<T> Default for InvalidationStack<T> {
28759    fn default() -> Self {
28760        Self(Default::default())
28761    }
28762}
28763
28764impl<T> Deref for InvalidationStack<T> {
28765    type Target = Vec<T>;
28766
28767    fn deref(&self) -> &Self::Target {
28768        &self.0
28769    }
28770}
28771
28772impl<T> DerefMut for InvalidationStack<T> {
28773    fn deref_mut(&mut self) -> &mut Self::Target {
28774        &mut self.0
28775    }
28776}
28777
28778impl InvalidationRegion for SnippetState {
28779    fn ranges(&self) -> &[Range<Anchor>] {
28780        &self.ranges[self.active_index]
28781    }
28782}
28783
28784fn edit_prediction_edit_text(
28785    current_snapshot: &BufferSnapshot,
28786    edits: &[(Range<Anchor>, impl AsRef<str>)],
28787    edit_preview: &EditPreview,
28788    include_deletions: bool,
28789    cx: &App,
28790) -> HighlightedText {
28791    let edits = edits
28792        .iter()
28793        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
28794        .collect::<Vec<_>>();
28795
28796    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28797}
28798
28799fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28800    // Fallback for providers that don't provide edit_preview (like Copilot)
28801    // Just show the raw edit text with basic styling
28802    let mut text = String::new();
28803    let mut highlights = Vec::new();
28804
28805    let insertion_highlight_style = HighlightStyle {
28806        color: Some(cx.theme().colors().text),
28807        ..Default::default()
28808    };
28809
28810    for (_, edit_text) in edits {
28811        let start_offset = text.len();
28812        text.push_str(edit_text);
28813        let end_offset = text.len();
28814
28815        if start_offset < end_offset {
28816            highlights.push((start_offset..end_offset, insertion_highlight_style));
28817        }
28818    }
28819
28820    HighlightedText {
28821        text: text.into(),
28822        highlights,
28823    }
28824}
28825
28826pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28827    match severity {
28828        lsp::DiagnosticSeverity::ERROR => colors.error,
28829        lsp::DiagnosticSeverity::WARNING => colors.warning,
28830        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28831        lsp::DiagnosticSeverity::HINT => colors.info,
28832        _ => colors.ignored,
28833    }
28834}
28835
28836pub fn styled_runs_for_code_label<'a>(
28837    label: &'a CodeLabel,
28838    syntax_theme: &'a theme::SyntaxTheme,
28839    local_player: &'a theme::PlayerColor,
28840) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28841    let fade_out = HighlightStyle {
28842        fade_out: Some(0.35),
28843        ..Default::default()
28844    };
28845
28846    let mut prev_end = label.filter_range.end;
28847    label
28848        .runs
28849        .iter()
28850        .enumerate()
28851        .flat_map(move |(ix, (range, highlight_id))| {
28852            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28853                HighlightStyle {
28854                    color: Some(local_player.cursor),
28855                    ..Default::default()
28856                }
28857            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28858                HighlightStyle {
28859                    background_color: Some(local_player.selection),
28860                    ..Default::default()
28861                }
28862            } else if let Some(style) = highlight_id.style(syntax_theme) {
28863                style
28864            } else {
28865                return Default::default();
28866            };
28867            let muted_style = style.highlight(fade_out);
28868
28869            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28870            if range.start >= label.filter_range.end {
28871                if range.start > prev_end {
28872                    runs.push((prev_end..range.start, fade_out));
28873                }
28874                runs.push((range.clone(), muted_style));
28875            } else if range.end <= label.filter_range.end {
28876                runs.push((range.clone(), style));
28877            } else {
28878                runs.push((range.start..label.filter_range.end, style));
28879                runs.push((label.filter_range.end..range.end, muted_style));
28880            }
28881            prev_end = cmp::max(prev_end, range.end);
28882
28883            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28884                runs.push((prev_end..label.text.len(), fade_out));
28885            }
28886
28887            runs
28888        })
28889}
28890
28891pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28892    let mut prev_index = 0;
28893    let mut prev_codepoint: Option<char> = None;
28894    text.char_indices()
28895        .chain([(text.len(), '\0')])
28896        .filter_map(move |(index, codepoint)| {
28897            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28898            let is_boundary = index == text.len()
28899                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28900                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28901            if is_boundary {
28902                let chunk = &text[prev_index..index];
28903                prev_index = index;
28904                Some(chunk)
28905            } else {
28906                None
28907            }
28908        })
28909}
28910
28911/// Given a string of text immediately before the cursor, iterates over possible
28912/// strings a snippet could match to. More precisely: returns an iterator over
28913/// suffixes of `text` created by splitting at word boundaries (before & after
28914/// every non-word character).
28915///
28916/// Shorter suffixes are returned first.
28917pub(crate) fn snippet_candidate_suffixes<'a>(
28918    text: &'a str,
28919    is_word_char: &'a dyn Fn(char) -> bool,
28920) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28921    let mut prev_index = text.len();
28922    let mut prev_codepoint = None;
28923    text.char_indices()
28924        .rev()
28925        .chain([(0, '\0')])
28926        .filter_map(move |(index, codepoint)| {
28927            let prev_index = std::mem::replace(&mut prev_index, index);
28928            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28929            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28930                None
28931            } else {
28932                let chunk = &text[prev_index..]; // go to end of string
28933                Some(chunk)
28934            }
28935        })
28936}
28937
28938pub trait RangeToAnchorExt: Sized {
28939    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28940
28941    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28942        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28943        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28944    }
28945}
28946
28947impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28948    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28949        let start_offset = self.start.to_offset(snapshot);
28950        let end_offset = self.end.to_offset(snapshot);
28951        if start_offset == end_offset {
28952            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28953        } else {
28954            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28955        }
28956    }
28957}
28958
28959pub trait RowExt {
28960    fn as_f64(&self) -> f64;
28961
28962    fn next_row(&self) -> Self;
28963
28964    fn previous_row(&self) -> Self;
28965
28966    fn minus(&self, other: Self) -> u32;
28967}
28968
28969impl RowExt for DisplayRow {
28970    fn as_f64(&self) -> f64 {
28971        self.0 as _
28972    }
28973
28974    fn next_row(&self) -> Self {
28975        Self(self.0 + 1)
28976    }
28977
28978    fn previous_row(&self) -> Self {
28979        Self(self.0.saturating_sub(1))
28980    }
28981
28982    fn minus(&self, other: Self) -> u32 {
28983        self.0 - other.0
28984    }
28985}
28986
28987impl RowExt for MultiBufferRow {
28988    fn as_f64(&self) -> f64 {
28989        self.0 as _
28990    }
28991
28992    fn next_row(&self) -> Self {
28993        Self(self.0 + 1)
28994    }
28995
28996    fn previous_row(&self) -> Self {
28997        Self(self.0.saturating_sub(1))
28998    }
28999
29000    fn minus(&self, other: Self) -> u32 {
29001        self.0 - other.0
29002    }
29003}
29004
29005trait RowRangeExt {
29006    type Row;
29007
29008    fn len(&self) -> usize;
29009
29010    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29011}
29012
29013impl RowRangeExt for Range<MultiBufferRow> {
29014    type Row = MultiBufferRow;
29015
29016    fn len(&self) -> usize {
29017        (self.end.0 - self.start.0) as usize
29018    }
29019
29020    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29021        (self.start.0..self.end.0).map(MultiBufferRow)
29022    }
29023}
29024
29025impl RowRangeExt for Range<DisplayRow> {
29026    type Row = DisplayRow;
29027
29028    fn len(&self) -> usize {
29029        (self.end.0 - self.start.0) as usize
29030    }
29031
29032    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29033        (self.start.0..self.end.0).map(DisplayRow)
29034    }
29035}
29036
29037/// If select range has more than one line, we
29038/// just point the cursor to range.start.
29039fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29040    if range.start.row == range.end.row {
29041        range
29042    } else {
29043        range.start..range.start
29044    }
29045}
29046pub struct KillRing(ClipboardItem);
29047impl Global for KillRing {}
29048
29049const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29050
29051enum BreakpointPromptEditAction {
29052    Log,
29053    Condition,
29054    HitCondition,
29055}
29056
29057struct BreakpointPromptEditor {
29058    pub(crate) prompt: Entity<Editor>,
29059    editor: WeakEntity<Editor>,
29060    breakpoint_anchor: Anchor,
29061    breakpoint: Breakpoint,
29062    edit_action: BreakpointPromptEditAction,
29063    block_ids: HashSet<CustomBlockId>,
29064    editor_margins: Arc<Mutex<EditorMargins>>,
29065    _subscriptions: Vec<Subscription>,
29066}
29067
29068impl BreakpointPromptEditor {
29069    const MAX_LINES: u8 = 4;
29070
29071    fn new(
29072        editor: WeakEntity<Editor>,
29073        breakpoint_anchor: Anchor,
29074        breakpoint: Breakpoint,
29075        edit_action: BreakpointPromptEditAction,
29076        window: &mut Window,
29077        cx: &mut Context<Self>,
29078    ) -> Self {
29079        let base_text = match edit_action {
29080            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29081            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29082            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29083        }
29084        .map(|msg| msg.to_string())
29085        .unwrap_or_default();
29086
29087        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29088        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29089
29090        let prompt = cx.new(|cx| {
29091            let mut prompt = Editor::new(
29092                EditorMode::AutoHeight {
29093                    min_lines: 1,
29094                    max_lines: Some(Self::MAX_LINES as usize),
29095                },
29096                buffer,
29097                None,
29098                window,
29099                cx,
29100            );
29101            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29102            prompt.set_show_cursor_when_unfocused(false, cx);
29103            prompt.set_placeholder_text(
29104                match edit_action {
29105                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29106                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29107                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29108                },
29109                window,
29110                cx,
29111            );
29112
29113            prompt
29114        });
29115
29116        Self {
29117            prompt,
29118            editor,
29119            breakpoint_anchor,
29120            breakpoint,
29121            edit_action,
29122            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29123            block_ids: Default::default(),
29124            _subscriptions: vec![],
29125        }
29126    }
29127
29128    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29129        self.block_ids.extend(block_ids)
29130    }
29131
29132    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29133        if let Some(editor) = self.editor.upgrade() {
29134            let message = self
29135                .prompt
29136                .read(cx)
29137                .buffer
29138                .read(cx)
29139                .as_singleton()
29140                .expect("A multi buffer in breakpoint prompt isn't possible")
29141                .read(cx)
29142                .as_rope()
29143                .to_string();
29144
29145            editor.update(cx, |editor, cx| {
29146                editor.edit_breakpoint_at_anchor(
29147                    self.breakpoint_anchor,
29148                    self.breakpoint.clone(),
29149                    match self.edit_action {
29150                        BreakpointPromptEditAction::Log => {
29151                            BreakpointEditAction::EditLogMessage(message.into())
29152                        }
29153                        BreakpointPromptEditAction::Condition => {
29154                            BreakpointEditAction::EditCondition(message.into())
29155                        }
29156                        BreakpointPromptEditAction::HitCondition => {
29157                            BreakpointEditAction::EditHitCondition(message.into())
29158                        }
29159                    },
29160                    cx,
29161                );
29162
29163                editor.remove_blocks(self.block_ids.clone(), None, cx);
29164                cx.focus_self(window);
29165            });
29166        }
29167    }
29168
29169    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29170        self.editor
29171            .update(cx, |editor, cx| {
29172                editor.remove_blocks(self.block_ids.clone(), None, cx);
29173                window.focus(&editor.focus_handle, cx);
29174            })
29175            .log_err();
29176    }
29177
29178    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29179        let settings = ThemeSettings::get_global(cx);
29180        let text_style = TextStyle {
29181            color: if self.prompt.read(cx).read_only(cx) {
29182                cx.theme().colors().text_disabled
29183            } else {
29184                cx.theme().colors().text
29185            },
29186            font_family: settings.buffer_font.family.clone(),
29187            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29188            font_size: settings.buffer_font_size(cx).into(),
29189            font_weight: settings.buffer_font.weight,
29190            line_height: relative(settings.buffer_line_height.value()),
29191            ..Default::default()
29192        };
29193        EditorElement::new(
29194            &self.prompt,
29195            EditorStyle {
29196                background: cx.theme().colors().editor_background,
29197                local_player: cx.theme().players().local(),
29198                text: text_style,
29199                ..Default::default()
29200            },
29201        )
29202    }
29203
29204    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29205        let focus_handle = self.prompt.focus_handle(cx);
29206        IconButton::new("cancel", IconName::Close)
29207            .icon_color(Color::Muted)
29208            .shape(IconButtonShape::Square)
29209            .tooltip(move |_window, cx| {
29210                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29211            })
29212            .on_click(cx.listener(|this, _, window, cx| {
29213                this.cancel(&menu::Cancel, window, cx);
29214            }))
29215    }
29216
29217    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29218        let focus_handle = self.prompt.focus_handle(cx);
29219        IconButton::new("confirm", IconName::Return)
29220            .icon_color(Color::Muted)
29221            .shape(IconButtonShape::Square)
29222            .tooltip(move |_window, cx| {
29223                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29224            })
29225            .on_click(cx.listener(|this, _, window, cx| {
29226                this.confirm(&menu::Confirm, window, cx);
29227            }))
29228    }
29229}
29230
29231impl Render for BreakpointPromptEditor {
29232    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29233        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29234        let editor_margins = *self.editor_margins.lock();
29235        let gutter_dimensions = editor_margins.gutter;
29236        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29237        let right_padding = editor_margins.right + px(9.);
29238        h_flex()
29239            .key_context("Editor")
29240            .bg(cx.theme().colors().editor_background)
29241            .border_y_1()
29242            .border_color(cx.theme().status().info_border)
29243            .size_full()
29244            .py(window.line_height() / 2.5)
29245            .pr(right_padding)
29246            .on_action(cx.listener(Self::confirm))
29247            .on_action(cx.listener(Self::cancel))
29248            .child(
29249                WithRemSize::new(ui_font_size)
29250                    .h_full()
29251                    .w(left_gutter_width)
29252                    .flex()
29253                    .flex_row()
29254                    .flex_shrink_0()
29255                    .items_center()
29256                    .justify_center()
29257                    .gap_1()
29258                    .child(self.render_close_button(cx)),
29259            )
29260            .child(
29261                h_flex()
29262                    .w_full()
29263                    .justify_between()
29264                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29265                    .child(
29266                        WithRemSize::new(ui_font_size)
29267                            .flex()
29268                            .flex_row()
29269                            .items_center()
29270                            .child(self.render_confirm_button(cx)),
29271                    ),
29272            )
29273    }
29274}
29275
29276impl Focusable for BreakpointPromptEditor {
29277    fn focus_handle(&self, cx: &App) -> FocusHandle {
29278        self.prompt.focus_handle(cx)
29279    }
29280}
29281
29282fn all_edits_insertions_or_deletions(
29283    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29284    snapshot: &MultiBufferSnapshot,
29285) -> bool {
29286    let mut all_insertions = true;
29287    let mut all_deletions = true;
29288
29289    for (range, new_text) in edits.iter() {
29290        let range_is_empty = range.to_offset(snapshot).is_empty();
29291        let text_is_empty = new_text.is_empty();
29292
29293        if range_is_empty != text_is_empty {
29294            if range_is_empty {
29295                all_deletions = false;
29296            } else {
29297                all_insertions = false;
29298            }
29299        } else {
29300            return false;
29301        }
29302
29303        if !all_insertions && !all_deletions {
29304            return false;
29305        }
29306    }
29307    all_insertions || all_deletions
29308}
29309
29310struct MissingEditPredictionKeybindingTooltip;
29311
29312impl Render for MissingEditPredictionKeybindingTooltip {
29313    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29314        ui::tooltip_container(cx, |container, cx| {
29315            container
29316                .flex_shrink_0()
29317                .max_w_80()
29318                .min_h(rems_from_px(124.))
29319                .justify_between()
29320                .child(
29321                    v_flex()
29322                        .flex_1()
29323                        .text_ui_sm(cx)
29324                        .child(Label::new("Conflict with Accept Keybinding"))
29325                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29326                )
29327                .child(
29328                    h_flex()
29329                        .pb_1()
29330                        .gap_1()
29331                        .items_end()
29332                        .w_full()
29333                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29334                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29335                        }))
29336                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29337                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29338                        })),
29339                )
29340        })
29341    }
29342}
29343
29344#[derive(Debug, Clone, Copy, PartialEq)]
29345pub struct LineHighlight {
29346    pub background: Background,
29347    pub border: Option<gpui::Hsla>,
29348    pub include_gutter: bool,
29349    pub type_id: Option<TypeId>,
29350}
29351
29352struct LineManipulationResult {
29353    pub new_text: String,
29354    pub line_count_before: usize,
29355    pub line_count_after: usize,
29356}
29357
29358fn render_diff_hunk_controls(
29359    row: u32,
29360    status: &DiffHunkStatus,
29361    hunk_range: Range<Anchor>,
29362    is_created_file: bool,
29363    line_height: Pixels,
29364    editor: &Entity<Editor>,
29365    _window: &mut Window,
29366    cx: &mut App,
29367) -> AnyElement {
29368    h_flex()
29369        .h(line_height)
29370        .mr_1()
29371        .gap_1()
29372        .px_0p5()
29373        .pb_1()
29374        .border_x_1()
29375        .border_b_1()
29376        .border_color(cx.theme().colors().border_variant)
29377        .rounded_b_lg()
29378        .bg(cx.theme().colors().editor_background)
29379        .gap_1()
29380        .block_mouse_except_scroll()
29381        .shadow_md()
29382        .child(if status.has_secondary_hunk() {
29383            Button::new(("stage", row as u64), "Stage")
29384                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29385                .tooltip({
29386                    let focus_handle = editor.focus_handle(cx);
29387                    move |_window, cx| {
29388                        Tooltip::for_action_in(
29389                            "Stage Hunk",
29390                            &::git::ToggleStaged,
29391                            &focus_handle,
29392                            cx,
29393                        )
29394                    }
29395                })
29396                .on_click({
29397                    let editor = editor.clone();
29398                    move |_event, _window, cx| {
29399                        editor.update(cx, |editor, cx| {
29400                            editor.stage_or_unstage_diff_hunks(
29401                                true,
29402                                vec![hunk_range.start..hunk_range.start],
29403                                cx,
29404                            );
29405                        });
29406                    }
29407                })
29408        } else {
29409            Button::new(("unstage", row as u64), "Unstage")
29410                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29411                .tooltip({
29412                    let focus_handle = editor.focus_handle(cx);
29413                    move |_window, cx| {
29414                        Tooltip::for_action_in(
29415                            "Unstage Hunk",
29416                            &::git::ToggleStaged,
29417                            &focus_handle,
29418                            cx,
29419                        )
29420                    }
29421                })
29422                .on_click({
29423                    let editor = editor.clone();
29424                    move |_event, _window, cx| {
29425                        editor.update(cx, |editor, cx| {
29426                            editor.stage_or_unstage_diff_hunks(
29427                                false,
29428                                vec![hunk_range.start..hunk_range.start],
29429                                cx,
29430                            );
29431                        });
29432                    }
29433                })
29434        })
29435        .child(
29436            Button::new(("restore", row as u64), "Restore")
29437                .tooltip({
29438                    let focus_handle = editor.focus_handle(cx);
29439                    move |_window, cx| {
29440                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29441                    }
29442                })
29443                .on_click({
29444                    let editor = editor.clone();
29445                    move |_event, window, cx| {
29446                        editor.update(cx, |editor, cx| {
29447                            let snapshot = editor.snapshot(window, cx);
29448                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29449                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29450                        });
29451                    }
29452                })
29453                .disabled(is_created_file),
29454        )
29455        .when(
29456            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29457            |el| {
29458                el.child(
29459                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29460                        .shape(IconButtonShape::Square)
29461                        .icon_size(IconSize::Small)
29462                        // .disabled(!has_multiple_hunks)
29463                        .tooltip({
29464                            let focus_handle = editor.focus_handle(cx);
29465                            move |_window, cx| {
29466                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29467                            }
29468                        })
29469                        .on_click({
29470                            let editor = editor.clone();
29471                            move |_event, window, cx| {
29472                                editor.update(cx, |editor, cx| {
29473                                    let snapshot = editor.snapshot(window, cx);
29474                                    let position =
29475                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29476                                    editor.go_to_hunk_before_or_after_position(
29477                                        &snapshot,
29478                                        position,
29479                                        Direction::Next,
29480                                        true,
29481                                        window,
29482                                        cx,
29483                                    );
29484                                    editor.expand_selected_diff_hunks(cx);
29485                                });
29486                            }
29487                        }),
29488                )
29489                .child(
29490                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29491                        .shape(IconButtonShape::Square)
29492                        .icon_size(IconSize::Small)
29493                        // .disabled(!has_multiple_hunks)
29494                        .tooltip({
29495                            let focus_handle = editor.focus_handle(cx);
29496                            move |_window, cx| {
29497                                Tooltip::for_action_in(
29498                                    "Previous Hunk",
29499                                    &GoToPreviousHunk,
29500                                    &focus_handle,
29501                                    cx,
29502                                )
29503                            }
29504                        })
29505                        .on_click({
29506                            let editor = editor.clone();
29507                            move |_event, window, cx| {
29508                                editor.update(cx, |editor, cx| {
29509                                    let snapshot = editor.snapshot(window, cx);
29510                                    let point =
29511                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29512                                    editor.go_to_hunk_before_or_after_position(
29513                                        &snapshot,
29514                                        point,
29515                                        Direction::Prev,
29516                                        true,
29517                                        window,
29518                                        cx,
29519                                    );
29520                                    editor.expand_selected_diff_hunks(cx);
29521                                });
29522                            }
29523                        }),
29524                )
29525            },
29526        )
29527        .into_any_element()
29528}
29529
29530pub fn multibuffer_context_lines(cx: &App) -> u32 {
29531    EditorSettings::try_get(cx)
29532        .map(|settings| settings.excerpt_context_lines)
29533        .unwrap_or(2)
29534        .min(32)
29535}