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_block_comment_tests;
   52#[cfg(test)]
   53mod editor_tests;
   54mod signature_help;
   55#[cfg(any(test, feature = "test-support"))]
   56pub mod test;
   57
   58pub(crate) use actions::*;
   59pub use display_map::{
   60    ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder, HighlightKey,
   61    SemanticTokenHighlight,
   62};
   63pub use edit_prediction_types::Direction;
   64pub use editor_settings::{
   65    CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
   66    EditorSettings, EditorSettingsScrollbarProxy, HideMouseMode, ScrollBeyondLastLine,
   67    ScrollbarAxes, SearchSettings, ShowMinimap, ui_scrollbar_settings_from_raw,
   68};
   69pub use element::{
   70    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   71    render_breadcrumb_text,
   72};
   73pub use git::blame::BlameRenderer;
   74pub use hover_popover::hover_markdown_style;
   75pub use inlays::Inlay;
   76pub use items::MAX_TAB_TITLE_LEN;
   77pub use linked_editing_ranges::LinkedEdits;
   78pub use lsp::CompletionContext;
   79pub use lsp_ext::lsp_tasks;
   80pub use multi_buffer::{
   81    Anchor, AnchorRangeExt, BufferOffset, ExcerptRange, MBTextSummary, MultiBuffer,
   82    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   83    ToPoint,
   84};
   85pub use split::{SplittableEditor, ToggleSplitDiff};
   86pub use split_editor_view::SplitEditorView;
   87pub use text::Bias;
   88
   89use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   90use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   91use anyhow::{Context as _, Result, anyhow, bail};
   92use blink_manager::BlinkManager;
   93use buffer_diff::DiffHunkStatus;
   94use client::{Collaborator, ParticipantIndex, parse_zed_link};
   95use clock::ReplicaId;
   96use code_context_menus::{
   97    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   98    CompletionsMenu, ContextMenuOrigin,
   99};
  100use collections::{BTreeMap, HashMap, HashSet, VecDeque};
  101use convert_case::{Case, Casing};
  102use dap::TelemetrySpawnLocation;
  103use display_map::*;
  104use document_colors::LspColorData;
  105use edit_prediction_types::{
  106    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason,
  107    EditPredictionGranularity, SuggestionDisplayType,
  108};
  109use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
  110use element::{LineWithInvisibles, PositionMap, layout_line};
  111use futures::{
  112    FutureExt,
  113    future::{self, Shared, join},
  114};
  115use fuzzy::{StringMatch, StringMatchCandidate};
  116use git::blame::{GitBlame, GlobalBlameRenderer};
  117use gpui::{
  118    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  119    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  120    DispatchPhase, Edges, Entity, EntityId, EntityInputHandler, EventEmitter, FocusHandle,
  121    FocusOutEvent, Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla,
  122    KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement,
  123    Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled,
  124    Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  125    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  126    pulsating_between, px, relative, size,
  127};
  128use hover_links::{HoverLink, HoveredLinkState, find_file};
  129use hover_popover::{HoverState, hide_hover};
  130use indent_guides::ActiveIndentGuidesState;
  131use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  132use itertools::{Either, Itertools};
  133use language::{
  134    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  135    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  136    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  137    IndentSize, Language, LanguageAwareStyling, LanguageName, LanguageRegistry, LanguageScope,
  138    LocalFile, OffsetRangeExt, OutlineItem, Point, Selection, SelectionGoal, TextObject,
  139    TransactionId, TreeSitterOptions, WordsQuery,
  140    language_settings::{
  141        self, AllLanguageSettings, LanguageSettings, LspInsertMode, RewrapBehavior,
  142        WordsCompletionMode, all_language_settings,
  143    },
  144    point_from_lsp, point_to_lsp, text_diff_with_options,
  145};
  146use linked_editing_ranges::refresh_linked_ranges;
  147use lsp::{
  148    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  149    LanguageServerId,
  150};
  151use markdown::Markdown;
  152use mouse_context_menu::MouseContextMenu;
  153use movement::TextLayoutDetails;
  154use multi_buffer::{
  155    ExcerptBoundaryInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint,
  156    MultiBufferRow,
  157};
  158use parking_lot::Mutex;
  159use persistence::EditorDb;
  160use project::{
  161    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  162    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  163    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  164    ProjectItem, ProjectPath, ProjectTransaction,
  165    debugger::{
  166        breakpoint_store::{
  167            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  168            BreakpointStore, BreakpointStoreEvent,
  169        },
  170        session::{Session, SessionEvent},
  171    },
  172    git_store::GitStoreEvent,
  173    lsp_store::{
  174        BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger,
  175        LspFormatTarget, OpenLspBufferHandle, RefreshForServer,
  176    },
  177    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  178};
  179use rand::seq::SliceRandom;
  180use regex::Regex;
  181use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  182use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};
  183use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  184use serde::{Deserialize, Serialize};
  185use settings::{
  186    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  187    update_settings_file,
  188};
  189use smallvec::{SmallVec, smallvec};
  190use snippet::Snippet;
  191use std::{
  192    any::{Any, TypeId},
  193    borrow::Cow,
  194    cell::{OnceCell, RefCell},
  195    cmp::{self, Ordering, Reverse},
  196    collections::hash_map,
  197    iter::{self, Peekable},
  198    mem,
  199    num::NonZeroU32,
  200    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  201    path::{Path, PathBuf},
  202    rc::Rc,
  203    sync::Arc,
  204    time::{Duration, Instant},
  205};
  206use task::TaskVariables;
  207use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};
  208use theme::{
  209    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  210};
  211use theme_settings::{ThemeSettings, observe_buffer_font_size_adjustment};
  212use ui::{
  213    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  214    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  215    utils::WithRemSize,
  216};
  217use ui_input::ErasedEditor;
  218use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  219use workspace::{
  220    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  221    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  222    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  223    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  224    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  225    searchable::SearchEvent,
  226};
  227pub use zed_actions::editor::RevealInFileManager;
  228use zed_actions::editor::{MoveDown, MoveUp};
  229
  230use crate::{
  231    code_context_menus::CompletionsMenuSource,
  232    editor_settings::MultiCursorModifier,
  233    hover_links::{find_url, find_url_from_range},
  234    inlays::{
  235        InlineValueCache,
  236        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  237    },
  238    runnables::{ResolvedTasks, RunnableData, RunnableTasks},
  239    scroll::{ScrollOffset, ScrollPixelOffset},
  240    selections_collection::resolve_selections_wrapping_blocks,
  241    semantic_tokens::SemanticTokenState,
  242    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  243};
  244
  245pub const FILE_HEADER_HEIGHT: u32 = 2;
  246pub const BUFFER_HEADER_PADDING: Rems = rems(0.25);
  247pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  248const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  249const MAX_LINE_LEN: usize = 1024;
  250const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  251const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  252pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  253#[doc(hidden)]
  254pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  255pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  256
  257pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  258pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  259pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  260pub const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50);
  261
  262pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  263pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  264
  265pub type RenderDiffHunkControlsFn = Arc<
  266    dyn Fn(
  267        u32,
  268        &DiffHunkStatus,
  269        Range<Anchor>,
  270        bool,
  271        Pixels,
  272        &Entity<Editor>,
  273        &mut Window,
  274        &mut App,
  275    ) -> AnyElement,
  276>;
  277
  278enum ReportEditorEvent {
  279    Saved { auto_saved: bool },
  280    EditorOpened,
  281    Closed,
  282}
  283
  284impl ReportEditorEvent {
  285    pub fn event_type(&self) -> &'static str {
  286        match self {
  287            Self::Saved { .. } => "Editor Saved",
  288            Self::EditorOpened => "Editor Opened",
  289            Self::Closed => "Editor Closed",
  290        }
  291    }
  292}
  293
  294pub enum ActiveDebugLine {}
  295pub enum DebugStackFrameLine {}
  296
  297pub enum ConflictsOuter {}
  298pub enum ConflictsOurs {}
  299pub enum ConflictsTheirs {}
  300pub enum ConflictsOursMarker {}
  301pub enum ConflictsTheirsMarker {}
  302
  303pub struct HunkAddedColor;
  304pub struct HunkRemovedColor;
  305
  306#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  307pub enum Navigated {
  308    Yes,
  309    No,
  310}
  311
  312impl Navigated {
  313    pub fn from_bool(yes: bool) -> Navigated {
  314        if yes { Navigated::Yes } else { Navigated::No }
  315    }
  316}
  317
  318#[derive(Debug, Clone, PartialEq, Eq)]
  319enum DisplayDiffHunk {
  320    Folded {
  321        display_row: DisplayRow,
  322    },
  323    Unfolded {
  324        is_created_file: bool,
  325        diff_base_byte_range: Range<usize>,
  326        display_row_range: Range<DisplayRow>,
  327        multi_buffer_range: Range<Anchor>,
  328        status: DiffHunkStatus,
  329        word_diffs: Vec<Range<MultiBufferOffset>>,
  330    },
  331}
  332
  333pub enum HideMouseCursorOrigin {
  334    TypingAction,
  335    MovementAction,
  336}
  337
  338pub fn init(cx: &mut App) {
  339    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  340    cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
  341
  342    workspace::register_project_item::<Editor>(cx);
  343    workspace::FollowableViewRegistry::register::<Editor>(cx);
  344    workspace::register_serializable_item::<Editor>(cx);
  345
  346    cx.observe_new(
  347        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  348            workspace.register_action(Editor::new_file);
  349            workspace.register_action(Editor::new_file_split);
  350            workspace.register_action(Editor::new_file_vertical);
  351            workspace.register_action(Editor::new_file_horizontal);
  352            workspace.register_action(Editor::cancel_language_server_work);
  353            workspace.register_action(Editor::toggle_focus);
  354        },
  355    )
  356    .detach();
  357
  358    cx.on_action(move |_: &workspace::NewFile, cx| {
  359        let app_state = workspace::AppState::global(cx);
  360        workspace::open_new(
  361            Default::default(),
  362            app_state,
  363            cx,
  364            |workspace, window, cx| Editor::new_file(workspace, &Default::default(), window, cx),
  365        )
  366        .detach_and_log_err(cx);
  367    })
  368    .on_action(move |_: &workspace::NewWindow, cx| {
  369        let app_state = workspace::AppState::global(cx);
  370        workspace::open_new(
  371            Default::default(),
  372            app_state,
  373            cx,
  374            |workspace, window, cx| {
  375                cx.activate(true);
  376                Editor::new_file(workspace, &Default::default(), window, cx)
  377            },
  378        )
  379        .detach_and_log_err(cx);
  380    });
  381    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  382        Arc::new(ErasedEditorImpl(
  383            cx.new(|cx| Editor::single_line(window, cx)),
  384        )) as Arc<dyn ErasedEditor>
  385    });
  386    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  387}
  388
  389pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  390    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  391}
  392
  393pub trait DiagnosticRenderer {
  394    fn render_group(
  395        &self,
  396        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  397        buffer_id: BufferId,
  398        snapshot: EditorSnapshot,
  399        editor: WeakEntity<Editor>,
  400        language_registry: Option<Arc<LanguageRegistry>>,
  401        cx: &mut App,
  402    ) -> Vec<BlockProperties<Anchor>>;
  403
  404    fn render_hover(
  405        &self,
  406        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  407        range: Range<Point>,
  408        buffer_id: BufferId,
  409        language_registry: Option<Arc<LanguageRegistry>>,
  410        cx: &mut App,
  411    ) -> Option<Entity<markdown::Markdown>>;
  412
  413    fn open_link(
  414        &self,
  415        editor: &mut Editor,
  416        link: SharedString,
  417        window: &mut Window,
  418        cx: &mut Context<Editor>,
  419    );
  420}
  421
  422pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  423
  424impl GlobalDiagnosticRenderer {
  425    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  426        cx.try_global::<Self>().map(|g| g.0.clone())
  427    }
  428}
  429
  430impl gpui::Global for GlobalDiagnosticRenderer {}
  431pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  432    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  433}
  434
  435pub struct SearchWithinRange;
  436
  437trait InvalidationRegion {
  438    fn ranges(&self) -> &[Range<Anchor>];
  439}
  440
  441#[derive(Clone, Debug, PartialEq)]
  442pub enum SelectPhase {
  443    Begin {
  444        position: DisplayPoint,
  445        add: bool,
  446        click_count: usize,
  447    },
  448    BeginColumnar {
  449        position: DisplayPoint,
  450        reset: bool,
  451        mode: ColumnarMode,
  452        goal_column: u32,
  453    },
  454    Extend {
  455        position: DisplayPoint,
  456        click_count: usize,
  457    },
  458    Update {
  459        position: DisplayPoint,
  460        goal_column: u32,
  461        scroll_delta: gpui::Point<f32>,
  462    },
  463    End,
  464}
  465
  466#[derive(Clone, Debug, PartialEq)]
  467pub enum ColumnarMode {
  468    FromMouse,
  469    FromSelection,
  470}
  471
  472#[derive(Clone, Debug)]
  473pub enum SelectMode {
  474    Character,
  475    Word(Range<Anchor>),
  476    Line(Range<Anchor>),
  477    All,
  478}
  479
  480#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  481pub enum SizingBehavior {
  482    /// The editor will layout itself using `size_full` and will include the vertical
  483    /// scroll margin as requested by user settings.
  484    #[default]
  485    Default,
  486    /// The editor will layout itself using `size_full`, but will not have any
  487    /// vertical overscroll.
  488    ExcludeOverscrollMargin,
  489    /// The editor will request a vertical size according to its content and will be
  490    /// layouted without a vertical scroll margin.
  491    SizeByContent,
  492}
  493
  494#[derive(Clone, PartialEq, Eq, Debug)]
  495pub enum EditorMode {
  496    SingleLine,
  497    AutoHeight {
  498        min_lines: usize,
  499        max_lines: Option<usize>,
  500    },
  501    Full {
  502        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  503        scale_ui_elements_with_buffer_font_size: bool,
  504        /// When set to `true`, the editor will render a background for the active line.
  505        show_active_line_background: bool,
  506        /// Determines the sizing behavior for this editor
  507        sizing_behavior: SizingBehavior,
  508    },
  509    Minimap {
  510        parent: WeakEntity<Editor>,
  511    },
  512}
  513
  514impl EditorMode {
  515    pub fn full() -> Self {
  516        Self::Full {
  517            scale_ui_elements_with_buffer_font_size: true,
  518            show_active_line_background: true,
  519            sizing_behavior: SizingBehavior::Default,
  520        }
  521    }
  522
  523    #[inline]
  524    pub fn is_full(&self) -> bool {
  525        matches!(self, Self::Full { .. })
  526    }
  527
  528    #[inline]
  529    pub fn is_single_line(&self) -> bool {
  530        matches!(self, Self::SingleLine { .. })
  531    }
  532
  533    #[inline]
  534    fn is_minimap(&self) -> bool {
  535        matches!(self, Self::Minimap { .. })
  536    }
  537}
  538
  539#[derive(Copy, Clone, Debug)]
  540pub enum SoftWrap {
  541    /// Prefer not to wrap at all.
  542    ///
  543    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  544    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  545    GitDiff,
  546    /// Prefer a single line generally, unless an overly long line is encountered.
  547    None,
  548    /// Soft wrap lines that exceed the editor width.
  549    EditorWidth,
  550    /// Soft wrap lines at the preferred line length.
  551    Column(u32),
  552    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  553    Bounded(u32),
  554}
  555
  556#[derive(Clone)]
  557pub struct EditorStyle {
  558    pub background: Hsla,
  559    pub border: Hsla,
  560    pub local_player: PlayerColor,
  561    pub text: TextStyle,
  562    pub scrollbar_width: Pixels,
  563    pub syntax: Arc<SyntaxTheme>,
  564    pub status: StatusColors,
  565    pub inlay_hints_style: HighlightStyle,
  566    pub edit_prediction_styles: EditPredictionStyles,
  567    pub unnecessary_code_fade: f32,
  568    pub show_underlines: bool,
  569}
  570
  571impl Default for EditorStyle {
  572    fn default() -> Self {
  573        Self {
  574            background: Hsla::default(),
  575            border: Hsla::default(),
  576            local_player: PlayerColor::default(),
  577            text: TextStyle::default(),
  578            scrollbar_width: Pixels::default(),
  579            syntax: Default::default(),
  580            // HACK: Status colors don't have a real default.
  581            // We should look into removing the status colors from the editor
  582            // style and retrieve them directly from the theme.
  583            status: StatusColors::dark(),
  584            inlay_hints_style: HighlightStyle::default(),
  585            edit_prediction_styles: EditPredictionStyles {
  586                insertion: HighlightStyle::default(),
  587                whitespace: HighlightStyle::default(),
  588            },
  589            unnecessary_code_fade: Default::default(),
  590            show_underlines: true,
  591        }
  592    }
  593}
  594
  595pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  596    let show_background = AllLanguageSettings::get_global(cx)
  597        .defaults
  598        .inlay_hints
  599        .show_background;
  600
  601    let mut style = cx
  602        .theme()
  603        .syntax()
  604        .style_for_name("hint")
  605        .unwrap_or_default();
  606
  607    if style.color.is_none() {
  608        style.color = Some(cx.theme().status().hint);
  609    }
  610
  611    if !show_background {
  612        style.background_color = None;
  613        return style;
  614    }
  615
  616    if style.background_color.is_none() {
  617        style.background_color = Some(cx.theme().status().hint_background);
  618    }
  619
  620    style
  621}
  622
  623pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  624    EditPredictionStyles {
  625        insertion: HighlightStyle {
  626            color: Some(cx.theme().status().predictive),
  627            ..HighlightStyle::default()
  628        },
  629        whitespace: HighlightStyle {
  630            background_color: Some(cx.theme().status().created_background),
  631            ..HighlightStyle::default()
  632        },
  633    }
  634}
  635
  636type CompletionId = usize;
  637
  638pub(crate) enum EditDisplayMode {
  639    TabAccept,
  640    DiffPopover,
  641    Inline,
  642}
  643
  644enum EditPrediction {
  645    Edit {
  646        // TODO could be a language::Anchor?
  647        edits: Vec<(Range<Anchor>, Arc<str>)>,
  648        /// Predicted cursor position as (anchor, offset_from_anchor).
  649        /// The anchor is in multibuffer coordinates; after applying edits,
  650        /// resolve the anchor and add the offset to get the final cursor position.
  651        cursor_position: Option<(Anchor, usize)>,
  652        edit_preview: Option<EditPreview>,
  653        display_mode: EditDisplayMode,
  654        snapshot: BufferSnapshot,
  655    },
  656    /// Move to a specific location in the active editor
  657    MoveWithin {
  658        target: Anchor,
  659        snapshot: BufferSnapshot,
  660    },
  661    /// Move to a specific location in a different editor (not the active one)
  662    MoveOutside {
  663        target: language::Anchor,
  664        snapshot: BufferSnapshot,
  665    },
  666}
  667
  668struct EditPredictionState {
  669    inlay_ids: Vec<InlayId>,
  670    completion: EditPrediction,
  671    completion_id: Option<SharedString>,
  672    invalidation_range: Option<Range<Anchor>>,
  673}
  674
  675enum EditPredictionSettings {
  676    Disabled,
  677    Enabled {
  678        show_in_menu: bool,
  679        preview_requires_modifier: bool,
  680    },
  681}
  682
  683#[derive(Debug, Clone)]
  684struct InlineDiagnostic {
  685    message: SharedString,
  686    group_id: usize,
  687    is_primary: bool,
  688    start: Point,
  689    severity: lsp::DiagnosticSeverity,
  690}
  691
  692pub enum MenuEditPredictionsPolicy {
  693    Never,
  694    ByProvider,
  695}
  696
  697pub enum EditPredictionPreview {
  698    /// Modifier is not pressed
  699    Inactive { released_too_fast: bool },
  700    /// Modifier pressed
  701    Active {
  702        since: Instant,
  703        previous_scroll_position: Option<SharedScrollAnchor>,
  704    },
  705}
  706
  707#[derive(Copy, Clone, Eq, PartialEq)]
  708enum EditPredictionKeybindSurface {
  709    Inline,
  710    CursorPopoverCompact,
  711    CursorPopoverExpanded,
  712}
  713
  714#[derive(Copy, Clone, Eq, PartialEq, Debug)]
  715enum EditPredictionKeybindAction {
  716    Accept,
  717    Preview,
  718}
  719
  720struct EditPredictionKeybindDisplay {
  721    #[cfg(test)]
  722    accept_keystroke: Option<gpui::KeybindingKeystroke>,
  723    #[cfg(test)]
  724    preview_keystroke: Option<gpui::KeybindingKeystroke>,
  725    displayed_keystroke: Option<gpui::KeybindingKeystroke>,
  726    action: EditPredictionKeybindAction,
  727    missing_accept_keystroke: bool,
  728    show_hold_label: bool,
  729}
  730
  731impl EditPredictionPreview {
  732    pub fn released_too_fast(&self) -> bool {
  733        match self {
  734            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  735            EditPredictionPreview::Active { .. } => false,
  736        }
  737    }
  738
  739    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  740        if let EditPredictionPreview::Active {
  741            previous_scroll_position,
  742            ..
  743        } = self
  744        {
  745            *previous_scroll_position = scroll_position;
  746        }
  747    }
  748}
  749
  750pub struct ContextMenuOptions {
  751    pub min_entries_visible: usize,
  752    pub max_entries_visible: usize,
  753    pub placement: Option<ContextMenuPlacement>,
  754}
  755
  756#[derive(Debug, Clone, PartialEq, Eq)]
  757pub enum ContextMenuPlacement {
  758    Above,
  759    Below,
  760}
  761
  762#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  763struct EditorActionId(usize);
  764
  765impl EditorActionId {
  766    pub fn post_inc(&mut self) -> Self {
  767        let answer = self.0;
  768
  769        *self = Self(answer + 1);
  770
  771        Self(answer)
  772    }
  773}
  774
  775// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  776// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  777
  778type BackgroundHighlight = (
  779    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  780    Arc<[Range<Anchor>]>,
  781);
  782type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  783
  784#[derive(Default)]
  785struct ScrollbarMarkerState {
  786    scrollbar_size: Size<Pixels>,
  787    dirty: bool,
  788    markers: Arc<[PaintQuad]>,
  789    pending_refresh: Option<Task<Result<()>>>,
  790}
  791
  792impl ScrollbarMarkerState {
  793    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  794        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  795    }
  796}
  797
  798#[derive(Clone, Copy, PartialEq, Eq)]
  799pub enum MinimapVisibility {
  800    Disabled,
  801    Enabled {
  802        /// The configuration currently present in the users settings.
  803        setting_configuration: bool,
  804        /// Whether to override the currently set visibility from the users setting.
  805        toggle_override: bool,
  806    },
  807}
  808
  809impl MinimapVisibility {
  810    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  811        if mode.is_full() {
  812            Self::Enabled {
  813                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  814                toggle_override: false,
  815            }
  816        } else {
  817            Self::Disabled
  818        }
  819    }
  820
  821    fn hidden(&self) -> Self {
  822        match *self {
  823            Self::Enabled {
  824                setting_configuration,
  825                ..
  826            } => Self::Enabled {
  827                setting_configuration,
  828                toggle_override: setting_configuration,
  829            },
  830            Self::Disabled => Self::Disabled,
  831        }
  832    }
  833
  834    fn disabled(&self) -> bool {
  835        matches!(*self, Self::Disabled)
  836    }
  837
  838    fn settings_visibility(&self) -> bool {
  839        match *self {
  840            Self::Enabled {
  841                setting_configuration,
  842                ..
  843            } => setting_configuration,
  844            _ => false,
  845        }
  846    }
  847
  848    fn visible(&self) -> bool {
  849        match *self {
  850            Self::Enabled {
  851                setting_configuration,
  852                toggle_override,
  853            } => setting_configuration ^ toggle_override,
  854            _ => false,
  855        }
  856    }
  857
  858    fn toggle_visibility(&self) -> Self {
  859        match *self {
  860            Self::Enabled {
  861                toggle_override,
  862                setting_configuration,
  863            } => Self::Enabled {
  864                setting_configuration,
  865                toggle_override: !toggle_override,
  866            },
  867            Self::Disabled => Self::Disabled,
  868        }
  869    }
  870}
  871
  872#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  873pub enum BufferSerialization {
  874    All,
  875    NonDirtyBuffers,
  876}
  877
  878impl BufferSerialization {
  879    fn new(restore_unsaved_buffers: bool) -> Self {
  880        if restore_unsaved_buffers {
  881            Self::All
  882        } else {
  883            Self::NonDirtyBuffers
  884        }
  885    }
  886}
  887
  888/// Addons allow storing per-editor state in other crates (e.g. Vim)
  889pub trait Addon: 'static {
  890    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  891
  892    fn render_buffer_header_controls(
  893        &self,
  894        _: &ExcerptBoundaryInfo,
  895        _: &language::BufferSnapshot,
  896        _: &Window,
  897        _: &App,
  898    ) -> Option<AnyElement> {
  899        None
  900    }
  901
  902    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  903        None
  904    }
  905
  906    fn to_any(&self) -> &dyn std::any::Any;
  907
  908    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  909        None
  910    }
  911}
  912
  913struct ChangeLocation {
  914    current: Option<Vec<Anchor>>,
  915    original: Vec<Anchor>,
  916}
  917impl ChangeLocation {
  918    fn locations(&self) -> &[Anchor] {
  919        self.current.as_ref().unwrap_or(&self.original)
  920    }
  921}
  922
  923/// A set of caret positions, registered when the editor was edited.
  924pub struct ChangeList {
  925    changes: Vec<ChangeLocation>,
  926    /// Currently "selected" change.
  927    position: Option<usize>,
  928}
  929
  930impl ChangeList {
  931    pub fn new() -> Self {
  932        Self {
  933            changes: Vec::new(),
  934            position: None,
  935        }
  936    }
  937
  938    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  939    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  940    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  941        if self.changes.is_empty() {
  942            return None;
  943        }
  944
  945        let prev = self.position.unwrap_or(self.changes.len());
  946        let next = if direction == Direction::Prev {
  947            prev.saturating_sub(count)
  948        } else {
  949            (prev + count).min(self.changes.len() - 1)
  950        };
  951        self.position = Some(next);
  952        self.changes.get(next).map(|change| change.locations())
  953    }
  954
  955    /// Adds a new change to the list, resetting the change list position.
  956    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  957        self.position.take();
  958        if let Some(last) = self.changes.last_mut()
  959            && group
  960        {
  961            last.current = Some(new_positions)
  962        } else {
  963            self.changes.push(ChangeLocation {
  964                original: new_positions,
  965                current: None,
  966            });
  967        }
  968    }
  969
  970    pub fn last(&self) -> Option<&[Anchor]> {
  971        self.changes.last().map(|change| change.locations())
  972    }
  973
  974    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  975        self.changes.last().map(|change| change.original.as_slice())
  976    }
  977
  978    pub fn invert_last_group(&mut self) {
  979        if let Some(last) = self.changes.last_mut()
  980            && let Some(current) = last.current.as_mut()
  981        {
  982            mem::swap(&mut last.original, current);
  983        }
  984    }
  985}
  986
  987#[derive(Clone)]
  988struct InlineBlamePopoverState {
  989    scroll_handle: ScrollHandle,
  990    commit_message: Option<ParsedCommitMessage>,
  991    markdown: Entity<Markdown>,
  992}
  993
  994struct InlineBlamePopover {
  995    position: gpui::Point<Pixels>,
  996    hide_task: Option<Task<()>>,
  997    popover_bounds: Option<Bounds<Pixels>>,
  998    popover_state: InlineBlamePopoverState,
  999    keyboard_grace: bool,
 1000}
 1001
 1002enum SelectionDragState {
 1003    /// State when no drag related activity is detected.
 1004    None,
 1005    /// State when the mouse is down on a selection that is about to be dragged.
 1006    ReadyToDrag {
 1007        selection: Selection<Anchor>,
 1008        click_position: gpui::Point<Pixels>,
 1009        mouse_down_time: Instant,
 1010    },
 1011    /// State when the mouse is dragging the selection in the editor.
 1012    Dragging {
 1013        selection: Selection<Anchor>,
 1014        drop_cursor: Selection<Anchor>,
 1015        hide_drop_cursor: bool,
 1016    },
 1017}
 1018
 1019enum ColumnarSelectionState {
 1020    FromMouse {
 1021        selection_tail: Anchor,
 1022        display_point: Option<DisplayPoint>,
 1023    },
 1024    FromSelection {
 1025        selection_tail: Anchor,
 1026    },
 1027}
 1028
 1029/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1030/// a breakpoint on them.
 1031#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1032struct PhantomBreakpointIndicator {
 1033    display_row: DisplayRow,
 1034    /// There's a small debounce between hovering over the line and showing the indicator.
 1035    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1036    is_active: bool,
 1037    collides_with_existing_breakpoint: bool,
 1038}
 1039
 1040/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1041/// in diff view mode.
 1042#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1043pub(crate) struct PhantomDiffReviewIndicator {
 1044    /// The starting anchor of the selection (or the only row if not dragging).
 1045    pub start: Anchor,
 1046    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1047    pub end: Anchor,
 1048    /// There's a small debounce between hovering over the line and showing the indicator.
 1049    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1050    pub is_active: bool,
 1051}
 1052
 1053#[derive(Clone, Debug)]
 1054pub(crate) struct DiffReviewDragState {
 1055    pub start_anchor: Anchor,
 1056    pub current_anchor: Anchor,
 1057}
 1058
 1059impl DiffReviewDragState {
 1060    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1061        let start = self.start_anchor.to_display_point(snapshot).row();
 1062        let current = self.current_anchor.to_display_point(snapshot).row();
 1063
 1064        (start..=current).sorted()
 1065    }
 1066}
 1067
 1068/// Identifies a specific hunk in the diff buffer.
 1069/// Used as a key to group comments by their location.
 1070#[derive(Clone, Debug)]
 1071pub struct DiffHunkKey {
 1072    /// The file path (relative to worktree) this hunk belongs to.
 1073    pub file_path: Arc<util::rel_path::RelPath>,
 1074    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1075    pub hunk_start_anchor: Anchor,
 1076}
 1077
 1078/// A review comment stored locally before being sent to the Agent panel.
 1079#[derive(Clone)]
 1080pub struct StoredReviewComment {
 1081    /// Unique identifier for this comment (for edit/delete operations).
 1082    pub id: usize,
 1083    /// The comment text entered by the user.
 1084    pub comment: String,
 1085    /// Anchors for the code range being reviewed.
 1086    pub range: Range<Anchor>,
 1087    /// Timestamp when the comment was created (for chronological ordering).
 1088    pub created_at: Instant,
 1089    /// Whether this comment is currently being edited inline.
 1090    pub is_editing: bool,
 1091}
 1092
 1093impl StoredReviewComment {
 1094    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1095        Self {
 1096            id,
 1097            comment,
 1098            range: anchor_range,
 1099            created_at: Instant::now(),
 1100            is_editing: false,
 1101        }
 1102    }
 1103}
 1104
 1105/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1106pub(crate) struct DiffReviewOverlay {
 1107    pub anchor_range: Range<Anchor>,
 1108    /// The block ID for the overlay.
 1109    pub block_id: CustomBlockId,
 1110    /// The editor entity for the review input.
 1111    pub prompt_editor: Entity<Editor>,
 1112    /// The hunk key this overlay belongs to.
 1113    pub hunk_key: DiffHunkKey,
 1114    /// Whether the comments section is expanded.
 1115    pub comments_expanded: bool,
 1116    /// Editors for comments currently being edited inline.
 1117    /// Key: comment ID, Value: Editor entity for inline editing.
 1118    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1119    /// Subscriptions for inline edit editors' action handlers.
 1120    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1121    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1122    /// The current user's avatar URI for display in comment rows.
 1123    pub user_avatar_uri: Option<SharedUri>,
 1124    /// Subscription to keep the action handler alive.
 1125    _subscription: Subscription,
 1126}
 1127
 1128/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1129///
 1130/// See the [module level documentation](self) for more information.
 1131pub struct Editor {
 1132    focus_handle: FocusHandle,
 1133    last_focused_descendant: Option<WeakFocusHandle>,
 1134    /// The text buffer being edited
 1135    buffer: Entity<MultiBuffer>,
 1136    /// Map of how text in the buffer should be displayed.
 1137    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1138    pub display_map: Entity<DisplayMap>,
 1139    placeholder_display_map: Option<Entity<DisplayMap>>,
 1140    pub selections: SelectionsCollection,
 1141    pub scroll_manager: ScrollManager,
 1142    /// When inline assist editors are linked, they all render cursors because
 1143    /// typing enters text into each of them, even the ones that aren't focused.
 1144    pub(crate) show_cursor_when_unfocused: bool,
 1145    columnar_selection_state: Option<ColumnarSelectionState>,
 1146    add_selections_state: Option<AddSelectionsState>,
 1147    select_next_state: Option<SelectNextState>,
 1148    select_prev_state: Option<SelectNextState>,
 1149    selection_history: SelectionHistory,
 1150    defer_selection_effects: bool,
 1151    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1152    autoclose_regions: Vec<AutocloseRegion>,
 1153    snippet_stack: InvalidationStack<SnippetState>,
 1154    select_syntax_node_history: SelectSyntaxNodeHistory,
 1155    ime_transaction: Option<TransactionId>,
 1156    pub diagnostics_max_severity: DiagnosticSeverity,
 1157    active_diagnostics: ActiveDiagnostic,
 1158    show_inline_diagnostics: bool,
 1159    inline_diagnostics_update: Task<()>,
 1160    inline_diagnostics_enabled: bool,
 1161    diagnostics_enabled: bool,
 1162    word_completions_enabled: bool,
 1163    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1164    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1165    hard_wrap: Option<usize>,
 1166    project: Option<Entity<Project>>,
 1167    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1168    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1169    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1170    blink_manager: Entity<BlinkManager>,
 1171    show_cursor_names: bool,
 1172    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1173    pub show_local_selections: bool,
 1174    mode: EditorMode,
 1175    show_breadcrumbs: bool,
 1176    show_gutter: bool,
 1177    show_scrollbars: ScrollbarAxes,
 1178    minimap_visibility: MinimapVisibility,
 1179    offset_content: bool,
 1180    disable_expand_excerpt_buttons: bool,
 1181    delegate_expand_excerpts: bool,
 1182    delegate_stage_and_restore: bool,
 1183    delegate_open_excerpts: bool,
 1184    enable_lsp_data: bool,
 1185    enable_runnables: bool,
 1186    enable_mouse_wheel_zoom: bool,
 1187    show_line_numbers: Option<bool>,
 1188    use_relative_line_numbers: Option<bool>,
 1189    show_git_diff_gutter: Option<bool>,
 1190    show_code_actions: Option<bool>,
 1191    show_runnables: Option<bool>,
 1192    show_breakpoints: Option<bool>,
 1193    show_diff_review_button: bool,
 1194    show_wrap_guides: Option<bool>,
 1195    show_indent_guides: Option<bool>,
 1196    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1197    highlight_order: usize,
 1198    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1199    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1200    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1201    scrollbar_marker_state: ScrollbarMarkerState,
 1202    active_indent_guides_state: ActiveIndentGuidesState,
 1203    nav_history: Option<ItemNavHistory>,
 1204    context_menu: RefCell<Option<CodeContextMenu>>,
 1205    context_menu_options: Option<ContextMenuOptions>,
 1206    mouse_context_menu: Option<MouseContextMenu>,
 1207    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1208    inline_blame_popover: Option<InlineBlamePopover>,
 1209    inline_blame_popover_show_task: Option<Task<()>>,
 1210    signature_help_state: SignatureHelpState,
 1211    auto_signature_help: Option<bool>,
 1212    find_all_references_task_sources: Vec<Anchor>,
 1213    next_completion_id: CompletionId,
 1214    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1215    code_actions_task: Option<Task<Result<()>>>,
 1216    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1217    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1218    debounced_selection_highlight_complete: bool,
 1219    document_highlights_task: Option<Task<()>>,
 1220    linked_editing_range_task: Option<Task<Option<()>>>,
 1221    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1222    pending_rename: Option<RenameState>,
 1223    searchable: bool,
 1224    cursor_shape: CursorShape,
 1225    /// Whether the cursor is offset one character to the left when something is
 1226    /// selected (needed for vim visual mode)
 1227    cursor_offset_on_selection: bool,
 1228    current_line_highlight: Option<CurrentLineHighlight>,
 1229    /// Whether to collapse search match ranges to just their start position.
 1230    /// When true, navigating to a match positions the cursor at the match
 1231    /// without selecting the matched text.
 1232    collapse_matches: bool,
 1233    autoindent_mode: Option<AutoindentMode>,
 1234    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1235    input_enabled: bool,
 1236    expects_character_input: bool,
 1237    use_modal_editing: bool,
 1238    read_only: bool,
 1239    leader_id: Option<CollaboratorId>,
 1240    remote_id: Option<ViewId>,
 1241    pub hover_state: HoverState,
 1242    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1243    prev_pressure_stage: Option<PressureStage>,
 1244    gutter_hovered: bool,
 1245    hovered_link_state: Option<HoveredLinkState>,
 1246    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1247    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1248    active_edit_prediction: Option<EditPredictionState>,
 1249    /// Used to prevent flickering as the user types while the menu is open
 1250    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1251    edit_prediction_settings: EditPredictionSettings,
 1252    edit_predictions_hidden_for_vim_mode: bool,
 1253    show_edit_predictions_override: Option<bool>,
 1254    show_completions_on_input_override: Option<bool>,
 1255    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1256    edit_prediction_preview: EditPredictionPreview,
 1257    in_leading_whitespace: bool,
 1258    next_inlay_id: usize,
 1259    next_color_inlay_id: usize,
 1260    _subscriptions: Vec<Subscription>,
 1261    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1262    gutter_dimensions: GutterDimensions,
 1263    style: Option<EditorStyle>,
 1264    text_style_refinement: Option<TextStyleRefinement>,
 1265    next_editor_action_id: EditorActionId,
 1266    editor_actions: Rc<
 1267        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1268    >,
 1269    use_autoclose: bool,
 1270    use_auto_surround: bool,
 1271    use_selection_highlight: bool,
 1272    auto_replace_emoji_shortcode: bool,
 1273    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1274    show_git_blame_gutter: bool,
 1275    show_git_blame_inline: bool,
 1276    show_git_blame_inline_delay_task: Option<Task<()>>,
 1277    git_blame_inline_enabled: bool,
 1278    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1279    buffer_serialization: Option<BufferSerialization>,
 1280    show_selection_menu: Option<bool>,
 1281    blame: Option<Entity<GitBlame>>,
 1282    blame_subscription: Option<Subscription>,
 1283    custom_context_menu: Option<
 1284        Box<
 1285            dyn 'static
 1286                + Fn(
 1287                    &mut Self,
 1288                    DisplayPoint,
 1289                    &mut Window,
 1290                    &mut Context<Self>,
 1291                ) -> Option<Entity<ui::ContextMenu>>,
 1292        >,
 1293    >,
 1294    last_bounds: Option<Bounds<Pixels>>,
 1295    last_position_map: Option<Rc<PositionMap>>,
 1296    expect_bounds_change: Option<Bounds<Pixels>>,
 1297    runnables: RunnableData,
 1298    breakpoint_store: Option<Entity<BreakpointStore>>,
 1299    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1300    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1301    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1302    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1303    /// when hunks have comments stored.
 1304    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1305    /// Stored review comments grouped by hunk.
 1306    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1307    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1308    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1309    /// Counter for generating unique comment IDs.
 1310    next_review_comment_id: usize,
 1311    hovered_diff_hunk_row: Option<DisplayRow>,
 1312    pull_diagnostics_task: Task<()>,
 1313    in_project_search: bool,
 1314    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1315    breadcrumb_header: Option<String>,
 1316    focused_block: Option<FocusedBlock>,
 1317    next_scroll_position: NextScrollCursorCenterTopBottom,
 1318    addons: HashMap<TypeId, Box<dyn Addon>>,
 1319    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1320    load_diff_task: Option<Shared<Task<()>>>,
 1321    /// Whether we are temporarily displaying a diff other than git's
 1322    temporary_diff_override: bool,
 1323    selection_mark_mode: bool,
 1324    toggle_fold_multiple_buffers: Task<()>,
 1325    _scroll_cursor_center_top_bottom_task: Task<()>,
 1326    serialize_selections: Task<()>,
 1327    serialize_folds: Task<()>,
 1328    mouse_cursor_hidden: bool,
 1329    minimap: Option<Entity<Self>>,
 1330    hide_mouse_mode: HideMouseMode,
 1331    pub change_list: ChangeList,
 1332    inline_value_cache: InlineValueCache,
 1333    number_deleted_lines: bool,
 1334
 1335    selection_drag_state: SelectionDragState,
 1336    colors: Option<LspColorData>,
 1337    post_scroll_update: Task<()>,
 1338    refresh_colors_task: Task<()>,
 1339    use_document_folding_ranges: bool,
 1340    refresh_folding_ranges_task: Task<()>,
 1341    inlay_hints: Option<LspInlayHintData>,
 1342    folding_newlines: Task<()>,
 1343    select_next_is_case_sensitive: Option<bool>,
 1344    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1345    on_local_selections_changed:
 1346        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1347    suppress_selection_callback: bool,
 1348    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1349    accent_data: Option<AccentData>,
 1350    bracket_fetched_tree_sitter_chunks: HashMap<Range<text::Anchor>, HashSet<Range<BufferRow>>>,
 1351    semantic_token_state: SemanticTokenState,
 1352    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1353    refresh_document_symbols_task: Shared<Task<()>>,
 1354    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1355    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1356    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1357    sticky_headers_task: Task<()>,
 1358    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1359    pub(crate) colorize_brackets_task: Task<()>,
 1360}
 1361
 1362#[derive(Debug, PartialEq)]
 1363struct AccentData {
 1364    colors: AccentColors,
 1365    overrides: Vec<SharedString>,
 1366}
 1367
 1368fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1369    if debounce_ms > 0 {
 1370        Some(Duration::from_millis(debounce_ms))
 1371    } else {
 1372        None
 1373    }
 1374}
 1375
 1376#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1377enum NextScrollCursorCenterTopBottom {
 1378    #[default]
 1379    Center,
 1380    Top,
 1381    Bottom,
 1382}
 1383
 1384impl NextScrollCursorCenterTopBottom {
 1385    fn next(&self) -> Self {
 1386        match self {
 1387            Self::Center => Self::Top,
 1388            Self::Top => Self::Bottom,
 1389            Self::Bottom => Self::Center,
 1390        }
 1391    }
 1392}
 1393
 1394#[derive(Clone)]
 1395pub struct EditorSnapshot {
 1396    pub mode: EditorMode,
 1397    show_gutter: bool,
 1398    offset_content: bool,
 1399    show_line_numbers: Option<bool>,
 1400    number_deleted_lines: bool,
 1401    show_git_diff_gutter: Option<bool>,
 1402    show_code_actions: Option<bool>,
 1403    show_runnables: Option<bool>,
 1404    show_breakpoints: Option<bool>,
 1405    git_blame_gutter_max_author_length: Option<usize>,
 1406    pub display_snapshot: DisplaySnapshot,
 1407    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1408    is_focused: bool,
 1409    scroll_anchor: SharedScrollAnchor,
 1410    ongoing_scroll: OngoingScroll,
 1411    current_line_highlight: CurrentLineHighlight,
 1412    gutter_hovered: bool,
 1413    semantic_tokens_enabled: bool,
 1414}
 1415
 1416#[derive(Default, Debug, Clone, Copy)]
 1417pub struct GutterDimensions {
 1418    pub left_padding: Pixels,
 1419    pub right_padding: Pixels,
 1420    pub width: Pixels,
 1421    pub margin: Pixels,
 1422    pub git_blame_entries_width: Option<Pixels>,
 1423}
 1424
 1425impl GutterDimensions {
 1426    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1427        Self {
 1428            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1429            ..Default::default()
 1430        }
 1431    }
 1432
 1433    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1434        -cx.text_system().descent(font_id, font_size)
 1435    }
 1436    /// The full width of the space taken up by the gutter.
 1437    pub fn full_width(&self) -> Pixels {
 1438        self.margin + self.width
 1439    }
 1440
 1441    /// The width of the space reserved for the fold indicators,
 1442    /// use alongside 'justify_end' and `gutter_width` to
 1443    /// right align content with the line numbers
 1444    pub fn fold_area_width(&self) -> Pixels {
 1445        self.margin + self.right_padding
 1446    }
 1447}
 1448
 1449struct CharacterDimensions {
 1450    em_width: Pixels,
 1451    em_advance: Pixels,
 1452    line_height: Pixels,
 1453}
 1454
 1455#[derive(Debug)]
 1456pub struct RemoteSelection {
 1457    pub replica_id: ReplicaId,
 1458    pub selection: Selection<Anchor>,
 1459    pub cursor_shape: CursorShape,
 1460    pub collaborator_id: CollaboratorId,
 1461    pub line_mode: bool,
 1462    pub user_name: Option<SharedString>,
 1463    pub color: PlayerColor,
 1464}
 1465
 1466#[derive(Clone, Debug)]
 1467struct SelectionHistoryEntry {
 1468    selections: Arc<[Selection<Anchor>]>,
 1469    select_next_state: Option<SelectNextState>,
 1470    select_prev_state: Option<SelectNextState>,
 1471    add_selections_state: Option<AddSelectionsState>,
 1472}
 1473
 1474#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1475enum SelectionHistoryMode {
 1476    #[default]
 1477    Normal,
 1478    Undoing,
 1479    Redoing,
 1480    Skipping,
 1481}
 1482
 1483#[derive(Clone, PartialEq, Eq, Hash)]
 1484struct HoveredCursor {
 1485    replica_id: ReplicaId,
 1486    selection_id: usize,
 1487}
 1488
 1489#[derive(Debug)]
 1490/// SelectionEffects controls the side-effects of updating the selection.
 1491///
 1492/// The default behaviour does "what you mostly want":
 1493/// - it pushes to the nav history if the cursor moved by >10 lines
 1494/// - it re-triggers completion requests
 1495/// - it scrolls to fit
 1496///
 1497/// You might want to modify these behaviours. For example when doing a "jump"
 1498/// like go to definition, we always want to add to nav history; but when scrolling
 1499/// in vim mode we never do.
 1500///
 1501/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1502/// move.
 1503#[derive(Clone)]
 1504pub struct SelectionEffects {
 1505    nav_history: Option<bool>,
 1506    completions: bool,
 1507    scroll: Option<Autoscroll>,
 1508}
 1509
 1510impl Default for SelectionEffects {
 1511    fn default() -> Self {
 1512        Self {
 1513            nav_history: None,
 1514            completions: true,
 1515            scroll: Some(Autoscroll::fit()),
 1516        }
 1517    }
 1518}
 1519impl SelectionEffects {
 1520    pub fn scroll(scroll: Autoscroll) -> Self {
 1521        Self {
 1522            scroll: Some(scroll),
 1523            ..Default::default()
 1524        }
 1525    }
 1526
 1527    pub fn no_scroll() -> Self {
 1528        Self {
 1529            scroll: None,
 1530            ..Default::default()
 1531        }
 1532    }
 1533
 1534    pub fn completions(self, completions: bool) -> Self {
 1535        Self {
 1536            completions,
 1537            ..self
 1538        }
 1539    }
 1540
 1541    pub fn nav_history(self, nav_history: bool) -> Self {
 1542        Self {
 1543            nav_history: Some(nav_history),
 1544            ..self
 1545        }
 1546    }
 1547}
 1548
 1549struct DeferredSelectionEffectsState {
 1550    changed: bool,
 1551    effects: SelectionEffects,
 1552    old_cursor_position: Anchor,
 1553    history_entry: SelectionHistoryEntry,
 1554}
 1555
 1556#[derive(Default)]
 1557struct SelectionHistory {
 1558    #[allow(clippy::type_complexity)]
 1559    selections_by_transaction:
 1560        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1561    mode: SelectionHistoryMode,
 1562    undo_stack: VecDeque<SelectionHistoryEntry>,
 1563    redo_stack: VecDeque<SelectionHistoryEntry>,
 1564}
 1565
 1566impl SelectionHistory {
 1567    #[track_caller]
 1568    fn insert_transaction(
 1569        &mut self,
 1570        transaction_id: TransactionId,
 1571        selections: Arc<[Selection<Anchor>]>,
 1572    ) {
 1573        if selections.is_empty() {
 1574            log::error!(
 1575                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1576                std::panic::Location::caller()
 1577            );
 1578            return;
 1579        }
 1580        self.selections_by_transaction
 1581            .insert(transaction_id, (selections, None));
 1582    }
 1583
 1584    #[allow(clippy::type_complexity)]
 1585    fn transaction(
 1586        &self,
 1587        transaction_id: TransactionId,
 1588    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1589        self.selections_by_transaction.get(&transaction_id)
 1590    }
 1591
 1592    #[allow(clippy::type_complexity)]
 1593    fn transaction_mut(
 1594        &mut self,
 1595        transaction_id: TransactionId,
 1596    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1597        self.selections_by_transaction.get_mut(&transaction_id)
 1598    }
 1599
 1600    fn push(&mut self, entry: SelectionHistoryEntry) {
 1601        if !entry.selections.is_empty() {
 1602            match self.mode {
 1603                SelectionHistoryMode::Normal => {
 1604                    self.push_undo(entry);
 1605                    self.redo_stack.clear();
 1606                }
 1607                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1608                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1609                SelectionHistoryMode::Skipping => {}
 1610            }
 1611        }
 1612    }
 1613
 1614    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1615        if self
 1616            .undo_stack
 1617            .back()
 1618            .is_none_or(|e| e.selections != entry.selections)
 1619        {
 1620            self.undo_stack.push_back(entry);
 1621            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1622                self.undo_stack.pop_front();
 1623            }
 1624        }
 1625    }
 1626
 1627    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1628        if self
 1629            .redo_stack
 1630            .back()
 1631            .is_none_or(|e| e.selections != entry.selections)
 1632        {
 1633            self.redo_stack.push_back(entry);
 1634            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1635                self.redo_stack.pop_front();
 1636            }
 1637        }
 1638    }
 1639}
 1640
 1641#[derive(Clone, Copy)]
 1642pub struct RowHighlightOptions {
 1643    pub autoscroll: bool,
 1644    pub include_gutter: bool,
 1645}
 1646
 1647impl Default for RowHighlightOptions {
 1648    fn default() -> Self {
 1649        Self {
 1650            autoscroll: Default::default(),
 1651            include_gutter: true,
 1652        }
 1653    }
 1654}
 1655
 1656struct RowHighlight {
 1657    index: usize,
 1658    range: Range<Anchor>,
 1659    color: Hsla,
 1660    options: RowHighlightOptions,
 1661    type_id: TypeId,
 1662}
 1663
 1664#[derive(Clone, Debug)]
 1665struct AddSelectionsState {
 1666    groups: Vec<AddSelectionsGroup>,
 1667}
 1668
 1669#[derive(Clone, Debug)]
 1670struct AddSelectionsGroup {
 1671    above: bool,
 1672    stack: Vec<usize>,
 1673}
 1674
 1675#[derive(Clone)]
 1676struct SelectNextState {
 1677    query: AhoCorasick,
 1678    wordwise: bool,
 1679    done: bool,
 1680}
 1681
 1682impl std::fmt::Debug for SelectNextState {
 1683    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1684        f.debug_struct(std::any::type_name::<Self>())
 1685            .field("wordwise", &self.wordwise)
 1686            .field("done", &self.done)
 1687            .finish()
 1688    }
 1689}
 1690
 1691#[derive(Debug)]
 1692struct AutocloseRegion {
 1693    selection_id: usize,
 1694    range: Range<Anchor>,
 1695    pair: BracketPair,
 1696}
 1697
 1698#[derive(Debug)]
 1699struct SnippetState {
 1700    ranges: Vec<Vec<Range<Anchor>>>,
 1701    active_index: usize,
 1702    choices: Vec<Option<Vec<String>>>,
 1703}
 1704
 1705#[doc(hidden)]
 1706pub struct RenameState {
 1707    pub range: Range<Anchor>,
 1708    pub old_name: Arc<str>,
 1709    pub editor: Entity<Editor>,
 1710    block_id: CustomBlockId,
 1711}
 1712
 1713struct InvalidationStack<T>(Vec<T>);
 1714
 1715struct RegisteredEditPredictionDelegate {
 1716    provider: Arc<dyn EditPredictionDelegateHandle>,
 1717    _subscription: Subscription,
 1718}
 1719
 1720#[derive(Debug, PartialEq, Eq)]
 1721pub struct ActiveDiagnosticGroup {
 1722    pub active_range: Range<Anchor>,
 1723    pub active_message: String,
 1724    pub group_id: usize,
 1725    pub blocks: HashSet<CustomBlockId>,
 1726}
 1727
 1728#[derive(Debug, PartialEq, Eq)]
 1729
 1730pub(crate) enum ActiveDiagnostic {
 1731    None,
 1732    All,
 1733    Group(ActiveDiagnosticGroup),
 1734}
 1735
 1736#[derive(Serialize, Deserialize, Clone, Debug)]
 1737pub struct ClipboardSelection {
 1738    /// The number of bytes in this selection.
 1739    pub len: usize,
 1740    /// Whether this was a full-line selection.
 1741    pub is_entire_line: bool,
 1742    /// The indentation of the first line when this content was originally copied.
 1743    pub first_line_indent: u32,
 1744    #[serde(default)]
 1745    pub file_path: Option<PathBuf>,
 1746    #[serde(default)]
 1747    pub line_range: Option<RangeInclusive<u32>>,
 1748}
 1749
 1750impl ClipboardSelection {
 1751    pub fn for_buffer(
 1752        len: usize,
 1753        is_entire_line: bool,
 1754        range: Range<Point>,
 1755        buffer: &MultiBufferSnapshot,
 1756        project: Option<&Entity<Project>>,
 1757        cx: &App,
 1758    ) -> Self {
 1759        let first_line_indent = buffer
 1760            .indent_size_for_line(MultiBufferRow(range.start.row))
 1761            .len;
 1762
 1763        let file_path = util::maybe!({
 1764            let project = project?.read(cx);
 1765            let file = buffer.file_at(range.start)?;
 1766            let project_path = ProjectPath {
 1767                worktree_id: file.worktree_id(cx),
 1768                path: file.path().clone(),
 1769            };
 1770            project.absolute_path(&project_path, cx)
 1771        });
 1772
 1773        let line_range = if file_path.is_some() {
 1774            buffer
 1775                .range_to_buffer_range(range)
 1776                .map(|(_, buffer_range)| buffer_range.start.row..=buffer_range.end.row)
 1777        } else {
 1778            None
 1779        };
 1780
 1781        Self {
 1782            len,
 1783            is_entire_line,
 1784            first_line_indent,
 1785            file_path,
 1786            line_range,
 1787        }
 1788    }
 1789}
 1790
 1791// selections, scroll behavior, was newest selection reversed
 1792type SelectSyntaxNodeHistoryState = (
 1793    Box<[Selection<Anchor>]>,
 1794    SelectSyntaxNodeScrollBehavior,
 1795    bool,
 1796);
 1797
 1798#[derive(Default)]
 1799struct SelectSyntaxNodeHistory {
 1800    stack: Vec<SelectSyntaxNodeHistoryState>,
 1801    // disable temporarily to allow changing selections without losing the stack
 1802    pub disable_clearing: bool,
 1803}
 1804
 1805impl SelectSyntaxNodeHistory {
 1806    pub fn try_clear(&mut self) {
 1807        if !self.disable_clearing {
 1808            self.stack.clear();
 1809        }
 1810    }
 1811
 1812    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1813        self.stack.push(selection);
 1814    }
 1815
 1816    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1817        self.stack.pop()
 1818    }
 1819}
 1820
 1821enum SelectSyntaxNodeScrollBehavior {
 1822    CursorTop,
 1823    FitSelection,
 1824    CursorBottom,
 1825}
 1826
 1827#[derive(Debug, Clone, Copy)]
 1828pub(crate) struct NavigationData {
 1829    cursor_anchor: Anchor,
 1830    cursor_position: Point,
 1831    scroll_anchor: ScrollAnchor,
 1832    scroll_top_row: u32,
 1833}
 1834
 1835#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1836pub enum GotoDefinitionKind {
 1837    Symbol,
 1838    Declaration,
 1839    Type,
 1840    Implementation,
 1841}
 1842
 1843pub enum FormatTarget {
 1844    Buffers(HashSet<Entity<Buffer>>),
 1845    Ranges(Vec<Range<MultiBufferPoint>>),
 1846}
 1847
 1848pub(crate) struct FocusedBlock {
 1849    id: BlockId,
 1850    focus_handle: WeakFocusHandle,
 1851}
 1852
 1853#[derive(Clone, Debug)]
 1854pub enum JumpData {
 1855    MultiBufferRow {
 1856        row: MultiBufferRow,
 1857        line_offset_from_top: u32,
 1858    },
 1859    MultiBufferPoint {
 1860        anchor: language::Anchor,
 1861        position: Point,
 1862        line_offset_from_top: u32,
 1863    },
 1864}
 1865
 1866pub enum MultibufferSelectionMode {
 1867    First,
 1868    All,
 1869}
 1870
 1871#[derive(Clone, Copy, Debug, Default)]
 1872pub struct RewrapOptions {
 1873    pub override_language_settings: bool,
 1874    pub preserve_existing_whitespace: bool,
 1875    pub line_length: Option<usize>,
 1876}
 1877
 1878impl Editor {
 1879    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1880        let buffer = cx.new(|cx| Buffer::local("", cx));
 1881        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1882        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1883    }
 1884
 1885    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1886        let buffer = cx.new(|cx| Buffer::local("", cx));
 1887        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1888        Self::new(EditorMode::full(), buffer, None, window, cx)
 1889    }
 1890
 1891    pub fn auto_height(
 1892        min_lines: usize,
 1893        max_lines: usize,
 1894        window: &mut Window,
 1895        cx: &mut Context<Self>,
 1896    ) -> Self {
 1897        let buffer = cx.new(|cx| Buffer::local("", cx));
 1898        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1899        Self::new(
 1900            EditorMode::AutoHeight {
 1901                min_lines,
 1902                max_lines: Some(max_lines),
 1903            },
 1904            buffer,
 1905            None,
 1906            window,
 1907            cx,
 1908        )
 1909    }
 1910
 1911    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1912    /// The editor grows as tall as needed to fit its content.
 1913    pub fn auto_height_unbounded(
 1914        min_lines: usize,
 1915        window: &mut Window,
 1916        cx: &mut Context<Self>,
 1917    ) -> Self {
 1918        let buffer = cx.new(|cx| Buffer::local("", cx));
 1919        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1920        Self::new(
 1921            EditorMode::AutoHeight {
 1922                min_lines,
 1923                max_lines: None,
 1924            },
 1925            buffer,
 1926            None,
 1927            window,
 1928            cx,
 1929        )
 1930    }
 1931
 1932    pub fn for_buffer(
 1933        buffer: Entity<Buffer>,
 1934        project: Option<Entity<Project>>,
 1935        window: &mut Window,
 1936        cx: &mut Context<Self>,
 1937    ) -> Self {
 1938        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1939        Self::new(EditorMode::full(), buffer, project, window, cx)
 1940    }
 1941
 1942    pub fn for_multibuffer(
 1943        buffer: Entity<MultiBuffer>,
 1944        project: Option<Entity<Project>>,
 1945        window: &mut Window,
 1946        cx: &mut Context<Self>,
 1947    ) -> Self {
 1948        Self::new(EditorMode::full(), buffer, project, window, cx)
 1949    }
 1950
 1951    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1952        let mut clone = Self::new(
 1953            self.mode.clone(),
 1954            self.buffer.clone(),
 1955            self.project.clone(),
 1956            window,
 1957            cx,
 1958        );
 1959        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1960            let snapshot = display_map.snapshot(cx);
 1961            clone.display_map.update(cx, |display_map, cx| {
 1962                display_map.set_state(&snapshot, cx);
 1963            });
 1964            snapshot
 1965        });
 1966        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1967        clone.folds_did_change(cx);
 1968        clone.selections.clone_state(&self.selections);
 1969        clone
 1970            .scroll_manager
 1971            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1972        clone.searchable = self.searchable;
 1973        clone.read_only = self.read_only;
 1974        clone.buffers_with_disabled_indent_guides =
 1975            self.buffers_with_disabled_indent_guides.clone();
 1976        clone.enable_mouse_wheel_zoom = self.enable_mouse_wheel_zoom;
 1977        clone.enable_lsp_data = self.enable_lsp_data;
 1978        clone.enable_runnables = self.enable_runnables;
 1979        clone
 1980    }
 1981
 1982    pub fn new(
 1983        mode: EditorMode,
 1984        buffer: Entity<MultiBuffer>,
 1985        project: Option<Entity<Project>>,
 1986        window: &mut Window,
 1987        cx: &mut Context<Self>,
 1988    ) -> Self {
 1989        Editor::new_internal(mode, buffer, project, None, window, cx)
 1990    }
 1991
 1992    pub fn refresh_sticky_headers(
 1993        &mut self,
 1994        display_snapshot: &DisplaySnapshot,
 1995        cx: &mut Context<Editor>,
 1996    ) {
 1997        if !self.mode.is_full() {
 1998            return;
 1999        }
 2000        let multi_buffer = display_snapshot.buffer_snapshot().clone();
 2001        let scroll_anchor = self
 2002            .scroll_manager
 2003            .native_anchor(display_snapshot, cx)
 2004            .anchor;
 2005        let Some(buffer_snapshot) = multi_buffer.as_singleton() else {
 2006            return;
 2007        };
 2008
 2009        let buffer = buffer_snapshot.clone();
 2010        let Some((buffer_visible_start, _)) = multi_buffer.anchor_to_buffer_anchor(scroll_anchor)
 2011        else {
 2012            return;
 2013        };
 2014        let buffer_visible_start = buffer_visible_start.to_point(&buffer);
 2015        let max_row = buffer.max_point().row;
 2016        let start_row = buffer_visible_start.row.min(max_row);
 2017        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2018
 2019        let syntax = self.style(cx).syntax.clone();
 2020        let background_task = cx.background_spawn(async move {
 2021            buffer
 2022                .outline_items_containing(
 2023                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2024                    true,
 2025                    Some(syntax.as_ref()),
 2026                )
 2027                .into_iter()
 2028                .filter_map(|outline_item| {
 2029                    Some(OutlineItem {
 2030                        depth: outline_item.depth,
 2031                        range: multi_buffer
 2032                            .buffer_anchor_range_to_anchor_range(outline_item.range)?,
 2033                        source_range_for_text: multi_buffer.buffer_anchor_range_to_anchor_range(
 2034                            outline_item.source_range_for_text,
 2035                        )?,
 2036                        text: outline_item.text,
 2037                        highlight_ranges: outline_item.highlight_ranges,
 2038                        name_ranges: outline_item.name_ranges,
 2039                        body_range: outline_item.body_range.and_then(|range| {
 2040                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2041                        }),
 2042                        annotation_range: outline_item.annotation_range.and_then(|range| {
 2043                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2044                        }),
 2045                    })
 2046                })
 2047                .collect()
 2048        });
 2049        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2050            let sticky_headers = background_task.await;
 2051            this.update(cx, |this, cx| {
 2052                this.sticky_headers = Some(sticky_headers);
 2053                cx.notify();
 2054            })
 2055            .ok();
 2056        });
 2057    }
 2058
 2059    fn new_internal(
 2060        mode: EditorMode,
 2061        multi_buffer: Entity<MultiBuffer>,
 2062        project: Option<Entity<Project>>,
 2063        display_map: Option<Entity<DisplayMap>>,
 2064        window: &mut Window,
 2065        cx: &mut Context<Self>,
 2066    ) -> Self {
 2067        debug_assert!(
 2068            display_map.is_none() || mode.is_minimap(),
 2069            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2070        );
 2071
 2072        let full_mode = mode.is_full();
 2073        let is_minimap = mode.is_minimap();
 2074        let diagnostics_max_severity = if full_mode {
 2075            EditorSettings::get_global(cx)
 2076                .diagnostics_max_severity
 2077                .unwrap_or(DiagnosticSeverity::Hint)
 2078        } else {
 2079            DiagnosticSeverity::Off
 2080        };
 2081        let style = window.text_style();
 2082        let font_size = style.font_size.to_pixels(window.rem_size());
 2083        let editor = cx.entity().downgrade();
 2084        let fold_placeholder = FoldPlaceholder {
 2085            constrain_width: false,
 2086            render: Arc::new(move |fold_id, fold_range, cx| {
 2087                let editor = editor.clone();
 2088                FoldPlaceholder::fold_element(fold_id, cx)
 2089                    .cursor_pointer()
 2090                    .child("")
 2091                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2092                    .on_click(move |_, _window, cx| {
 2093                        editor
 2094                            .update(cx, |editor, cx| {
 2095                                editor.unfold_ranges(
 2096                                    &[fold_range.start..fold_range.end],
 2097                                    true,
 2098                                    false,
 2099                                    cx,
 2100                                );
 2101                                cx.stop_propagation();
 2102                            })
 2103                            .ok();
 2104                    })
 2105                    .into_any()
 2106            }),
 2107            merge_adjacent: true,
 2108            ..FoldPlaceholder::default()
 2109        };
 2110        let display_map = display_map.unwrap_or_else(|| {
 2111            cx.new(|cx| {
 2112                DisplayMap::new(
 2113                    multi_buffer.clone(),
 2114                    style.font(),
 2115                    font_size,
 2116                    None,
 2117                    FILE_HEADER_HEIGHT,
 2118                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2119                    fold_placeholder,
 2120                    diagnostics_max_severity,
 2121                    cx,
 2122                )
 2123            })
 2124        });
 2125
 2126        let selections = SelectionsCollection::new();
 2127
 2128        let blink_manager = cx.new(|cx| {
 2129            let mut blink_manager = BlinkManager::new(
 2130                CURSOR_BLINK_INTERVAL,
 2131                |cx| EditorSettings::get_global(cx).cursor_blink,
 2132                cx,
 2133            );
 2134            if is_minimap {
 2135                blink_manager.disable(cx);
 2136            }
 2137            blink_manager
 2138        });
 2139
 2140        let soft_wrap_mode_override =
 2141            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2142
 2143        let mut project_subscriptions = Vec::new();
 2144        if full_mode && let Some(project) = project.as_ref() {
 2145            project_subscriptions.push(cx.subscribe_in(
 2146                project,
 2147                window,
 2148                |editor, _, event, window, cx| match event {
 2149                    project::Event::RefreshCodeLens => {
 2150                        // we always query lens with actions, without storing them, always refreshing them
 2151                    }
 2152                    project::Event::RefreshInlayHints {
 2153                        server_id,
 2154                        request_id,
 2155                    } => {
 2156                        editor.refresh_inlay_hints(
 2157                            InlayHintRefreshReason::RefreshRequested {
 2158                                server_id: *server_id,
 2159                                request_id: *request_id,
 2160                            },
 2161                            cx,
 2162                        );
 2163                    }
 2164                    project::Event::RefreshSemanticTokens {
 2165                        server_id,
 2166                        request_id,
 2167                    } => {
 2168                        editor.refresh_semantic_tokens(
 2169                            None,
 2170                            Some(RefreshForServer {
 2171                                server_id: *server_id,
 2172                                request_id: *request_id,
 2173                            }),
 2174                            cx,
 2175                        );
 2176                    }
 2177                    project::Event::LanguageServerRemoved(_) => {
 2178                        editor.registered_buffers.clear();
 2179                        editor.register_visible_buffers(cx);
 2180                        editor.invalidate_semantic_tokens(None);
 2181                        editor.refresh_runnables(None, window, cx);
 2182                        editor.update_lsp_data(None, window, cx);
 2183                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2184                    }
 2185                    project::Event::SnippetEdit(id, snippet_edits) => {
 2186                        // todo(lw): Non singletons
 2187                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2188                            let snapshot = buffer.read(cx).snapshot();
 2189                            let focus_handle = editor.focus_handle(cx);
 2190                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2191                                for (range, snippet) in snippet_edits {
 2192                                    let buffer_range =
 2193                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2194                                    editor
 2195                                        .insert_snippet(
 2196                                            &[MultiBufferOffset(buffer_range.start)
 2197                                                ..MultiBufferOffset(buffer_range.end)],
 2198                                            snippet.clone(),
 2199                                            window,
 2200                                            cx,
 2201                                        )
 2202                                        .ok();
 2203                                }
 2204                            }
 2205                        }
 2206                    }
 2207                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2208                        let buffer_id = *buffer_id;
 2209                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2210                            editor.register_buffer(buffer_id, cx);
 2211                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2212                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2213                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2214                            refresh_linked_ranges(editor, window, cx);
 2215                            editor.refresh_code_actions(window, cx);
 2216                            editor.refresh_document_highlights(cx);
 2217                        }
 2218                    }
 2219
 2220                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2221                        let Some(workspace) = editor.workspace() else {
 2222                            return;
 2223                        };
 2224                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2225                        else {
 2226                            return;
 2227                        };
 2228
 2229                        if active_editor.entity_id() == cx.entity_id() {
 2230                            let entity_id = cx.entity_id();
 2231                            workspace.update(cx, |this, cx| {
 2232                                this.panes_mut()
 2233                                    .iter_mut()
 2234                                    .filter(|pane| pane.entity_id() != entity_id)
 2235                                    .for_each(|p| {
 2236                                        p.update(cx, |pane, _| {
 2237                                            pane.nav_history_mut().rename_item(
 2238                                                entity_id,
 2239                                                project_path.clone(),
 2240                                                abs_path.clone().into(),
 2241                                            );
 2242                                        })
 2243                                    });
 2244                            });
 2245
 2246                            Self::open_transaction_for_hidden_buffers(
 2247                                workspace,
 2248                                transaction.clone(),
 2249                                "Rename".to_string(),
 2250                                window,
 2251                                cx,
 2252                            );
 2253                        }
 2254                    }
 2255
 2256                    project::Event::WorkspaceEditApplied(transaction) => {
 2257                        let Some(workspace) = editor.workspace() else {
 2258                            return;
 2259                        };
 2260                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2261                        else {
 2262                            return;
 2263                        };
 2264
 2265                        if active_editor.entity_id() == cx.entity_id() {
 2266                            Self::open_transaction_for_hidden_buffers(
 2267                                workspace,
 2268                                transaction.clone(),
 2269                                "LSP Edit".to_string(),
 2270                                window,
 2271                                cx,
 2272                            );
 2273                        }
 2274                    }
 2275
 2276                    _ => {}
 2277                },
 2278            ));
 2279            if let Some(task_inventory) = project
 2280                .read(cx)
 2281                .task_store()
 2282                .read(cx)
 2283                .task_inventory()
 2284                .cloned()
 2285            {
 2286                project_subscriptions.push(cx.observe_in(
 2287                    &task_inventory,
 2288                    window,
 2289                    |editor, _, window, cx| {
 2290                        editor.refresh_runnables(None, window, cx);
 2291                    },
 2292                ));
 2293            };
 2294
 2295            project_subscriptions.push(cx.subscribe_in(
 2296                &project.read(cx).breakpoint_store(),
 2297                window,
 2298                |editor, _, event, window, cx| match event {
 2299                    BreakpointStoreEvent::ClearDebugLines => {
 2300                        editor.clear_row_highlights::<ActiveDebugLine>();
 2301                        editor.refresh_inline_values(cx);
 2302                    }
 2303                    BreakpointStoreEvent::SetDebugLine => {
 2304                        if editor.go_to_active_debug_line(window, cx) {
 2305                            cx.stop_propagation();
 2306                        }
 2307
 2308                        editor.refresh_inline_values(cx);
 2309                    }
 2310                    _ => {}
 2311                },
 2312            ));
 2313            let git_store = project.read(cx).git_store().clone();
 2314            let project = project.clone();
 2315            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2316                if let GitStoreEvent::RepositoryAdded = event {
 2317                    this.load_diff_task = Some(
 2318                        update_uncommitted_diff_for_buffer(
 2319                            cx.entity(),
 2320                            &project,
 2321                            this.buffer.read(cx).all_buffers(),
 2322                            this.buffer.clone(),
 2323                            cx,
 2324                        )
 2325                        .shared(),
 2326                    );
 2327                }
 2328            }));
 2329        }
 2330
 2331        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2332
 2333        let inlay_hint_settings =
 2334            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2335        let focus_handle = cx.focus_handle();
 2336        if !is_minimap {
 2337            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2338                .detach();
 2339            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2340                .detach();
 2341            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2342                .detach();
 2343            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2344                .detach();
 2345            cx.observe_pending_input(window, Self::observe_pending_input)
 2346                .detach();
 2347        }
 2348
 2349        let show_indent_guides =
 2350            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2351                Some(false)
 2352            } else {
 2353                None
 2354            };
 2355
 2356        let breakpoint_store = match (&mode, project.as_ref()) {
 2357            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2358            _ => None,
 2359        };
 2360
 2361        let mut code_action_providers = Vec::new();
 2362        let mut load_uncommitted_diff = None;
 2363        if let Some(project) = project.clone() {
 2364            load_uncommitted_diff = Some(
 2365                update_uncommitted_diff_for_buffer(
 2366                    cx.entity(),
 2367                    &project,
 2368                    multi_buffer.read(cx).all_buffers(),
 2369                    multi_buffer.clone(),
 2370                    cx,
 2371                )
 2372                .shared(),
 2373            );
 2374            code_action_providers.push(Rc::new(project) as Rc<_>);
 2375        }
 2376
 2377        let mut editor = Self {
 2378            focus_handle,
 2379            show_cursor_when_unfocused: false,
 2380            last_focused_descendant: None,
 2381            buffer: multi_buffer.clone(),
 2382            display_map: display_map.clone(),
 2383            placeholder_display_map: None,
 2384            selections,
 2385            scroll_manager: ScrollManager::new(cx),
 2386            columnar_selection_state: None,
 2387            add_selections_state: None,
 2388            select_next_state: None,
 2389            select_prev_state: None,
 2390            selection_history: SelectionHistory::default(),
 2391            defer_selection_effects: false,
 2392            deferred_selection_effects_state: None,
 2393            autoclose_regions: Vec::new(),
 2394            snippet_stack: InvalidationStack::default(),
 2395            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2396            ime_transaction: None,
 2397            active_diagnostics: ActiveDiagnostic::None,
 2398            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2399            inline_diagnostics_update: Task::ready(()),
 2400            inline_diagnostics: Vec::new(),
 2401            soft_wrap_mode_override,
 2402            diagnostics_max_severity,
 2403            hard_wrap: None,
 2404            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2405            semantics_provider: project
 2406                .as_ref()
 2407                .map(|project| Rc::new(project.downgrade()) as _),
 2408            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2409            project,
 2410            blink_manager: blink_manager.clone(),
 2411            show_local_selections: true,
 2412            show_scrollbars: ScrollbarAxes {
 2413                horizontal: full_mode,
 2414                vertical: full_mode,
 2415            },
 2416            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2417            offset_content: !matches!(mode, EditorMode::SingleLine),
 2418            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2419            show_gutter: full_mode,
 2420            show_line_numbers: (!full_mode).then_some(false),
 2421            use_relative_line_numbers: None,
 2422            disable_expand_excerpt_buttons: !full_mode,
 2423            delegate_expand_excerpts: false,
 2424            delegate_stage_and_restore: false,
 2425            delegate_open_excerpts: false,
 2426            enable_lsp_data: full_mode,
 2427            enable_runnables: full_mode,
 2428            enable_mouse_wheel_zoom: full_mode,
 2429            show_git_diff_gutter: None,
 2430            show_code_actions: None,
 2431            show_runnables: None,
 2432            show_breakpoints: None,
 2433            show_diff_review_button: false,
 2434            show_wrap_guides: None,
 2435            show_indent_guides,
 2436            buffers_with_disabled_indent_guides: HashSet::default(),
 2437            highlight_order: 0,
 2438            highlighted_rows: HashMap::default(),
 2439            background_highlights: HashMap::default(),
 2440            gutter_highlights: HashMap::default(),
 2441            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2442            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2443            nav_history: None,
 2444            context_menu: RefCell::new(None),
 2445            context_menu_options: None,
 2446            mouse_context_menu: None,
 2447            completion_tasks: Vec::new(),
 2448            inline_blame_popover: None,
 2449            inline_blame_popover_show_task: None,
 2450            signature_help_state: SignatureHelpState::default(),
 2451            auto_signature_help: None,
 2452            find_all_references_task_sources: Vec::new(),
 2453            next_completion_id: 0,
 2454            next_inlay_id: 0,
 2455            code_action_providers,
 2456            available_code_actions: None,
 2457            code_actions_task: None,
 2458            quick_selection_highlight_task: None,
 2459            debounced_selection_highlight_task: None,
 2460            debounced_selection_highlight_complete: false,
 2461            document_highlights_task: None,
 2462            linked_editing_range_task: None,
 2463            pending_rename: None,
 2464            searchable: !is_minimap,
 2465            cursor_shape: EditorSettings::get_global(cx)
 2466                .cursor_shape
 2467                .unwrap_or_default(),
 2468            cursor_offset_on_selection: false,
 2469            current_line_highlight: None,
 2470            autoindent_mode: Some(AutoindentMode::EachLine),
 2471            collapse_matches: false,
 2472            workspace: None,
 2473            input_enabled: !is_minimap,
 2474            expects_character_input: !is_minimap,
 2475            use_modal_editing: full_mode,
 2476            read_only: is_minimap,
 2477            use_autoclose: true,
 2478            use_auto_surround: true,
 2479            use_selection_highlight: true,
 2480            auto_replace_emoji_shortcode: false,
 2481            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2482            leader_id: None,
 2483            remote_id: None,
 2484            hover_state: HoverState::default(),
 2485            pending_mouse_down: None,
 2486            prev_pressure_stage: None,
 2487            hovered_link_state: None,
 2488            edit_prediction_provider: None,
 2489            active_edit_prediction: None,
 2490            stale_edit_prediction_in_menu: None,
 2491            edit_prediction_preview: EditPredictionPreview::Inactive {
 2492                released_too_fast: false,
 2493            },
 2494            inline_diagnostics_enabled: full_mode,
 2495            diagnostics_enabled: full_mode,
 2496            word_completions_enabled: full_mode,
 2497            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2498            gutter_hovered: false,
 2499            pixel_position_of_newest_cursor: None,
 2500            last_bounds: None,
 2501            last_position_map: None,
 2502            expect_bounds_change: None,
 2503            gutter_dimensions: GutterDimensions::default(),
 2504            style: None,
 2505            show_cursor_names: false,
 2506            hovered_cursors: HashMap::default(),
 2507            next_editor_action_id: EditorActionId::default(),
 2508            editor_actions: Rc::default(),
 2509            edit_predictions_hidden_for_vim_mode: false,
 2510            show_edit_predictions_override: None,
 2511            show_completions_on_input_override: None,
 2512            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2513            edit_prediction_settings: EditPredictionSettings::Disabled,
 2514            in_leading_whitespace: false,
 2515            custom_context_menu: None,
 2516            show_git_blame_gutter: false,
 2517            show_git_blame_inline: false,
 2518            show_selection_menu: None,
 2519            show_git_blame_inline_delay_task: None,
 2520            git_blame_inline_enabled: full_mode
 2521                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2522            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2523            buffer_serialization: is_minimap.not().then(|| {
 2524                BufferSerialization::new(
 2525                    ProjectSettings::get_global(cx)
 2526                        .session
 2527                        .restore_unsaved_buffers,
 2528                )
 2529            }),
 2530            blame: None,
 2531            blame_subscription: None,
 2532
 2533            breakpoint_store,
 2534            gutter_breakpoint_indicator: (None, None),
 2535            gutter_diff_review_indicator: (None, None),
 2536            diff_review_drag_state: None,
 2537            diff_review_overlays: Vec::new(),
 2538            stored_review_comments: Vec::new(),
 2539            next_review_comment_id: 0,
 2540            hovered_diff_hunk_row: None,
 2541            _subscriptions: (!is_minimap)
 2542                .then(|| {
 2543                    vec![
 2544                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2545                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2546                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2547                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2548                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2549                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2550                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2551                        cx.observe_window_activation(window, |editor, window, cx| {
 2552                            let active = window.is_window_active();
 2553                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2554                                if active {
 2555                                    blink_manager.enable(cx);
 2556                                } else {
 2557                                    blink_manager.disable(cx);
 2558                                }
 2559                            });
 2560                            if active {
 2561                                editor.show_mouse_cursor(cx);
 2562                            }
 2563                        }),
 2564                    ]
 2565                })
 2566                .unwrap_or_default(),
 2567            runnables: RunnableData::new(),
 2568            pull_diagnostics_task: Task::ready(()),
 2569            colors: None,
 2570            refresh_colors_task: Task::ready(()),
 2571            use_document_folding_ranges: false,
 2572            refresh_folding_ranges_task: Task::ready(()),
 2573            inlay_hints: None,
 2574            next_color_inlay_id: 0,
 2575            post_scroll_update: Task::ready(()),
 2576            linked_edit_ranges: Default::default(),
 2577            in_project_search: false,
 2578            previous_search_ranges: None,
 2579            breadcrumb_header: None,
 2580            focused_block: None,
 2581            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2582            addons: HashMap::default(),
 2583            registered_buffers: HashMap::default(),
 2584            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2585            selection_mark_mode: false,
 2586            toggle_fold_multiple_buffers: Task::ready(()),
 2587            serialize_selections: Task::ready(()),
 2588            serialize_folds: Task::ready(()),
 2589            text_style_refinement: None,
 2590            load_diff_task: load_uncommitted_diff,
 2591            temporary_diff_override: false,
 2592            mouse_cursor_hidden: false,
 2593            minimap: None,
 2594            hide_mouse_mode: EditorSettings::get_global(cx)
 2595                .hide_mouse
 2596                .unwrap_or_default(),
 2597            change_list: ChangeList::new(),
 2598            mode,
 2599            selection_drag_state: SelectionDragState::None,
 2600            folding_newlines: Task::ready(()),
 2601            lookup_key: None,
 2602            select_next_is_case_sensitive: None,
 2603            on_local_selections_changed: None,
 2604            suppress_selection_callback: false,
 2605            applicable_language_settings: HashMap::default(),
 2606            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2607            accent_data: None,
 2608            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2609            number_deleted_lines: false,
 2610            refresh_matching_bracket_highlights_task: Task::ready(()),
 2611            refresh_document_symbols_task: Task::ready(()).shared(),
 2612            lsp_document_symbols: HashMap::default(),
 2613            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2614            outline_symbols_at_cursor: None,
 2615            sticky_headers_task: Task::ready(()),
 2616            sticky_headers: None,
 2617            colorize_brackets_task: Task::ready(()),
 2618        };
 2619
 2620        if is_minimap {
 2621            return editor;
 2622        }
 2623
 2624        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2625        editor.accent_data = editor.fetch_accent_data(cx);
 2626
 2627        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2628            editor
 2629                ._subscriptions
 2630                .push(cx.observe(breakpoints, |_, _, cx| {
 2631                    cx.notify();
 2632                }));
 2633        }
 2634        editor._subscriptions.extend(project_subscriptions);
 2635
 2636        editor._subscriptions.push(cx.subscribe_in(
 2637            &cx.entity(),
 2638            window,
 2639            |editor, _, e: &EditorEvent, window, cx| match e {
 2640                EditorEvent::ScrollPositionChanged { local, .. } => {
 2641                    if *local {
 2642                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2643                        editor.inline_blame_popover.take();
 2644                        let snapshot = editor.snapshot(window, cx);
 2645                        let new_anchor = editor
 2646                            .scroll_manager
 2647                            .native_anchor(&snapshot.display_snapshot, cx);
 2648                        editor.update_restoration_data(cx, move |data| {
 2649                            data.scroll_position = (
 2650                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2651                                new_anchor.offset,
 2652                            );
 2653                        });
 2654
 2655                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2656                            cx.background_executor()
 2657                                .timer(Duration::from_millis(50))
 2658                                .await;
 2659                            editor
 2660                                .update_in(cx, |editor, window, cx| {
 2661                                    editor.update_data_on_scroll(window, cx)
 2662                                })
 2663                                .ok();
 2664                        });
 2665                    }
 2666                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2667                }
 2668                EditorEvent::Edited { .. } => {
 2669                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2670                        .map(|vim_mode| vim_mode.0)
 2671                        .unwrap_or(false);
 2672                    if !vim_mode {
 2673                        let display_map = editor.display_snapshot(cx);
 2674                        let selections = editor.selections.all_adjusted_display(&display_map);
 2675                        let pop_state = editor
 2676                            .change_list
 2677                            .last()
 2678                            .map(|previous| {
 2679                                previous.len() == selections.len()
 2680                                    && previous.iter().enumerate().all(|(ix, p)| {
 2681                                        p.to_display_point(&display_map).row()
 2682                                            == selections[ix].head().row()
 2683                                    })
 2684                            })
 2685                            .unwrap_or(false);
 2686                        let new_positions = selections
 2687                            .into_iter()
 2688                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2689                            .collect();
 2690                        editor
 2691                            .change_list
 2692                            .push_to_change_list(pop_state, new_positions);
 2693                    }
 2694                }
 2695                _ => (),
 2696            },
 2697        ));
 2698
 2699        if let Some(dap_store) = editor
 2700            .project
 2701            .as_ref()
 2702            .map(|project| project.read(cx).dap_store())
 2703        {
 2704            let weak_editor = cx.weak_entity();
 2705
 2706            editor
 2707                ._subscriptions
 2708                .push(
 2709                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2710                        let session_entity = cx.entity();
 2711                        weak_editor
 2712                            .update(cx, |editor, cx| {
 2713                                editor._subscriptions.push(
 2714                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2715                                );
 2716                            })
 2717                            .ok();
 2718                    }),
 2719                );
 2720
 2721            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2722                editor
 2723                    ._subscriptions
 2724                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2725            }
 2726        }
 2727
 2728        // skip adding the initial selection to selection history
 2729        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2730        editor.end_selection(window, cx);
 2731        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2732
 2733        editor.scroll_manager.show_scrollbars(window, cx);
 2734        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2735
 2736        if full_mode {
 2737            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2738            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2739
 2740            if editor.git_blame_inline_enabled {
 2741                editor.start_git_blame_inline(false, window, cx);
 2742            }
 2743
 2744            editor.go_to_active_debug_line(window, cx);
 2745
 2746            editor.minimap =
 2747                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2748            editor.colors = Some(LspColorData::new(cx));
 2749            editor.use_document_folding_ranges = true;
 2750            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2751
 2752            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2753                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2754            }
 2755            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2756        }
 2757
 2758        editor
 2759    }
 2760
 2761    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2762        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2763    }
 2764
 2765    pub fn deploy_mouse_context_menu(
 2766        &mut self,
 2767        position: gpui::Point<Pixels>,
 2768        context_menu: Entity<ContextMenu>,
 2769        window: &mut Window,
 2770        cx: &mut Context<Self>,
 2771    ) {
 2772        self.mouse_context_menu = Some(MouseContextMenu::new(
 2773            self,
 2774            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2775            context_menu,
 2776            window,
 2777            cx,
 2778        ));
 2779    }
 2780
 2781    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2782        self.mouse_context_menu
 2783            .as_ref()
 2784            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2785    }
 2786
 2787    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2788        if self
 2789            .selections
 2790            .pending_anchor()
 2791            .is_some_and(|pending_selection| {
 2792                let snapshot = self.buffer().read(cx).snapshot(cx);
 2793                pending_selection.range().includes(range, &snapshot)
 2794            })
 2795        {
 2796            return true;
 2797        }
 2798
 2799        self.selections
 2800            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2801            .into_iter()
 2802            .any(|selection| {
 2803                // This is needed to cover a corner case, if we just check for an existing
 2804                // selection in the fold range, having a cursor at the start of the fold
 2805                // marks it as selected. Non-empty selections don't cause this.
 2806                let length = selection.end - selection.start;
 2807                length > 0
 2808            })
 2809    }
 2810
 2811    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2812        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2813    }
 2814
 2815    fn key_context_internal(
 2816        &self,
 2817        has_active_edit_prediction: bool,
 2818        window: &mut Window,
 2819        cx: &mut App,
 2820    ) -> KeyContext {
 2821        let mut key_context = KeyContext::new_with_defaults();
 2822        key_context.add("Editor");
 2823        let mode = match self.mode {
 2824            EditorMode::SingleLine => "single_line",
 2825            EditorMode::AutoHeight { .. } => "auto_height",
 2826            EditorMode::Minimap { .. } => "minimap",
 2827            EditorMode::Full { .. } => "full",
 2828        };
 2829
 2830        if EditorSettings::jupyter_enabled(cx) {
 2831            key_context.add("jupyter");
 2832        }
 2833
 2834        key_context.set("mode", mode);
 2835        if self.pending_rename.is_some() {
 2836            key_context.add("renaming");
 2837        }
 2838
 2839        if let Some(snippet_stack) = self.snippet_stack.last() {
 2840            key_context.add("in_snippet");
 2841
 2842            if snippet_stack.active_index > 0 {
 2843                key_context.add("has_previous_tabstop");
 2844            }
 2845
 2846            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2847                key_context.add("has_next_tabstop");
 2848            }
 2849        }
 2850
 2851        match self.context_menu.borrow().as_ref() {
 2852            Some(CodeContextMenu::Completions(menu)) => {
 2853                if menu.visible() {
 2854                    key_context.add("menu");
 2855                    key_context.add("showing_completions");
 2856                }
 2857            }
 2858            Some(CodeContextMenu::CodeActions(menu)) => {
 2859                if menu.visible() {
 2860                    key_context.add("menu");
 2861                    key_context.add("showing_code_actions")
 2862                }
 2863            }
 2864            None => {}
 2865        }
 2866
 2867        if self.signature_help_state.has_multiple_signatures() {
 2868            key_context.add("showing_signature_help");
 2869        }
 2870
 2871        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2872        if !self.focus_handle(cx).contains_focused(window, cx)
 2873            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2874        {
 2875            for addon in self.addons.values() {
 2876                addon.extend_key_context(&mut key_context, cx)
 2877            }
 2878        }
 2879
 2880        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2881            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2882                Some(
 2883                    file.full_path(cx)
 2884                        .extension()?
 2885                        .to_string_lossy()
 2886                        .to_lowercase(),
 2887                )
 2888            }) {
 2889                key_context.set("extension", extension);
 2890            }
 2891        } else {
 2892            key_context.add("multibuffer");
 2893        }
 2894
 2895        if has_active_edit_prediction {
 2896            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2897            key_context.add("copilot_suggestion");
 2898        }
 2899
 2900        if self.in_leading_whitespace {
 2901            key_context.add("in_leading_whitespace");
 2902        }
 2903        if self.edit_prediction_requires_modifier() {
 2904            key_context.set("edit_prediction_mode", "subtle")
 2905        } else {
 2906            key_context.set("edit_prediction_mode", "eager");
 2907        }
 2908
 2909        if self.selection_mark_mode {
 2910            key_context.add("selection_mode");
 2911        }
 2912
 2913        let disjoint = self.selections.disjoint_anchors();
 2914        if matches!(
 2915            &self.mode,
 2916            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2917        ) && let [selection] = disjoint
 2918            && selection.start == selection.end
 2919        {
 2920            let snapshot = self.snapshot(window, cx);
 2921            let snapshot = snapshot.buffer_snapshot();
 2922            let caret_offset = selection.end.to_offset(snapshot);
 2923
 2924            if caret_offset == MultiBufferOffset(0) {
 2925                key_context.add("start_of_input");
 2926            }
 2927
 2928            if caret_offset == snapshot.len() {
 2929                key_context.add("end_of_input");
 2930            }
 2931        }
 2932
 2933        if self.has_any_expanded_diff_hunks(cx) {
 2934            key_context.add("diffs_expanded");
 2935        }
 2936
 2937        key_context
 2938    }
 2939
 2940    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2941        self.last_bounds.as_ref()
 2942    }
 2943
 2944    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2945        if self.mouse_cursor_hidden {
 2946            self.mouse_cursor_hidden = false;
 2947            cx.notify();
 2948        }
 2949    }
 2950
 2951    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2952        let hide_mouse_cursor = match origin {
 2953            HideMouseCursorOrigin::TypingAction => {
 2954                matches!(
 2955                    self.hide_mouse_mode,
 2956                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2957                )
 2958            }
 2959            HideMouseCursorOrigin::MovementAction => {
 2960                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2961            }
 2962        };
 2963        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2964            self.mouse_cursor_hidden = hide_mouse_cursor;
 2965            cx.notify();
 2966        }
 2967    }
 2968
 2969    fn accept_edit_prediction_keystroke(
 2970        &self,
 2971        granularity: EditPredictionGranularity,
 2972        window: &mut Window,
 2973        cx: &mut App,
 2974    ) -> Option<gpui::KeybindingKeystroke> {
 2975        let key_context = self.key_context_internal(true, window, cx);
 2976
 2977        let bindings =
 2978            match granularity {
 2979                EditPredictionGranularity::Word => window
 2980                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2981                EditPredictionGranularity::Line => window
 2982                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2983                EditPredictionGranularity::Full => {
 2984                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2985                }
 2986            };
 2987
 2988        bindings
 2989            .into_iter()
 2990            .rev()
 2991            .find_map(|binding| match binding.keystrokes() {
 2992                [keystroke, ..] => Some(keystroke.clone()),
 2993                _ => None,
 2994            })
 2995    }
 2996
 2997    fn preview_edit_prediction_keystroke(
 2998        &self,
 2999        window: &mut Window,
 3000        cx: &mut App,
 3001    ) -> Option<gpui::KeybindingKeystroke> {
 3002        let key_context = self.key_context_internal(true, window, cx);
 3003        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 3004        bindings
 3005            .into_iter()
 3006            .rev()
 3007            .find_map(|binding| match binding.keystrokes() {
 3008                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 3009                _ => None,
 3010            })
 3011    }
 3012
 3013    fn edit_prediction_preview_modifiers_held(
 3014        &self,
 3015        modifiers: &Modifiers,
 3016        window: &mut Window,
 3017        cx: &mut App,
 3018    ) -> bool {
 3019        let key_context = self.key_context_internal(true, window, cx);
 3020        let actions: [&dyn Action; 3] = [
 3021            &AcceptEditPrediction,
 3022            &AcceptNextWordEditPrediction,
 3023            &AcceptNextLineEditPrediction,
 3024        ];
 3025
 3026        actions.into_iter().any(|action| {
 3027            window
 3028                .bindings_for_action_in_context(action, key_context.clone())
 3029                .into_iter()
 3030                .rev()
 3031                .any(|binding| {
 3032                    binding.keystrokes().first().is_some_and(|keystroke| {
 3033                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3034                    })
 3035                })
 3036        })
 3037    }
 3038
 3039    fn edit_prediction_cursor_popover_prefers_preview(
 3040        &self,
 3041        completion: &EditPredictionState,
 3042        cx: &App,
 3043    ) -> bool {
 3044        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 3045
 3046        match &completion.completion {
 3047            EditPrediction::Edit {
 3048                edits, snapshot, ..
 3049            } => {
 3050                let mut start_row: Option<u32> = None;
 3051                let mut end_row: Option<u32> = None;
 3052
 3053                for (range, text) in edits {
 3054                    let Some((_, range)) =
 3055                        multibuffer_snapshot.anchor_range_to_buffer_anchor_range(range.clone())
 3056                    else {
 3057                        continue;
 3058                    };
 3059                    let edit_start_row = range.start.to_point(snapshot).row;
 3060                    let old_end_row = range.end.to_point(snapshot).row;
 3061                    let inserted_newline_count = text
 3062                        .as_ref()
 3063                        .chars()
 3064                        .filter(|character| *character == '\n')
 3065                        .count() as u32;
 3066                    let deleted_newline_count = old_end_row - edit_start_row;
 3067                    let preview_end_row = edit_start_row + inserted_newline_count;
 3068
 3069                    start_row =
 3070                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3071                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3072
 3073                    if deleted_newline_count > 1 {
 3074                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3075                    }
 3076                }
 3077
 3078                start_row
 3079                    .zip(end_row)
 3080                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3081            }
 3082            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3083        }
 3084    }
 3085
 3086    fn edit_prediction_keybind_display(
 3087        &self,
 3088        surface: EditPredictionKeybindSurface,
 3089        window: &mut Window,
 3090        cx: &mut App,
 3091    ) -> EditPredictionKeybindDisplay {
 3092        let accept_keystroke =
 3093            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3094        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3095
 3096        let action = match surface {
 3097            EditPredictionKeybindSurface::Inline
 3098            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3099                if self.edit_prediction_requires_modifier() {
 3100                    EditPredictionKeybindAction::Preview
 3101                } else {
 3102                    EditPredictionKeybindAction::Accept
 3103                }
 3104            }
 3105            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3106                .active_edit_prediction
 3107                .as_ref()
 3108                .filter(|completion| {
 3109                    self.edit_prediction_cursor_popover_prefers_preview(completion, cx)
 3110                })
 3111                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3112                    EditPredictionKeybindAction::Preview
 3113                }),
 3114        };
 3115        #[cfg(test)]
 3116        let preview_copy = preview_keystroke.clone();
 3117        #[cfg(test)]
 3118        let accept_copy = accept_keystroke.clone();
 3119
 3120        let displayed_keystroke = match surface {
 3121            EditPredictionKeybindSurface::Inline => match action {
 3122                EditPredictionKeybindAction::Accept => accept_keystroke,
 3123                EditPredictionKeybindAction::Preview => preview_keystroke,
 3124            },
 3125            EditPredictionKeybindSurface::CursorPopoverCompact
 3126            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3127                EditPredictionKeybindAction::Accept => accept_keystroke,
 3128                EditPredictionKeybindAction::Preview => {
 3129                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3130                }
 3131            },
 3132        };
 3133
 3134        let missing_accept_keystroke = displayed_keystroke.is_none();
 3135
 3136        EditPredictionKeybindDisplay {
 3137            #[cfg(test)]
 3138            accept_keystroke: accept_copy,
 3139            #[cfg(test)]
 3140            preview_keystroke: preview_copy,
 3141            displayed_keystroke,
 3142            action,
 3143            missing_accept_keystroke,
 3144            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3145                && self.edit_prediction_preview.released_too_fast(),
 3146        }
 3147    }
 3148
 3149    pub fn new_file(
 3150        workspace: &mut Workspace,
 3151        _: &workspace::NewFile,
 3152        window: &mut Window,
 3153        cx: &mut Context<Workspace>,
 3154    ) {
 3155        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3156            "Failed to create buffer",
 3157            window,
 3158            cx,
 3159            |e, _, _| match e.error_code() {
 3160                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3161                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3162                e.error_tag("required").unwrap_or("the latest version")
 3163            )),
 3164                _ => None,
 3165            },
 3166        );
 3167    }
 3168
 3169    pub fn new_in_workspace(
 3170        workspace: &mut Workspace,
 3171        window: &mut Window,
 3172        cx: &mut Context<Workspace>,
 3173    ) -> Task<Result<Entity<Editor>>> {
 3174        let project = workspace.project().clone();
 3175        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3176
 3177        cx.spawn_in(window, async move |workspace, cx| {
 3178            let buffer = create.await?;
 3179            workspace.update_in(cx, |workspace, window, cx| {
 3180                let editor =
 3181                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3182                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3183                editor
 3184            })
 3185        })
 3186    }
 3187
 3188    fn new_file_vertical(
 3189        workspace: &mut Workspace,
 3190        _: &workspace::NewFileSplitVertical,
 3191        window: &mut Window,
 3192        cx: &mut Context<Workspace>,
 3193    ) {
 3194        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3195    }
 3196
 3197    fn new_file_horizontal(
 3198        workspace: &mut Workspace,
 3199        _: &workspace::NewFileSplitHorizontal,
 3200        window: &mut Window,
 3201        cx: &mut Context<Workspace>,
 3202    ) {
 3203        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3204    }
 3205
 3206    fn new_file_split(
 3207        workspace: &mut Workspace,
 3208        action: &workspace::NewFileSplit,
 3209        window: &mut Window,
 3210        cx: &mut Context<Workspace>,
 3211    ) {
 3212        Self::new_file_in_direction(workspace, action.0, window, cx)
 3213    }
 3214
 3215    fn new_file_in_direction(
 3216        workspace: &mut Workspace,
 3217        direction: SplitDirection,
 3218        window: &mut Window,
 3219        cx: &mut Context<Workspace>,
 3220    ) {
 3221        let project = workspace.project().clone();
 3222        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3223
 3224        cx.spawn_in(window, async move |workspace, cx| {
 3225            let buffer = create.await?;
 3226            workspace.update_in(cx, move |workspace, window, cx| {
 3227                workspace.split_item(
 3228                    direction,
 3229                    Box::new(
 3230                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3231                    ),
 3232                    window,
 3233                    cx,
 3234                )
 3235            })?;
 3236            anyhow::Ok(())
 3237        })
 3238        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3239            match e.error_code() {
 3240                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3241                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3242                e.error_tag("required").unwrap_or("the latest version")
 3243            )),
 3244                _ => None,
 3245            }
 3246        });
 3247    }
 3248
 3249    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3250        self.leader_id
 3251    }
 3252
 3253    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3254        &self.buffer
 3255    }
 3256
 3257    pub fn project(&self) -> Option<&Entity<Project>> {
 3258        self.project.as_ref()
 3259    }
 3260
 3261    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3262        self.workspace.as_ref()?.0.upgrade()
 3263    }
 3264
 3265    /// Detaches a task and shows an error notification in the workspace if available,
 3266    /// otherwise just logs the error.
 3267    pub fn detach_and_notify_err<R, E>(
 3268        &self,
 3269        task: Task<Result<R, E>>,
 3270        window: &mut Window,
 3271        cx: &mut App,
 3272    ) where
 3273        E: std::fmt::Debug + std::fmt::Display + 'static,
 3274        R: 'static,
 3275    {
 3276        if let Some(workspace) = self.workspace() {
 3277            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3278        } else {
 3279            task.detach_and_log_err(cx);
 3280        }
 3281    }
 3282
 3283    /// Returns the workspace serialization ID if this editor should be serialized.
 3284    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3285        self.workspace
 3286            .as_ref()
 3287            .filter(|_| self.should_serialize_buffer())
 3288            .and_then(|workspace| workspace.1)
 3289    }
 3290
 3291    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3292        self.buffer().read(cx).title(cx)
 3293    }
 3294
 3295    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3296        let git_blame_gutter_max_author_length = self
 3297            .render_git_blame_gutter(cx)
 3298            .then(|| {
 3299                if let Some(blame) = self.blame.as_ref() {
 3300                    let max_author_length =
 3301                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3302                    Some(max_author_length)
 3303                } else {
 3304                    None
 3305                }
 3306            })
 3307            .flatten();
 3308
 3309        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3310
 3311        EditorSnapshot {
 3312            mode: self.mode.clone(),
 3313            show_gutter: self.show_gutter,
 3314            offset_content: self.offset_content,
 3315            show_line_numbers: self.show_line_numbers,
 3316            number_deleted_lines: self.number_deleted_lines,
 3317            show_git_diff_gutter: self.show_git_diff_gutter,
 3318            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3319            show_code_actions: self.show_code_actions,
 3320            show_runnables: self.show_runnables,
 3321            show_breakpoints: self.show_breakpoints,
 3322            git_blame_gutter_max_author_length,
 3323            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3324            display_snapshot,
 3325            placeholder_display_snapshot: self
 3326                .placeholder_display_map
 3327                .as_ref()
 3328                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3329            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3330            is_focused: self.focus_handle.is_focused(window),
 3331            current_line_highlight: self
 3332                .current_line_highlight
 3333                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3334            gutter_hovered: self.gutter_hovered,
 3335        }
 3336    }
 3337
 3338    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3339        self.buffer.read(cx).language_at(point, cx)
 3340    }
 3341
 3342    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3343        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3344    }
 3345
 3346    pub fn active_buffer(&self, cx: &App) -> Option<Entity<Buffer>> {
 3347        let multibuffer = self.buffer.read(cx);
 3348        let snapshot = multibuffer.snapshot(cx);
 3349        let (anchor, _) =
 3350            snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())?;
 3351        multibuffer.buffer(anchor.buffer_id)
 3352    }
 3353
 3354    pub fn mode(&self) -> &EditorMode {
 3355        &self.mode
 3356    }
 3357
 3358    pub fn set_mode(&mut self, mode: EditorMode) {
 3359        self.mode = mode;
 3360    }
 3361
 3362    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3363        self.collaboration_hub.as_deref()
 3364    }
 3365
 3366    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3367        self.collaboration_hub = Some(hub);
 3368    }
 3369
 3370    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3371        self.in_project_search = in_project_search;
 3372    }
 3373
 3374    pub fn set_custom_context_menu(
 3375        &mut self,
 3376        f: impl 'static
 3377        + Fn(
 3378            &mut Self,
 3379            DisplayPoint,
 3380            &mut Window,
 3381            &mut Context<Self>,
 3382        ) -> Option<Entity<ui::ContextMenu>>,
 3383    ) {
 3384        self.custom_context_menu = Some(Box::new(f))
 3385    }
 3386
 3387    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3388        self.completion_provider = provider;
 3389    }
 3390
 3391    #[cfg(any(test, feature = "test-support"))]
 3392    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3393        self.completion_provider.clone()
 3394    }
 3395
 3396    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3397        self.semantics_provider.clone()
 3398    }
 3399
 3400    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3401        self.semantics_provider = provider;
 3402    }
 3403
 3404    pub fn set_edit_prediction_provider<T>(
 3405        &mut self,
 3406        provider: Option<Entity<T>>,
 3407        window: &mut Window,
 3408        cx: &mut Context<Self>,
 3409    ) where
 3410        T: EditPredictionDelegate,
 3411    {
 3412        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3413            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3414                if this.focus_handle.is_focused(window) {
 3415                    this.update_visible_edit_prediction(window, cx);
 3416                }
 3417            }),
 3418            provider: Arc::new(provider),
 3419        });
 3420        self.update_edit_prediction_settings(cx);
 3421        self.refresh_edit_prediction(false, false, window, cx);
 3422    }
 3423
 3424    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3425        self.placeholder_display_map
 3426            .as_ref()
 3427            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3428    }
 3429
 3430    pub fn set_placeholder_text(
 3431        &mut self,
 3432        placeholder_text: &str,
 3433        window: &mut Window,
 3434        cx: &mut Context<Self>,
 3435    ) {
 3436        let multibuffer = cx
 3437            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3438
 3439        let style = window.text_style();
 3440
 3441        self.placeholder_display_map = Some(cx.new(|cx| {
 3442            DisplayMap::new(
 3443                multibuffer,
 3444                style.font(),
 3445                style.font_size.to_pixels(window.rem_size()),
 3446                None,
 3447                FILE_HEADER_HEIGHT,
 3448                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3449                Default::default(),
 3450                DiagnosticSeverity::Off,
 3451                cx,
 3452            )
 3453        }));
 3454        cx.notify();
 3455    }
 3456
 3457    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3458        self.cursor_shape = cursor_shape;
 3459
 3460        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3461        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3462
 3463        cx.notify();
 3464    }
 3465
 3466    pub fn cursor_shape(&self) -> CursorShape {
 3467        self.cursor_shape
 3468    }
 3469
 3470    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3471        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3472    }
 3473
 3474    pub fn set_current_line_highlight(
 3475        &mut self,
 3476        current_line_highlight: Option<CurrentLineHighlight>,
 3477    ) {
 3478        self.current_line_highlight = current_line_highlight;
 3479    }
 3480
 3481    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3482        self.collapse_matches = collapse_matches;
 3483    }
 3484
 3485    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3486        if self.collapse_matches {
 3487            return range.start..range.start;
 3488        }
 3489        range.clone()
 3490    }
 3491
 3492    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3493        self.display_map.read(cx).clip_at_line_ends
 3494    }
 3495
 3496    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3497        if self.display_map.read(cx).clip_at_line_ends != clip {
 3498            self.display_map
 3499                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3500        }
 3501    }
 3502
 3503    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3504        self.input_enabled = input_enabled;
 3505    }
 3506
 3507    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3508        self.expects_character_input = expects_character_input;
 3509    }
 3510
 3511    pub fn set_edit_predictions_hidden_for_vim_mode(
 3512        &mut self,
 3513        hidden: bool,
 3514        window: &mut Window,
 3515        cx: &mut Context<Self>,
 3516    ) {
 3517        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3518            self.edit_predictions_hidden_for_vim_mode = hidden;
 3519            if hidden {
 3520                self.update_visible_edit_prediction(window, cx);
 3521            } else {
 3522                self.refresh_edit_prediction(true, false, window, cx);
 3523            }
 3524        }
 3525    }
 3526
 3527    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3528        self.menu_edit_predictions_policy = value;
 3529    }
 3530
 3531    pub fn set_autoindent(&mut self, autoindent: bool) {
 3532        if autoindent {
 3533            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3534        } else {
 3535            self.autoindent_mode = None;
 3536        }
 3537    }
 3538
 3539    pub fn capability(&self, cx: &App) -> Capability {
 3540        if self.read_only {
 3541            Capability::ReadOnly
 3542        } else {
 3543            self.buffer.read(cx).capability()
 3544        }
 3545    }
 3546
 3547    pub fn read_only(&self, cx: &App) -> bool {
 3548        self.read_only || self.buffer.read(cx).read_only()
 3549    }
 3550
 3551    pub fn set_read_only(&mut self, read_only: bool) {
 3552        self.read_only = read_only;
 3553    }
 3554
 3555    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3556        self.use_autoclose = autoclose;
 3557    }
 3558
 3559    pub fn set_use_selection_highlight(&mut self, highlight: bool) {
 3560        self.use_selection_highlight = highlight;
 3561    }
 3562
 3563    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3564        self.use_auto_surround = auto_surround;
 3565    }
 3566
 3567    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3568        self.auto_replace_emoji_shortcode = auto_replace;
 3569    }
 3570
 3571    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3572        self.buffer_serialization = should_serialize.then(|| {
 3573            BufferSerialization::new(
 3574                ProjectSettings::get_global(cx)
 3575                    .session
 3576                    .restore_unsaved_buffers,
 3577            )
 3578        })
 3579    }
 3580
 3581    fn should_serialize_buffer(&self) -> bool {
 3582        self.buffer_serialization.is_some()
 3583    }
 3584
 3585    pub fn toggle_edit_predictions(
 3586        &mut self,
 3587        _: &ToggleEditPrediction,
 3588        window: &mut Window,
 3589        cx: &mut Context<Self>,
 3590    ) {
 3591        if self.show_edit_predictions_override.is_some() {
 3592            self.set_show_edit_predictions(None, window, cx);
 3593        } else {
 3594            let show_edit_predictions = !self.edit_predictions_enabled();
 3595            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3596        }
 3597    }
 3598
 3599    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3600        self.show_completions_on_input_override = show_completions_on_input;
 3601    }
 3602
 3603    pub fn set_show_edit_predictions(
 3604        &mut self,
 3605        show_edit_predictions: Option<bool>,
 3606        window: &mut Window,
 3607        cx: &mut Context<Self>,
 3608    ) {
 3609        self.show_edit_predictions_override = show_edit_predictions;
 3610        self.update_edit_prediction_settings(cx);
 3611
 3612        if let Some(false) = show_edit_predictions {
 3613            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3614        } else {
 3615            self.refresh_edit_prediction(false, true, window, cx);
 3616        }
 3617    }
 3618
 3619    fn edit_predictions_disabled_in_scope(
 3620        &self,
 3621        buffer: &Entity<Buffer>,
 3622        buffer_position: language::Anchor,
 3623        cx: &App,
 3624    ) -> bool {
 3625        let snapshot = buffer.read(cx).snapshot();
 3626        let settings = snapshot.settings_at(buffer_position, cx);
 3627
 3628        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3629            return false;
 3630        };
 3631
 3632        scope.override_name().is_some_and(|scope_name| {
 3633            settings
 3634                .edit_predictions_disabled_in
 3635                .iter()
 3636                .any(|s| s == scope_name)
 3637        })
 3638    }
 3639
 3640    pub fn set_use_modal_editing(&mut self, to: bool) {
 3641        self.use_modal_editing = to;
 3642    }
 3643
 3644    pub fn use_modal_editing(&self) -> bool {
 3645        self.use_modal_editing
 3646    }
 3647
 3648    fn selections_did_change(
 3649        &mut self,
 3650        local: bool,
 3651        old_cursor_position: &Anchor,
 3652        effects: SelectionEffects,
 3653        window: &mut Window,
 3654        cx: &mut Context<Self>,
 3655    ) {
 3656        window.invalidate_character_coordinates();
 3657
 3658        // Copy selections to primary selection buffer
 3659        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3660        if local {
 3661            let selections = self
 3662                .selections
 3663                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3664            let buffer_handle = self.buffer.read(cx).read(cx);
 3665
 3666            let mut text = String::new();
 3667            for (index, selection) in selections.iter().enumerate() {
 3668                let text_for_selection = buffer_handle
 3669                    .text_for_range(selection.start..selection.end)
 3670                    .collect::<String>();
 3671
 3672                text.push_str(&text_for_selection);
 3673                if index != selections.len() - 1 {
 3674                    text.push('\n');
 3675                }
 3676            }
 3677
 3678            if !text.is_empty() {
 3679                cx.write_to_primary(ClipboardItem::new_string(text));
 3680            }
 3681        }
 3682
 3683        let selection_anchors = self.selections.disjoint_anchors_arc();
 3684
 3685        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3686            self.buffer.update(cx, |buffer, cx| {
 3687                buffer.set_active_selections(
 3688                    &selection_anchors,
 3689                    self.selections.line_mode(),
 3690                    self.cursor_shape,
 3691                    cx,
 3692                )
 3693            });
 3694        }
 3695        let display_map = self
 3696            .display_map
 3697            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3698        let buffer = display_map.buffer_snapshot();
 3699        if self.selections.count() == 1 {
 3700            self.add_selections_state = None;
 3701        }
 3702        self.select_next_state = None;
 3703        self.select_prev_state = None;
 3704        self.select_syntax_node_history.try_clear();
 3705        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3706        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3707        self.take_rename(false, window, cx);
 3708
 3709        let newest_selection = self.selections.newest_anchor();
 3710        let new_cursor_position = newest_selection.head();
 3711        let selection_start = newest_selection.start;
 3712
 3713        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3714            self.push_to_nav_history(
 3715                *old_cursor_position,
 3716                Some(new_cursor_position.to_point(buffer)),
 3717                false,
 3718                effects.nav_history == Some(true),
 3719                cx,
 3720            );
 3721        }
 3722
 3723        if local {
 3724            if let Some((anchor, _)) = buffer.anchor_to_buffer_anchor(new_cursor_position) {
 3725                self.register_buffer(anchor.buffer_id, cx);
 3726            }
 3727
 3728            let mut context_menu = self.context_menu.borrow_mut();
 3729            let completion_menu = match context_menu.as_ref() {
 3730                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3731                Some(CodeContextMenu::CodeActions(_)) => {
 3732                    *context_menu = None;
 3733                    None
 3734                }
 3735                None => None,
 3736            };
 3737            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3738            drop(context_menu);
 3739
 3740            if effects.completions
 3741                && let Some(completion_position) = completion_position
 3742            {
 3743                let start_offset = selection_start.to_offset(buffer);
 3744                let position_matches = start_offset == completion_position.to_offset(buffer);
 3745                let continue_showing = if let Some((snap, ..)) =
 3746                    buffer.point_to_buffer_offset(completion_position)
 3747                    && !snap.capability.editable()
 3748                {
 3749                    false
 3750                } else if position_matches {
 3751                    if self.snippet_stack.is_empty() {
 3752                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3753                            == Some(CharKind::Word)
 3754                    } else {
 3755                        // Snippet choices can be shown even when the cursor is in whitespace.
 3756                        // Dismissing the menu with actions like backspace is handled by
 3757                        // invalidation regions.
 3758                        true
 3759                    }
 3760                } else {
 3761                    false
 3762                };
 3763
 3764                if continue_showing {
 3765                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3766                } else {
 3767                    self.hide_context_menu(window, cx);
 3768                }
 3769            }
 3770
 3771            hide_hover(self, cx);
 3772
 3773            if old_cursor_position.to_display_point(&display_map).row()
 3774                != new_cursor_position.to_display_point(&display_map).row()
 3775            {
 3776                self.available_code_actions.take();
 3777            }
 3778            self.refresh_code_actions(window, cx);
 3779            self.refresh_document_highlights(cx);
 3780            refresh_linked_ranges(self, window, cx);
 3781
 3782            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3783            self.refresh_matching_bracket_highlights(&display_map, cx);
 3784            self.refresh_outline_symbols_at_cursor(cx);
 3785            self.update_visible_edit_prediction(window, cx);
 3786            self.inline_blame_popover.take();
 3787            if self.git_blame_inline_enabled {
 3788                self.start_inline_blame_timer(window, cx);
 3789            }
 3790        }
 3791
 3792        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3793
 3794        if local && !self.suppress_selection_callback {
 3795            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3796                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3797                callback(cursor_position, window, cx);
 3798            }
 3799        }
 3800
 3801        cx.emit(EditorEvent::SelectionsChanged { local });
 3802
 3803        let selections = &self.selections.disjoint_anchors_arc();
 3804        if selections.len() == 1 {
 3805            cx.emit(SearchEvent::ActiveMatchChanged)
 3806        }
 3807        if local && let Some(buffer_snapshot) = buffer.as_singleton() {
 3808            let inmemory_selections = selections
 3809                .iter()
 3810                .map(|s| {
 3811                    let start = s.range().start.text_anchor_in(buffer_snapshot);
 3812                    let end = s.range().end.text_anchor_in(buffer_snapshot);
 3813                    (start..end).to_point(buffer_snapshot)
 3814                })
 3815                .collect();
 3816            self.update_restoration_data(cx, |data| {
 3817                data.selections = inmemory_selections;
 3818            });
 3819
 3820            if WorkspaceSettings::get(None, cx).restore_on_startup
 3821                != RestoreOnStartupBehavior::EmptyTab
 3822                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3823            {
 3824                let snapshot = self.buffer().read(cx).snapshot(cx);
 3825                let selections = selections.clone();
 3826                let background_executor = cx.background_executor().clone();
 3827                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3828                let db = EditorDb::global(cx);
 3829                self.serialize_selections = cx.background_spawn(async move {
 3830                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3831                    let db_selections = selections
 3832                        .iter()
 3833                        .map(|selection| {
 3834                            (
 3835                                selection.start.to_offset(&snapshot).0,
 3836                                selection.end.to_offset(&snapshot).0,
 3837                            )
 3838                        })
 3839                        .collect();
 3840
 3841                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3842                        .await
 3843                        .with_context(|| {
 3844                            format!(
 3845                                "persisting editor selections for editor {editor_id}, \
 3846                                workspace {workspace_id:?}"
 3847                            )
 3848                        })
 3849                        .log_err();
 3850                });
 3851            }
 3852        }
 3853
 3854        cx.notify();
 3855    }
 3856
 3857    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3858        use text::ToOffset as _;
 3859
 3860        if self.mode.is_minimap()
 3861            || WorkspaceSettings::get(None, cx).restore_on_startup
 3862                == RestoreOnStartupBehavior::EmptyTab
 3863        {
 3864            return;
 3865        }
 3866
 3867        let display_snapshot = self
 3868            .display_map
 3869            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3870        let Some(buffer_snapshot) = display_snapshot.buffer_snapshot().as_singleton() else {
 3871            return;
 3872        };
 3873        let inmemory_folds = display_snapshot
 3874            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3875            .map(|fold| {
 3876                let start = fold.range.start.text_anchor_in(buffer_snapshot);
 3877                let end = fold.range.end.text_anchor_in(buffer_snapshot);
 3878                (start..end).to_point(buffer_snapshot)
 3879            })
 3880            .collect();
 3881        self.update_restoration_data(cx, |data| {
 3882            data.folds = inmemory_folds;
 3883        });
 3884
 3885        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3886            return;
 3887        };
 3888
 3889        // Get file path for path-based fold storage (survives tab close)
 3890        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3891            project::File::from_dyn(buffer.read(cx).file())
 3892                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3893        }) else {
 3894            return;
 3895        };
 3896
 3897        let background_executor = cx.background_executor().clone();
 3898        const FINGERPRINT_LEN: usize = 32;
 3899        let db_folds = display_snapshot
 3900            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3901            .map(|fold| {
 3902                let start = fold
 3903                    .range
 3904                    .start
 3905                    .text_anchor_in(buffer_snapshot)
 3906                    .to_offset(buffer_snapshot);
 3907                let end = fold
 3908                    .range
 3909                    .end
 3910                    .text_anchor_in(buffer_snapshot)
 3911                    .to_offset(buffer_snapshot);
 3912
 3913                // Extract fingerprints - content at fold boundaries for validation on restore
 3914                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3915                // content that might change independently.
 3916                // start_fp: first min(32, fold_len) bytes of fold content
 3917                // end_fp: last min(32, fold_len) bytes of fold content
 3918                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3919                let fold_len = end - start;
 3920                let start_fp_end = buffer_snapshot
 3921                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3922                let start_fp: String = buffer_snapshot
 3923                    .text_for_range(start..start_fp_end)
 3924                    .collect();
 3925                let end_fp_start = buffer_snapshot
 3926                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3927                let end_fp: String = buffer_snapshot.text_for_range(end_fp_start..end).collect();
 3928
 3929                (start, end, start_fp, end_fp)
 3930            })
 3931            .collect::<Vec<_>>();
 3932        let db = EditorDb::global(cx);
 3933        self.serialize_folds = cx.background_spawn(async move {
 3934            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3935            if db_folds.is_empty() {
 3936                // No folds - delete any persisted folds for this file
 3937                db.delete_file_folds(workspace_id, file_path)
 3938                    .await
 3939                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3940                    .log_err();
 3941            } else {
 3942                db.save_file_folds(workspace_id, file_path, db_folds)
 3943                    .await
 3944                    .with_context(|| {
 3945                        format!("persisting file folds for workspace {workspace_id:?}")
 3946                    })
 3947                    .log_err();
 3948            }
 3949        });
 3950    }
 3951
 3952    pub fn sync_selections(
 3953        &mut self,
 3954        other: Entity<Editor>,
 3955        cx: &mut Context<Self>,
 3956    ) -> gpui::Subscription {
 3957        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3958        if !other_selections.is_empty() {
 3959            self.selections
 3960                .change_with(&self.display_snapshot(cx), |selections| {
 3961                    selections.select_anchors(other_selections);
 3962                });
 3963        }
 3964
 3965        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3966            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3967                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3968                if other_selections.is_empty() {
 3969                    return;
 3970                }
 3971                let snapshot = this.display_snapshot(cx);
 3972                this.selections.change_with(&snapshot, |selections| {
 3973                    selections.select_anchors(other_selections);
 3974                });
 3975            }
 3976        });
 3977
 3978        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3979            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3980                let these_selections = this.selections.disjoint_anchors().to_vec();
 3981                if these_selections.is_empty() {
 3982                    return;
 3983                }
 3984                other.update(cx, |other_editor, cx| {
 3985                    let snapshot = other_editor.display_snapshot(cx);
 3986                    other_editor
 3987                        .selections
 3988                        .change_with(&snapshot, |selections| {
 3989                            selections.select_anchors(these_selections);
 3990                        })
 3991                });
 3992            }
 3993        });
 3994
 3995        Subscription::join(other_subscription, this_subscription)
 3996    }
 3997
 3998    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3999        if self.buffer().read(cx).is_singleton() {
 4000            return;
 4001        }
 4002        let snapshot = self.buffer.read(cx).snapshot(cx);
 4003        let buffer_ids: HashSet<BufferId> = self
 4004            .selections
 4005            .disjoint_anchor_ranges()
 4006            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 4007            .collect();
 4008        for buffer_id in buffer_ids {
 4009            self.unfold_buffer(buffer_id, cx);
 4010        }
 4011    }
 4012
 4013    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 4014    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 4015    /// effects of selection change occur at the end of the transaction.
 4016    pub fn change_selections<R>(
 4017        &mut self,
 4018        effects: SelectionEffects,
 4019        window: &mut Window,
 4020        cx: &mut Context<Self>,
 4021        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 4022    ) -> R {
 4023        let snapshot = self.display_snapshot(cx);
 4024        if let Some(state) = &mut self.deferred_selection_effects_state {
 4025            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 4026            state.effects.completions = effects.completions;
 4027            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 4028            let (changed, result) = self.selections.change_with(&snapshot, change);
 4029            state.changed |= changed;
 4030            return result;
 4031        }
 4032        let mut state = DeferredSelectionEffectsState {
 4033            changed: false,
 4034            effects,
 4035            old_cursor_position: self.selections.newest_anchor().head(),
 4036            history_entry: SelectionHistoryEntry {
 4037                selections: self.selections.disjoint_anchors_arc(),
 4038                select_next_state: self.select_next_state.clone(),
 4039                select_prev_state: self.select_prev_state.clone(),
 4040                add_selections_state: self.add_selections_state.clone(),
 4041            },
 4042        };
 4043        let (changed, result) = self.selections.change_with(&snapshot, change);
 4044        state.changed = state.changed || changed;
 4045        if self.defer_selection_effects {
 4046            self.deferred_selection_effects_state = Some(state);
 4047        } else {
 4048            self.apply_selection_effects(state, window, cx);
 4049        }
 4050        result
 4051    }
 4052
 4053    /// Defers the effects of selection change, so that the effects of multiple calls to
 4054    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4055    /// to selection history and the state of popovers based on selection position aren't
 4056    /// erroneously updated.
 4057    pub fn with_selection_effects_deferred<R>(
 4058        &mut self,
 4059        window: &mut Window,
 4060        cx: &mut Context<Self>,
 4061        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4062    ) -> R {
 4063        let already_deferred = self.defer_selection_effects;
 4064        self.defer_selection_effects = true;
 4065        let result = update(self, window, cx);
 4066        if !already_deferred {
 4067            self.defer_selection_effects = false;
 4068            if let Some(state) = self.deferred_selection_effects_state.take() {
 4069                self.apply_selection_effects(state, window, cx);
 4070            }
 4071        }
 4072        result
 4073    }
 4074
 4075    fn apply_selection_effects(
 4076        &mut self,
 4077        state: DeferredSelectionEffectsState,
 4078        window: &mut Window,
 4079        cx: &mut Context<Self>,
 4080    ) {
 4081        if state.changed {
 4082            self.selection_history.push(state.history_entry);
 4083
 4084            if let Some(autoscroll) = state.effects.scroll {
 4085                self.request_autoscroll(autoscroll, cx);
 4086            }
 4087
 4088            let old_cursor_position = &state.old_cursor_position;
 4089
 4090            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4091
 4092            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4093                self.show_signature_help_auto(window, cx);
 4094            }
 4095        }
 4096    }
 4097
 4098    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4099    where
 4100        I: IntoIterator<Item = (Range<S>, T)>,
 4101        S: ToOffset,
 4102        T: Into<Arc<str>>,
 4103    {
 4104        if self.read_only(cx) {
 4105            return;
 4106        }
 4107
 4108        self.buffer
 4109            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4110    }
 4111
 4112    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4113    where
 4114        I: IntoIterator<Item = (Range<S>, T)>,
 4115        S: ToOffset,
 4116        T: Into<Arc<str>>,
 4117    {
 4118        if self.read_only(cx) {
 4119            return;
 4120        }
 4121
 4122        self.buffer.update(cx, |buffer, cx| {
 4123            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4124        });
 4125    }
 4126
 4127    pub fn edit_with_block_indent<I, S, T>(
 4128        &mut self,
 4129        edits: I,
 4130        original_indent_columns: Vec<Option<u32>>,
 4131        cx: &mut Context<Self>,
 4132    ) where
 4133        I: IntoIterator<Item = (Range<S>, T)>,
 4134        S: ToOffset,
 4135        T: Into<Arc<str>>,
 4136    {
 4137        if self.read_only(cx) {
 4138            return;
 4139        }
 4140
 4141        self.buffer.update(cx, |buffer, cx| {
 4142            buffer.edit(
 4143                edits,
 4144                Some(AutoindentMode::Block {
 4145                    original_indent_columns,
 4146                }),
 4147                cx,
 4148            )
 4149        });
 4150    }
 4151
 4152    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4153        self.hide_context_menu(window, cx);
 4154
 4155        match phase {
 4156            SelectPhase::Begin {
 4157                position,
 4158                add,
 4159                click_count,
 4160            } => self.begin_selection(position, add, click_count, window, cx),
 4161            SelectPhase::BeginColumnar {
 4162                position,
 4163                goal_column,
 4164                reset,
 4165                mode,
 4166            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4167            SelectPhase::Extend {
 4168                position,
 4169                click_count,
 4170            } => self.extend_selection(position, click_count, window, cx),
 4171            SelectPhase::Update {
 4172                position,
 4173                goal_column,
 4174                scroll_delta,
 4175            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4176            SelectPhase::End => self.end_selection(window, cx),
 4177        }
 4178    }
 4179
 4180    fn extend_selection(
 4181        &mut self,
 4182        position: DisplayPoint,
 4183        click_count: usize,
 4184        window: &mut Window,
 4185        cx: &mut Context<Self>,
 4186    ) {
 4187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4188        let tail = self
 4189            .selections
 4190            .newest::<MultiBufferOffset>(&display_map)
 4191            .tail();
 4192        let click_count = click_count.max(match self.selections.select_mode() {
 4193            SelectMode::Character => 1,
 4194            SelectMode::Word(_) => 2,
 4195            SelectMode::Line(_) => 3,
 4196            SelectMode::All => 4,
 4197        });
 4198        self.begin_selection(position, false, click_count, window, cx);
 4199
 4200        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4201
 4202        let current_selection = match self.selections.select_mode() {
 4203            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4204            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4205        };
 4206
 4207        let mut pending_selection = self
 4208            .selections
 4209            .pending_anchor()
 4210            .cloned()
 4211            .expect("extend_selection not called with pending selection");
 4212
 4213        if pending_selection
 4214            .start
 4215            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4216            == Ordering::Greater
 4217        {
 4218            pending_selection.start = current_selection.start;
 4219        }
 4220        if pending_selection
 4221            .end
 4222            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4223            == Ordering::Less
 4224        {
 4225            pending_selection.end = current_selection.end;
 4226            pending_selection.reversed = true;
 4227        }
 4228
 4229        let mut pending_mode = self.selections.pending_mode().unwrap();
 4230        match &mut pending_mode {
 4231            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4232            _ => {}
 4233        }
 4234
 4235        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4236            SelectionEffects::scroll(Autoscroll::fit())
 4237        } else {
 4238            SelectionEffects::no_scroll()
 4239        };
 4240
 4241        self.change_selections(effects, window, cx, |s| {
 4242            s.set_pending(pending_selection.clone(), pending_mode);
 4243            s.set_is_extending(true);
 4244        });
 4245    }
 4246
 4247    fn begin_selection(
 4248        &mut self,
 4249        position: DisplayPoint,
 4250        add: bool,
 4251        click_count: usize,
 4252        window: &mut Window,
 4253        cx: &mut Context<Self>,
 4254    ) {
 4255        if !self.focus_handle.is_focused(window) {
 4256            self.last_focused_descendant = None;
 4257            window.focus(&self.focus_handle, cx);
 4258        }
 4259
 4260        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4261        let buffer = display_map.buffer_snapshot();
 4262        let position = display_map.clip_point(position, Bias::Left);
 4263
 4264        let start;
 4265        let end;
 4266        let mode;
 4267        let mut auto_scroll;
 4268        match click_count {
 4269            1 => {
 4270                start = buffer.anchor_before(position.to_point(&display_map));
 4271                end = start;
 4272                mode = SelectMode::Character;
 4273                auto_scroll = true;
 4274            }
 4275            2 => {
 4276                let position = display_map
 4277                    .clip_point(position, Bias::Left)
 4278                    .to_offset(&display_map, Bias::Left);
 4279                let (range, _) = buffer.surrounding_word(position, None);
 4280                start = buffer.anchor_before(range.start);
 4281                end = buffer.anchor_before(range.end);
 4282                mode = SelectMode::Word(start..end);
 4283                auto_scroll = true;
 4284            }
 4285            3 => {
 4286                let position = display_map
 4287                    .clip_point(position, Bias::Left)
 4288                    .to_point(&display_map);
 4289                let line_start = display_map.prev_line_boundary(position).0;
 4290                let next_line_start = buffer.clip_point(
 4291                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4292                    Bias::Left,
 4293                );
 4294                start = buffer.anchor_before(line_start);
 4295                end = buffer.anchor_before(next_line_start);
 4296                mode = SelectMode::Line(start..end);
 4297                auto_scroll = true;
 4298            }
 4299            _ => {
 4300                start = buffer.anchor_before(MultiBufferOffset(0));
 4301                end = buffer.anchor_before(buffer.len());
 4302                mode = SelectMode::All;
 4303                auto_scroll = false;
 4304            }
 4305        }
 4306        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4307
 4308        let point_to_delete: Option<usize> = {
 4309            let selected_points: Vec<Selection<Point>> =
 4310                self.selections.disjoint_in_range(start..end, &display_map);
 4311
 4312            if !add || click_count > 1 {
 4313                None
 4314            } else if !selected_points.is_empty() {
 4315                Some(selected_points[0].id)
 4316            } else {
 4317                let clicked_point_already_selected =
 4318                    self.selections.disjoint_anchors().iter().find(|selection| {
 4319                        selection.start.to_point(buffer) == start.to_point(buffer)
 4320                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4321                    });
 4322
 4323                clicked_point_already_selected.map(|selection| selection.id)
 4324            }
 4325        };
 4326
 4327        let selections_count = self.selections.count();
 4328        let effects = if auto_scroll {
 4329            SelectionEffects::default()
 4330        } else {
 4331            SelectionEffects::no_scroll()
 4332        };
 4333
 4334        self.change_selections(effects, window, cx, |s| {
 4335            if let Some(point_to_delete) = point_to_delete {
 4336                s.delete(point_to_delete);
 4337
 4338                if selections_count == 1 {
 4339                    s.set_pending_anchor_range(start..end, mode);
 4340                }
 4341            } else {
 4342                if !add {
 4343                    s.clear_disjoint();
 4344                }
 4345
 4346                s.set_pending_anchor_range(start..end, mode);
 4347            }
 4348        });
 4349    }
 4350
 4351    fn begin_columnar_selection(
 4352        &mut self,
 4353        position: DisplayPoint,
 4354        goal_column: u32,
 4355        reset: bool,
 4356        mode: ColumnarMode,
 4357        window: &mut Window,
 4358        cx: &mut Context<Self>,
 4359    ) {
 4360        if !self.focus_handle.is_focused(window) {
 4361            self.last_focused_descendant = None;
 4362            window.focus(&self.focus_handle, cx);
 4363        }
 4364
 4365        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4366
 4367        if reset {
 4368            let pointer_position = display_map
 4369                .buffer_snapshot()
 4370                .anchor_before(position.to_point(&display_map));
 4371
 4372            self.change_selections(
 4373                SelectionEffects::scroll(Autoscroll::newest()),
 4374                window,
 4375                cx,
 4376                |s| {
 4377                    s.clear_disjoint();
 4378                    s.set_pending_anchor_range(
 4379                        pointer_position..pointer_position,
 4380                        SelectMode::Character,
 4381                    );
 4382                },
 4383            );
 4384        };
 4385
 4386        let tail = self.selections.newest::<Point>(&display_map).tail();
 4387        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4388        self.columnar_selection_state = match mode {
 4389            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4390                selection_tail: selection_anchor,
 4391                display_point: if reset {
 4392                    if position.column() != goal_column {
 4393                        Some(DisplayPoint::new(position.row(), goal_column))
 4394                    } else {
 4395                        None
 4396                    }
 4397                } else {
 4398                    None
 4399                },
 4400            }),
 4401            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4402                selection_tail: selection_anchor,
 4403            }),
 4404        };
 4405
 4406        if !reset {
 4407            self.select_columns(position, goal_column, &display_map, window, cx);
 4408        }
 4409    }
 4410
 4411    fn update_selection(
 4412        &mut self,
 4413        position: DisplayPoint,
 4414        goal_column: u32,
 4415        scroll_delta: gpui::Point<f32>,
 4416        window: &mut Window,
 4417        cx: &mut Context<Self>,
 4418    ) {
 4419        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4420
 4421        if self.columnar_selection_state.is_some() {
 4422            self.select_columns(position, goal_column, &display_map, window, cx);
 4423        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4424            let buffer = display_map.buffer_snapshot();
 4425            let head;
 4426            let tail;
 4427            let mode = self.selections.pending_mode().unwrap();
 4428            match &mode {
 4429                SelectMode::Character => {
 4430                    head = position.to_point(&display_map);
 4431                    tail = pending.tail().to_point(buffer);
 4432                }
 4433                SelectMode::Word(original_range) => {
 4434                    let offset = display_map
 4435                        .clip_point(position, Bias::Left)
 4436                        .to_offset(&display_map, Bias::Left);
 4437                    let original_range = original_range.to_offset(buffer);
 4438
 4439                    let head_offset = if buffer.is_inside_word(offset, None)
 4440                        || original_range.contains(&offset)
 4441                    {
 4442                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4443                        if word_range.start < original_range.start {
 4444                            word_range.start
 4445                        } else {
 4446                            word_range.end
 4447                        }
 4448                    } else {
 4449                        offset
 4450                    };
 4451
 4452                    head = head_offset.to_point(buffer);
 4453                    if head_offset <= original_range.start {
 4454                        tail = original_range.end.to_point(buffer);
 4455                    } else {
 4456                        tail = original_range.start.to_point(buffer);
 4457                    }
 4458                }
 4459                SelectMode::Line(original_range) => {
 4460                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4461
 4462                    let position = display_map
 4463                        .clip_point(position, Bias::Left)
 4464                        .to_point(&display_map);
 4465                    let line_start = display_map.prev_line_boundary(position).0;
 4466                    let next_line_start = buffer.clip_point(
 4467                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4468                        Bias::Left,
 4469                    );
 4470
 4471                    if line_start < original_range.start {
 4472                        head = line_start
 4473                    } else {
 4474                        head = next_line_start
 4475                    }
 4476
 4477                    if head <= original_range.start {
 4478                        tail = original_range.end;
 4479                    } else {
 4480                        tail = original_range.start;
 4481                    }
 4482                }
 4483                SelectMode::All => {
 4484                    return;
 4485                }
 4486            };
 4487
 4488            if head < tail {
 4489                pending.start = buffer.anchor_before(head);
 4490                pending.end = buffer.anchor_before(tail);
 4491                pending.reversed = true;
 4492            } else {
 4493                pending.start = buffer.anchor_before(tail);
 4494                pending.end = buffer.anchor_before(head);
 4495                pending.reversed = false;
 4496            }
 4497
 4498            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4499                s.set_pending(pending.clone(), mode);
 4500            });
 4501        } else {
 4502            log::error!("update_selection dispatched with no pending selection");
 4503            return;
 4504        }
 4505
 4506        self.apply_scroll_delta(scroll_delta, window, cx);
 4507        cx.notify();
 4508    }
 4509
 4510    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4511        self.columnar_selection_state.take();
 4512        if let Some(pending_mode) = self.selections.pending_mode() {
 4513            let selections = self
 4514                .selections
 4515                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4516            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4517                s.select(selections);
 4518                s.clear_pending();
 4519                if s.is_extending() {
 4520                    s.set_is_extending(false);
 4521                } else {
 4522                    s.set_select_mode(pending_mode);
 4523                }
 4524            });
 4525        }
 4526    }
 4527
 4528    fn select_columns(
 4529        &mut self,
 4530        head: DisplayPoint,
 4531        goal_column: u32,
 4532        display_map: &DisplaySnapshot,
 4533        window: &mut Window,
 4534        cx: &mut Context<Self>,
 4535    ) {
 4536        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4537            return;
 4538        };
 4539
 4540        let tail = match columnar_state {
 4541            ColumnarSelectionState::FromMouse {
 4542                selection_tail,
 4543                display_point,
 4544            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4545            ColumnarSelectionState::FromSelection { selection_tail } => {
 4546                selection_tail.to_display_point(display_map)
 4547            }
 4548        };
 4549
 4550        let start_row = cmp::min(tail.row(), head.row());
 4551        let end_row = cmp::max(tail.row(), head.row());
 4552        let start_column = cmp::min(tail.column(), goal_column);
 4553        let end_column = cmp::max(tail.column(), goal_column);
 4554        let reversed = start_column < tail.column();
 4555
 4556        let selection_ranges = (start_row.0..=end_row.0)
 4557            .map(DisplayRow)
 4558            .filter_map(|row| {
 4559                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4560                    || start_column <= display_map.line_len(row))
 4561                    && !display_map.is_block_line(row)
 4562                {
 4563                    let start = display_map
 4564                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4565                        .to_point(display_map);
 4566                    let end = display_map
 4567                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4568                        .to_point(display_map);
 4569                    if reversed {
 4570                        Some(end..start)
 4571                    } else {
 4572                        Some(start..end)
 4573                    }
 4574                } else {
 4575                    None
 4576                }
 4577            })
 4578            .collect::<Vec<_>>();
 4579        if selection_ranges.is_empty() {
 4580            return;
 4581        }
 4582
 4583        let ranges = match columnar_state {
 4584            ColumnarSelectionState::FromMouse { .. } => {
 4585                let mut non_empty_ranges = selection_ranges
 4586                    .iter()
 4587                    .filter(|selection_range| selection_range.start != selection_range.end)
 4588                    .peekable();
 4589                if non_empty_ranges.peek().is_some() {
 4590                    non_empty_ranges.cloned().collect()
 4591                } else {
 4592                    selection_ranges
 4593                }
 4594            }
 4595            _ => selection_ranges,
 4596        };
 4597
 4598        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4599            s.select_ranges(ranges);
 4600        });
 4601        cx.notify();
 4602    }
 4603
 4604    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4605        self.selections
 4606            .all_adjusted(snapshot)
 4607            .iter()
 4608            .any(|selection| !selection.is_empty())
 4609    }
 4610
 4611    pub fn has_pending_nonempty_selection(&self) -> bool {
 4612        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4613            Some(Selection { start, end, .. }) => start != end,
 4614            None => false,
 4615        };
 4616
 4617        pending_nonempty_selection
 4618            || (self.columnar_selection_state.is_some()
 4619                && self.selections.disjoint_anchors().len() > 1)
 4620    }
 4621
 4622    pub fn has_pending_selection(&self) -> bool {
 4623        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4624    }
 4625
 4626    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4627        self.selection_mark_mode = false;
 4628        self.selection_drag_state = SelectionDragState::None;
 4629
 4630        if self.dismiss_menus_and_popups(true, window, cx) {
 4631            cx.notify();
 4632            return;
 4633        }
 4634        if self.clear_expanded_diff_hunks(cx) {
 4635            cx.notify();
 4636            return;
 4637        }
 4638        if self.show_git_blame_gutter {
 4639            self.show_git_blame_gutter = false;
 4640            cx.notify();
 4641            return;
 4642        }
 4643
 4644        if self.mode.is_full()
 4645            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4646        {
 4647            cx.notify();
 4648            return;
 4649        }
 4650
 4651        cx.propagate();
 4652    }
 4653
 4654    pub fn dismiss_menus_and_popups(
 4655        &mut self,
 4656        is_user_requested: bool,
 4657        window: &mut Window,
 4658        cx: &mut Context<Self>,
 4659    ) -> bool {
 4660        let mut dismissed = false;
 4661
 4662        dismissed |= self.take_rename(false, window, cx).is_some();
 4663        dismissed |= self.hide_blame_popover(true, cx);
 4664        dismissed |= hide_hover(self, cx);
 4665        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4666        dismissed |= self.hide_context_menu(window, cx).is_some();
 4667        dismissed |= self.mouse_context_menu.take().is_some();
 4668        dismissed |= is_user_requested
 4669            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4670        dismissed |= self.snippet_stack.pop().is_some();
 4671        if self.diff_review_drag_state.is_some() {
 4672            self.cancel_diff_review_drag(cx);
 4673            dismissed = true;
 4674        }
 4675        if !self.diff_review_overlays.is_empty() {
 4676            self.dismiss_all_diff_review_overlays(cx);
 4677            dismissed = true;
 4678        }
 4679
 4680        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4681            self.dismiss_diagnostics(cx);
 4682            dismissed = true;
 4683        }
 4684
 4685        dismissed
 4686    }
 4687
 4688    fn linked_editing_ranges_for(
 4689        &self,
 4690        query_range: Range<text::Anchor>,
 4691        cx: &App,
 4692    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4693        use text::ToOffset as TO;
 4694
 4695        if self.linked_edit_ranges.is_empty() {
 4696            return None;
 4697        }
 4698        if query_range.start.buffer_id != query_range.end.buffer_id {
 4699            return None;
 4700        };
 4701        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 4702        let buffer = self.buffer.read(cx).buffer(query_range.end.buffer_id)?;
 4703        let buffer_snapshot = buffer.read(cx).snapshot();
 4704        let (base_range, linked_ranges) = self.linked_edit_ranges.get(
 4705            buffer_snapshot.remote_id(),
 4706            query_range.clone(),
 4707            &buffer_snapshot,
 4708        )?;
 4709        // find offset from the start of current range to current cursor position
 4710        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4711
 4712        let start_offset = TO::to_offset(&query_range.start, &buffer_snapshot);
 4713        let start_difference = start_offset - start_byte_offset;
 4714        let end_offset = TO::to_offset(&query_range.end, &buffer_snapshot);
 4715        let end_difference = end_offset - start_byte_offset;
 4716
 4717        // Current range has associated linked ranges.
 4718        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4719        for range in linked_ranges.iter() {
 4720            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4721            let end_offset = start_offset + end_difference;
 4722            let start_offset = start_offset + start_difference;
 4723            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4724                continue;
 4725            }
 4726            if self.selections.disjoint_anchor_ranges().any(|s| {
 4727                let Some((selection_start, _)) =
 4728                    multibuffer_snapshot.anchor_to_buffer_anchor(s.start)
 4729                else {
 4730                    return false;
 4731                };
 4732                let Some((selection_end, _)) = multibuffer_snapshot.anchor_to_buffer_anchor(s.end)
 4733                else {
 4734                    return false;
 4735                };
 4736                if selection_start.buffer_id != query_range.start.buffer_id
 4737                    || selection_end.buffer_id != query_range.end.buffer_id
 4738                {
 4739                    return false;
 4740                }
 4741                TO::to_offset(&selection_start, &buffer_snapshot) <= end_offset
 4742                    && TO::to_offset(&selection_end, &buffer_snapshot) >= start_offset
 4743            }) {
 4744                continue;
 4745            }
 4746            let start = buffer_snapshot.anchor_after(start_offset);
 4747            let end = buffer_snapshot.anchor_after(end_offset);
 4748            linked_edits
 4749                .entry(buffer.clone())
 4750                .or_default()
 4751                .push(start..end);
 4752        }
 4753        Some(linked_edits)
 4754    }
 4755
 4756    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4757        let text: Arc<str> = text.into();
 4758
 4759        if self.read_only(cx) {
 4760            return;
 4761        }
 4762
 4763        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4764
 4765        self.unfold_buffers_with_selections(cx);
 4766
 4767        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4768        let mut bracket_inserted = false;
 4769        let mut edits = Vec::new();
 4770        let mut linked_edits = LinkedEdits::new();
 4771        let mut new_selections = Vec::with_capacity(selections.len());
 4772        let mut new_autoclose_regions = Vec::new();
 4773        let snapshot = self.buffer.read(cx).read(cx);
 4774        let mut clear_linked_edit_ranges = false;
 4775        let mut all_selections_read_only = true;
 4776        let mut has_adjacent_edits = false;
 4777        let mut in_adjacent_group = false;
 4778
 4779        let mut regions = self
 4780            .selections_with_autoclose_regions(selections, &snapshot)
 4781            .peekable();
 4782
 4783        while let Some((selection, autoclose_region)) = regions.next() {
 4784            if snapshot
 4785                .point_to_buffer_point(selection.head())
 4786                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4787            {
 4788                continue;
 4789            }
 4790            if snapshot
 4791                .point_to_buffer_point(selection.tail())
 4792                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4793            {
 4794                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4795                continue;
 4796            }
 4797            all_selections_read_only = false;
 4798
 4799            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4800                // Determine if the inserted text matches the opening or closing
 4801                // bracket of any of this language's bracket pairs.
 4802                let mut bracket_pair = None;
 4803                let mut is_bracket_pair_start = false;
 4804                let mut is_bracket_pair_end = false;
 4805                if !text.is_empty() {
 4806                    let mut bracket_pair_matching_end = None;
 4807                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4808                    //  and they are removing the character that triggered IME popup.
 4809                    for (pair, enabled) in scope.brackets() {
 4810                        if !pair.close && !pair.surround {
 4811                            continue;
 4812                        }
 4813
 4814                        if enabled && pair.start.ends_with(text.as_ref()) {
 4815                            let prefix_len = pair.start.len() - text.len();
 4816                            let preceding_text_matches_prefix = prefix_len == 0
 4817                                || (selection.start.column >= (prefix_len as u32)
 4818                                    && snapshot.contains_str_at(
 4819                                        Point::new(
 4820                                            selection.start.row,
 4821                                            selection.start.column - (prefix_len as u32),
 4822                                        ),
 4823                                        &pair.start[..prefix_len],
 4824                                    ));
 4825                            if preceding_text_matches_prefix {
 4826                                bracket_pair = Some(pair.clone());
 4827                                is_bracket_pair_start = true;
 4828                                break;
 4829                            }
 4830                        }
 4831                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4832                        {
 4833                            // take first bracket pair matching end, but don't break in case a later bracket
 4834                            // pair matches start
 4835                            bracket_pair_matching_end = Some(pair.clone());
 4836                        }
 4837                    }
 4838                    if let Some(end) = bracket_pair_matching_end
 4839                        && bracket_pair.is_none()
 4840                    {
 4841                        bracket_pair = Some(end);
 4842                        is_bracket_pair_end = true;
 4843                    }
 4844                }
 4845
 4846                if let Some(bracket_pair) = bracket_pair {
 4847                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4848                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4849                    let auto_surround =
 4850                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4851                    if selection.is_empty() {
 4852                        if is_bracket_pair_start {
 4853                            // If the inserted text is a suffix of an opening bracket and the
 4854                            // selection is preceded by the rest of the opening bracket, then
 4855                            // insert the closing bracket.
 4856                            let following_text_allows_autoclose = snapshot
 4857                                .chars_at(selection.start)
 4858                                .next()
 4859                                .is_none_or(|c| scope.should_autoclose_before(c));
 4860
 4861                            let preceding_text_allows_autoclose = selection.start.column == 0
 4862                                || snapshot
 4863                                    .reversed_chars_at(selection.start)
 4864                                    .next()
 4865                                    .is_none_or(|c| {
 4866                                        bracket_pair.start != bracket_pair.end
 4867                                            || !snapshot
 4868                                                .char_classifier_at(selection.start)
 4869                                                .is_word(c)
 4870                                    });
 4871
 4872                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4873                                && bracket_pair.start.len() == 1
 4874                            {
 4875                                let target = bracket_pair.start.chars().next().unwrap();
 4876                                let mut byte_offset = 0u32;
 4877                                let current_line_count = snapshot
 4878                                    .reversed_chars_at(selection.start)
 4879                                    .take_while(|&c| c != '\n')
 4880                                    .filter(|c| {
 4881                                        byte_offset += c.len_utf8() as u32;
 4882                                        if *c != target {
 4883                                            return false;
 4884                                        }
 4885
 4886                                        let point = Point::new(
 4887                                            selection.start.row,
 4888                                            selection.start.column.saturating_sub(byte_offset),
 4889                                        );
 4890
 4891                                        let is_enabled = snapshot
 4892                                            .language_scope_at(point)
 4893                                            .and_then(|scope| {
 4894                                                scope
 4895                                                    .brackets()
 4896                                                    .find(|(pair, _)| {
 4897                                                        pair.start == bracket_pair.start
 4898                                                    })
 4899                                                    .map(|(_, enabled)| enabled)
 4900                                            })
 4901                                            .unwrap_or(true);
 4902
 4903                                        let is_delimiter = snapshot
 4904                                            .language_scope_at(Point::new(
 4905                                                point.row,
 4906                                                point.column + 1,
 4907                                            ))
 4908                                            .and_then(|scope| {
 4909                                                scope
 4910                                                    .brackets()
 4911                                                    .find(|(pair, _)| {
 4912                                                        pair.start == bracket_pair.start
 4913                                                    })
 4914                                                    .map(|(_, enabled)| !enabled)
 4915                                            })
 4916                                            .unwrap_or(false);
 4917
 4918                                        is_enabled && !is_delimiter
 4919                                    })
 4920                                    .count();
 4921                                current_line_count % 2 == 1
 4922                            } else {
 4923                                false
 4924                            };
 4925
 4926                            if autoclose
 4927                                && bracket_pair.close
 4928                                && following_text_allows_autoclose
 4929                                && preceding_text_allows_autoclose
 4930                                && !is_closing_quote
 4931                            {
 4932                                let anchor = snapshot.anchor_before(selection.end);
 4933                                new_selections.push((selection.map(|_| anchor), text.len()));
 4934                                new_autoclose_regions.push((
 4935                                    anchor,
 4936                                    text.len(),
 4937                                    selection.id,
 4938                                    bracket_pair.clone(),
 4939                                ));
 4940                                edits.push((
 4941                                    selection.range(),
 4942                                    format!("{}{}", text, bracket_pair.end).into(),
 4943                                ));
 4944                                bracket_inserted = true;
 4945                                continue;
 4946                            }
 4947                        }
 4948
 4949                        if let Some(region) = autoclose_region {
 4950                            // If the selection is followed by an auto-inserted closing bracket,
 4951                            // then don't insert that closing bracket again; just move the selection
 4952                            // past the closing bracket.
 4953                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4954                                && text.as_ref() == region.pair.end.as_str()
 4955                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4956                            if should_skip {
 4957                                let anchor = snapshot.anchor_after(selection.end);
 4958                                new_selections
 4959                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4960                                continue;
 4961                            }
 4962                        }
 4963
 4964                        let always_treat_brackets_as_autoclosed = snapshot
 4965                            .language_settings_at(selection.start, cx)
 4966                            .always_treat_brackets_as_autoclosed;
 4967                        if always_treat_brackets_as_autoclosed
 4968                            && is_bracket_pair_end
 4969                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4970                        {
 4971                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4972                            // and the inserted text is a closing bracket and the selection is followed
 4973                            // by the closing bracket then move the selection past the closing bracket.
 4974                            let anchor = snapshot.anchor_after(selection.end);
 4975                            new_selections.push((selection.map(|_| anchor), text.len()));
 4976                            continue;
 4977                        }
 4978                    }
 4979                    // If an opening bracket is 1 character long and is typed while
 4980                    // text is selected, then surround that text with the bracket pair.
 4981                    else if auto_surround
 4982                        && bracket_pair.surround
 4983                        && is_bracket_pair_start
 4984                        && bracket_pair.start.chars().count() == 1
 4985                    {
 4986                        edits.push((selection.start..selection.start, text.clone()));
 4987                        edits.push((
 4988                            selection.end..selection.end,
 4989                            bracket_pair.end.as_str().into(),
 4990                        ));
 4991                        bracket_inserted = true;
 4992                        new_selections.push((
 4993                            Selection {
 4994                                id: selection.id,
 4995                                start: snapshot.anchor_after(selection.start),
 4996                                end: snapshot.anchor_before(selection.end),
 4997                                reversed: selection.reversed,
 4998                                goal: selection.goal,
 4999                            },
 5000                            0,
 5001                        ));
 5002                        continue;
 5003                    }
 5004                }
 5005            }
 5006
 5007            if self.auto_replace_emoji_shortcode
 5008                && selection.is_empty()
 5009                && text.as_ref().ends_with(':')
 5010                && let Some(possible_emoji_short_code) =
 5011                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 5012                && !possible_emoji_short_code.is_empty()
 5013                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 5014            {
 5015                let emoji_shortcode_start = Point::new(
 5016                    selection.start.row,
 5017                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 5018                );
 5019
 5020                // Remove shortcode from buffer
 5021                edits.push((
 5022                    emoji_shortcode_start..selection.start,
 5023                    "".to_string().into(),
 5024                ));
 5025                new_selections.push((
 5026                    Selection {
 5027                        id: selection.id,
 5028                        start: snapshot.anchor_after(emoji_shortcode_start),
 5029                        end: snapshot.anchor_before(selection.start),
 5030                        reversed: selection.reversed,
 5031                        goal: selection.goal,
 5032                    },
 5033                    0,
 5034                ));
 5035
 5036                // Insert emoji
 5037                let selection_start_anchor = snapshot.anchor_after(selection.start);
 5038                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 5039                edits.push((selection.start..selection.end, emoji.to_string().into()));
 5040
 5041                continue;
 5042            }
 5043
 5044            let next_is_adjacent = regions
 5045                .peek()
 5046                .is_some_and(|(next, _)| selection.end == next.start);
 5047
 5048            // If not handling any auto-close operation, then just replace the selected
 5049            // text with the given input and move the selection to the end of the
 5050            // newly inserted text.
 5051            let anchor = if in_adjacent_group || next_is_adjacent {
 5052                // After edits the right bias would shift those anchor to the next visible fragment
 5053                // but we want to resolve to the previous one
 5054                snapshot.anchor_before(selection.end)
 5055            } else {
 5056                snapshot.anchor_after(selection.end)
 5057            };
 5058
 5059            if !self.linked_edit_ranges.is_empty() {
 5060                let start_anchor = snapshot.anchor_before(selection.start);
 5061                let classifier = snapshot
 5062                    .char_classifier_at(start_anchor)
 5063                    .scope_context(Some(CharScopeContext::LinkedEdit));
 5064
 5065                if let Some((_, anchor_range)) =
 5066                    snapshot.anchor_range_to_buffer_anchor_range(start_anchor..anchor)
 5067                {
 5068                    let is_word_char = text
 5069                        .chars()
 5070                        .next()
 5071                        .is_none_or(|char| classifier.is_word(char));
 5072
 5073                    let is_dot = text.as_ref() == ".";
 5074                    let should_apply_linked_edit = is_word_char || is_dot;
 5075
 5076                    if should_apply_linked_edit {
 5077                        linked_edits.push(&self, anchor_range, text.clone(), cx);
 5078                    } else {
 5079                        clear_linked_edit_ranges = true;
 5080                    }
 5081                }
 5082            }
 5083
 5084            new_selections.push((selection.map(|_| anchor), 0));
 5085            edits.push((selection.start..selection.end, text.clone()));
 5086
 5087            has_adjacent_edits |= next_is_adjacent;
 5088            in_adjacent_group = next_is_adjacent;
 5089        }
 5090
 5091        if all_selections_read_only {
 5092            return;
 5093        }
 5094
 5095        drop(regions);
 5096        drop(snapshot);
 5097
 5098        self.transact(window, cx, |this, window, cx| {
 5099            if clear_linked_edit_ranges {
 5100                this.linked_edit_ranges.clear();
 5101            }
 5102            let initial_buffer_versions =
 5103                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5104
 5105            this.buffer.update(cx, |buffer, cx| {
 5106                if has_adjacent_edits {
 5107                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5108                } else {
 5109                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5110                }
 5111            });
 5112            linked_edits.apply(cx);
 5113            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5114            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5115            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5116            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5117                new_anchor_selections,
 5118                &map,
 5119            )
 5120            .zip(new_selection_deltas)
 5121            .map(|(selection, delta)| Selection {
 5122                id: selection.id,
 5123                start: selection.start + delta,
 5124                end: selection.end + delta,
 5125                reversed: selection.reversed,
 5126                goal: SelectionGoal::None,
 5127            })
 5128            .collect::<Vec<_>>();
 5129
 5130            let mut i = 0;
 5131            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5132                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5133                let start = map.buffer_snapshot().anchor_before(position);
 5134                let end = map.buffer_snapshot().anchor_after(position);
 5135                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5136                    match existing_state
 5137                        .range
 5138                        .start
 5139                        .cmp(&start, map.buffer_snapshot())
 5140                    {
 5141                        Ordering::Less => i += 1,
 5142                        Ordering::Greater => break,
 5143                        Ordering::Equal => {
 5144                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5145                                Ordering::Less => i += 1,
 5146                                Ordering::Equal => break,
 5147                                Ordering::Greater => break,
 5148                            }
 5149                        }
 5150                    }
 5151                }
 5152                this.autoclose_regions.insert(
 5153                    i,
 5154                    AutocloseRegion {
 5155                        selection_id,
 5156                        range: start..end,
 5157                        pair,
 5158                    },
 5159                );
 5160            }
 5161
 5162            let had_active_edit_prediction = this.has_active_edit_prediction();
 5163            this.change_selections(
 5164                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5165                window,
 5166                cx,
 5167                |s| s.select(new_selections),
 5168            );
 5169
 5170            if !bracket_inserted
 5171                && let Some(on_type_format_task) =
 5172                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5173            {
 5174                on_type_format_task.detach_and_log_err(cx);
 5175            }
 5176
 5177            let editor_settings = EditorSettings::get_global(cx);
 5178            if bracket_inserted
 5179                && (editor_settings.auto_signature_help
 5180                    || editor_settings.show_signature_help_after_edits)
 5181            {
 5182                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5183            }
 5184
 5185            let trigger_in_words =
 5186                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5187            if this.hard_wrap.is_some() {
 5188                let latest: Range<Point> = this.selections.newest(&map).range();
 5189                if latest.is_empty()
 5190                    && this
 5191                        .buffer()
 5192                        .read(cx)
 5193                        .snapshot(cx)
 5194                        .line_len(MultiBufferRow(latest.start.row))
 5195                        == latest.start.column
 5196                {
 5197                    this.rewrap_impl(
 5198                        RewrapOptions {
 5199                            override_language_settings: true,
 5200                            preserve_existing_whitespace: true,
 5201                            line_length: None,
 5202                        },
 5203                        cx,
 5204                    )
 5205                }
 5206            }
 5207            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5208            refresh_linked_ranges(this, window, cx);
 5209            this.refresh_edit_prediction(true, false, window, cx);
 5210            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5211        });
 5212    }
 5213
 5214    fn find_possible_emoji_shortcode_at_position(
 5215        snapshot: &MultiBufferSnapshot,
 5216        position: Point,
 5217    ) -> Option<String> {
 5218        let mut chars = Vec::new();
 5219        let mut found_colon = false;
 5220        for char in snapshot.reversed_chars_at(position).take(100) {
 5221            // Found a possible emoji shortcode in the middle of the buffer
 5222            if found_colon {
 5223                if char.is_whitespace() {
 5224                    chars.reverse();
 5225                    return Some(chars.iter().collect());
 5226                }
 5227                // If the previous character is not a whitespace, we are in the middle of a word
 5228                // and we only want to complete the shortcode if the word is made up of other emojis
 5229                let mut containing_word = String::new();
 5230                for ch in snapshot
 5231                    .reversed_chars_at(position)
 5232                    .skip(chars.len() + 1)
 5233                    .take(100)
 5234                {
 5235                    if ch.is_whitespace() {
 5236                        break;
 5237                    }
 5238                    containing_word.push(ch);
 5239                }
 5240                let containing_word = containing_word.chars().rev().collect::<String>();
 5241                if util::word_consists_of_emojis(containing_word.as_str()) {
 5242                    chars.reverse();
 5243                    return Some(chars.iter().collect());
 5244                }
 5245            }
 5246
 5247            if char.is_whitespace() || !char.is_ascii() {
 5248                return None;
 5249            }
 5250            if char == ':' {
 5251                found_colon = true;
 5252            } else {
 5253                chars.push(char);
 5254            }
 5255        }
 5256        // Found a possible emoji shortcode at the beginning of the buffer
 5257        chars.reverse();
 5258        Some(chars.iter().collect())
 5259    }
 5260
 5261    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5262        if self.read_only(cx) {
 5263            return;
 5264        }
 5265
 5266        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5267        self.transact(window, cx, |this, window, cx| {
 5268            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5269                let selections = this
 5270                    .selections
 5271                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5272                let multi_buffer = this.buffer.read(cx);
 5273                let buffer = multi_buffer.snapshot(cx);
 5274                selections
 5275                    .iter()
 5276                    .map(|selection| {
 5277                        let start_point = selection.start.to_point(&buffer);
 5278                        let mut existing_indent =
 5279                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5280                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5281                        let start = selection.start;
 5282                        let end = selection.end;
 5283                        let selection_is_empty = start == end;
 5284                        let language_scope = buffer.language_scope_at(start);
 5285                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5286                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5287                                &buffer,
 5288                                start..end,
 5289                                language,
 5290                            )
 5291                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5292                                    &buffer,
 5293                                    start..end,
 5294                                );
 5295
 5296                            let mut newline_config = NewlineConfig::Newline {
 5297                                additional_indent: IndentSize::spaces(0),
 5298                                extra_line_additional_indent: if needs_extra_newline {
 5299                                    Some(IndentSize::spaces(0))
 5300                                } else {
 5301                                    None
 5302                                },
 5303                                prevent_auto_indent: false,
 5304                            };
 5305
 5306                            let comment_delimiter = maybe!({
 5307                                if !selection_is_empty {
 5308                                    return None;
 5309                                }
 5310
 5311                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5312                                    return None;
 5313                                }
 5314
 5315                                return comment_delimiter_for_newline(
 5316                                    &start_point,
 5317                                    &buffer,
 5318                                    language,
 5319                                );
 5320                            });
 5321
 5322                            let doc_delimiter = maybe!({
 5323                                if !selection_is_empty {
 5324                                    return None;
 5325                                }
 5326
 5327                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5328                                    return None;
 5329                                }
 5330
 5331                                return documentation_delimiter_for_newline(
 5332                                    &start_point,
 5333                                    &buffer,
 5334                                    language,
 5335                                    &mut newline_config,
 5336                                );
 5337                            });
 5338
 5339                            let list_delimiter = maybe!({
 5340                                if !selection_is_empty {
 5341                                    return None;
 5342                                }
 5343
 5344                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5345                                    return None;
 5346                                }
 5347
 5348                                return list_delimiter_for_newline(
 5349                                    &start_point,
 5350                                    &buffer,
 5351                                    language,
 5352                                    &mut newline_config,
 5353                                );
 5354                            });
 5355
 5356                            (
 5357                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5358                                newline_config,
 5359                            )
 5360                        } else {
 5361                            (
 5362                                None,
 5363                                NewlineConfig::Newline {
 5364                                    additional_indent: IndentSize::spaces(0),
 5365                                    extra_line_additional_indent: None,
 5366                                    prevent_auto_indent: false,
 5367                                },
 5368                            )
 5369                        };
 5370
 5371                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5372                            NewlineConfig::ClearCurrentLine => {
 5373                                let row_start =
 5374                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5375                                (row_start, String::new(), false)
 5376                            }
 5377                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5378                                let row_start =
 5379                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5380                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5381                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5382                                let reduced_indent =
 5383                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5384                                let mut new_text = String::new();
 5385                                new_text.extend(reduced_indent.chars());
 5386                                new_text.push_str(continuation);
 5387                                (row_start, new_text, true)
 5388                            }
 5389                            NewlineConfig::Newline {
 5390                                additional_indent,
 5391                                extra_line_additional_indent,
 5392                                prevent_auto_indent,
 5393                            } => {
 5394                                let auto_indent_mode =
 5395                                    buffer.language_settings_at(start, cx).auto_indent;
 5396                                let preserve_indent =
 5397                                    auto_indent_mode != language::AutoIndentMode::None;
 5398                                let apply_syntax_indent =
 5399                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5400                                let capacity_for_delimiter =
 5401                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5402                                let existing_indent_len = if preserve_indent {
 5403                                    existing_indent.len as usize
 5404                                } else {
 5405                                    0
 5406                                };
 5407                                let extra_line_len = extra_line_additional_indent
 5408                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5409                                    .unwrap_or(0);
 5410                                let mut new_text = String::with_capacity(
 5411                                    1 + capacity_for_delimiter
 5412                                        + existing_indent_len
 5413                                        + additional_indent.len as usize
 5414                                        + extra_line_len,
 5415                                );
 5416                                new_text.push('\n');
 5417                                if preserve_indent {
 5418                                    new_text.extend(existing_indent.chars());
 5419                                }
 5420                                new_text.extend(additional_indent.chars());
 5421                                if let Some(delimiter) = &delimiter {
 5422                                    new_text.push_str(delimiter);
 5423                                }
 5424                                if let Some(extra_indent) = extra_line_additional_indent {
 5425                                    new_text.push('\n');
 5426                                    if preserve_indent {
 5427                                        new_text.extend(existing_indent.chars());
 5428                                    }
 5429                                    new_text.extend(extra_indent.chars());
 5430                                }
 5431                                (
 5432                                    start,
 5433                                    new_text,
 5434                                    *prevent_auto_indent || !apply_syntax_indent,
 5435                                )
 5436                            }
 5437                        };
 5438
 5439                        let anchor = buffer.anchor_after(end);
 5440                        let new_selection = selection.map(|_| anchor);
 5441                        (
 5442                            ((edit_start..end, new_text), prevent_auto_indent),
 5443                            (newline_config.has_extra_line(), new_selection),
 5444                        )
 5445                    })
 5446                    .unzip()
 5447            };
 5448
 5449            let mut auto_indent_edits = Vec::new();
 5450            let mut edits = Vec::new();
 5451            for (edit, prevent_auto_indent) in edits_with_flags {
 5452                if prevent_auto_indent {
 5453                    edits.push(edit);
 5454                } else {
 5455                    auto_indent_edits.push(edit);
 5456                }
 5457            }
 5458            if !edits.is_empty() {
 5459                this.edit(edits, cx);
 5460            }
 5461            if !auto_indent_edits.is_empty() {
 5462                this.edit_with_autoindent(auto_indent_edits, cx);
 5463            }
 5464
 5465            let buffer = this.buffer.read(cx).snapshot(cx);
 5466            let new_selections = selection_info
 5467                .into_iter()
 5468                .map(|(extra_newline_inserted, new_selection)| {
 5469                    let mut cursor = new_selection.end.to_point(&buffer);
 5470                    if extra_newline_inserted {
 5471                        cursor.row -= 1;
 5472                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5473                    }
 5474                    new_selection.map(|_| cursor)
 5475                })
 5476                .collect();
 5477
 5478            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5479            this.refresh_edit_prediction(true, false, window, cx);
 5480            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5481                task.detach_and_log_err(cx);
 5482            }
 5483        });
 5484    }
 5485
 5486    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5487        if self.read_only(cx) {
 5488            return;
 5489        }
 5490
 5491        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5492
 5493        let buffer = self.buffer.read(cx);
 5494        let snapshot = buffer.snapshot(cx);
 5495
 5496        let mut edits = Vec::new();
 5497        let mut rows = Vec::new();
 5498
 5499        for (rows_inserted, selection) in self
 5500            .selections
 5501            .all_adjusted(&self.display_snapshot(cx))
 5502            .into_iter()
 5503            .enumerate()
 5504        {
 5505            let cursor = selection.head();
 5506            let row = cursor.row;
 5507
 5508            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5509
 5510            let newline = "\n".to_string();
 5511            edits.push((start_of_line..start_of_line, newline));
 5512
 5513            rows.push(row + rows_inserted as u32);
 5514        }
 5515
 5516        self.transact(window, cx, |editor, window, cx| {
 5517            editor.edit(edits, cx);
 5518
 5519            editor.change_selections(Default::default(), window, cx, |s| {
 5520                let mut index = 0;
 5521                s.move_cursors_with(&mut |map, _, _| {
 5522                    let row = rows[index];
 5523                    index += 1;
 5524
 5525                    let point = Point::new(row, 0);
 5526                    let boundary = map.next_line_boundary(point).1;
 5527                    let clipped = map.clip_point(boundary, Bias::Left);
 5528
 5529                    (clipped, SelectionGoal::None)
 5530                });
 5531            });
 5532
 5533            let mut indent_edits = Vec::new();
 5534            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5535            for row in rows {
 5536                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5537                for (row, indent) in indents {
 5538                    if indent.len == 0 {
 5539                        continue;
 5540                    }
 5541
 5542                    let text = match indent.kind {
 5543                        IndentKind::Space => " ".repeat(indent.len as usize),
 5544                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5545                    };
 5546                    let point = Point::new(row.0, 0);
 5547                    indent_edits.push((point..point, text));
 5548                }
 5549            }
 5550            editor.edit(indent_edits, cx);
 5551            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5552                format.detach_and_log_err(cx);
 5553            }
 5554        });
 5555    }
 5556
 5557    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5558        if self.read_only(cx) {
 5559            return;
 5560        }
 5561
 5562        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5563
 5564        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5565        let mut rows = Vec::new();
 5566        let mut rows_inserted = 0;
 5567
 5568        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5569            let cursor = selection.head();
 5570            let row = cursor.row;
 5571
 5572            let point = Point::new(row, 0);
 5573            let Some((buffer_handle, buffer_point)) =
 5574                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5575            else {
 5576                continue;
 5577            };
 5578
 5579            buffer_edits
 5580                .entry(buffer_handle.entity_id())
 5581                .or_insert_with(|| (buffer_handle, Vec::new()))
 5582                .1
 5583                .push(buffer_point);
 5584
 5585            rows_inserted += 1;
 5586            rows.push(row + rows_inserted);
 5587        }
 5588
 5589        self.transact(window, cx, |editor, window, cx| {
 5590            for (_, (buffer_handle, points)) in &buffer_edits {
 5591                buffer_handle.update(cx, |buffer, cx| {
 5592                    let edits: Vec<_> = points
 5593                        .iter()
 5594                        .map(|point| {
 5595                            let target = Point::new(point.row + 1, 0);
 5596                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5597                            (start_of_line..start_of_line, "\n")
 5598                        })
 5599                        .collect();
 5600                    buffer.edit(edits, None, cx);
 5601                });
 5602            }
 5603
 5604            editor.change_selections(Default::default(), window, cx, |s| {
 5605                let mut index = 0;
 5606                s.move_cursors_with(&mut |map, _, _| {
 5607                    let row = rows[index];
 5608                    index += 1;
 5609
 5610                    let point = Point::new(row, 0);
 5611                    let boundary = map.next_line_boundary(point).1;
 5612                    let clipped = map.clip_point(boundary, Bias::Left);
 5613
 5614                    (clipped, SelectionGoal::None)
 5615                });
 5616            });
 5617
 5618            let mut indent_edits = Vec::new();
 5619            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5620            for row in rows {
 5621                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5622                for (row, indent) in indents {
 5623                    if indent.len == 0 {
 5624                        continue;
 5625                    }
 5626
 5627                    let text = match indent.kind {
 5628                        IndentKind::Space => " ".repeat(indent.len as usize),
 5629                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5630                    };
 5631                    let point = Point::new(row.0, 0);
 5632                    indent_edits.push((point..point, text));
 5633                }
 5634            }
 5635            editor.edit(indent_edits, cx);
 5636            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5637                format.detach_and_log_err(cx);
 5638            }
 5639        });
 5640    }
 5641
 5642    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5643        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5644            original_indent_columns: Vec::new(),
 5645        });
 5646        self.replace_selections(text, autoindent, window, cx, false);
 5647    }
 5648
 5649    /// Replaces the editor's selections with the provided `text`, applying the
 5650    /// given `autoindent_mode` (`None` will skip autoindentation).
 5651    ///
 5652    /// Early returns if the editor is in read-only mode, without applying any
 5653    /// edits.
 5654    fn replace_selections(
 5655        &mut self,
 5656        text: &str,
 5657        autoindent_mode: Option<AutoindentMode>,
 5658        window: &mut Window,
 5659        cx: &mut Context<Self>,
 5660        apply_linked_edits: bool,
 5661    ) {
 5662        if self.read_only(cx) {
 5663            return;
 5664        }
 5665
 5666        let text: Arc<str> = text.into();
 5667        self.transact(window, cx, |this, window, cx| {
 5668            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5669            let linked_edits = if apply_linked_edits {
 5670                this.linked_edits_for_selections(text.clone(), cx)
 5671            } else {
 5672                LinkedEdits::new()
 5673            };
 5674
 5675            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5676                let anchors = {
 5677                    let snapshot = buffer.read(cx);
 5678                    old_selections
 5679                        .iter()
 5680                        .map(|s| {
 5681                            let anchor = snapshot.anchor_after(s.head());
 5682                            s.map(|_| anchor)
 5683                        })
 5684                        .collect::<Vec<_>>()
 5685                };
 5686                buffer.edit(
 5687                    old_selections
 5688                        .iter()
 5689                        .map(|s| (s.start..s.end, text.clone())),
 5690                    autoindent_mode,
 5691                    cx,
 5692                );
 5693                anchors
 5694            });
 5695
 5696            linked_edits.apply(cx);
 5697
 5698            this.change_selections(Default::default(), window, cx, |s| {
 5699                s.select_anchors(selection_anchors);
 5700            });
 5701
 5702            if apply_linked_edits {
 5703                refresh_linked_ranges(this, window, cx);
 5704            }
 5705
 5706            cx.notify();
 5707        });
 5708    }
 5709
 5710    /// Collects linked edits for the current selections, pairing each linked
 5711    /// range with `text`.
 5712    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5713        let multibuffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5714        let mut linked_edits = LinkedEdits::new();
 5715        if !self.linked_edit_ranges.is_empty() {
 5716            for selection in self.selections.disjoint_anchors() {
 5717                let Some((_, range)) =
 5718                    multibuffer_snapshot.anchor_range_to_buffer_anchor_range(selection.range())
 5719                else {
 5720                    continue;
 5721                };
 5722                linked_edits.push(self, range, text.clone(), cx);
 5723            }
 5724        }
 5725        linked_edits
 5726    }
 5727
 5728    /// Deletes the content covered by the current selections and applies
 5729    /// linked edits.
 5730    pub fn delete_selections_with_linked_edits(
 5731        &mut self,
 5732        window: &mut Window,
 5733        cx: &mut Context<Self>,
 5734    ) {
 5735        self.replace_selections("", None, window, cx, true);
 5736    }
 5737
 5738    #[cfg(any(test, feature = "test-support"))]
 5739    pub fn set_linked_edit_ranges_for_testing(
 5740        &mut self,
 5741        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5742        cx: &mut Context<Self>,
 5743    ) -> Option<()> {
 5744        let Some((buffer, _)) = self
 5745            .buffer
 5746            .read(cx)
 5747            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5748        else {
 5749            return None;
 5750        };
 5751        let buffer = buffer.read(cx);
 5752        let buffer_id = buffer.remote_id();
 5753        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5754        for (base_range, linked_ranges_points) in ranges {
 5755            let base_anchor =
 5756                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5757            let linked_anchors = linked_ranges_points
 5758                .into_iter()
 5759                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5760                .collect();
 5761            linked_ranges.push((base_anchor, linked_anchors));
 5762        }
 5763        let mut map = HashMap::default();
 5764        map.insert(buffer_id, linked_ranges);
 5765        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5766        Some(())
 5767    }
 5768
 5769    fn trigger_completion_on_input(
 5770        &mut self,
 5771        text: &str,
 5772        trigger_in_words: bool,
 5773        window: &mut Window,
 5774        cx: &mut Context<Self>,
 5775    ) {
 5776        let completions_source = self
 5777            .context_menu
 5778            .borrow()
 5779            .as_ref()
 5780            .and_then(|menu| match menu {
 5781                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5782                CodeContextMenu::CodeActions(_) => None,
 5783            });
 5784
 5785        match completions_source {
 5786            Some(CompletionsMenuSource::Words { .. }) => {
 5787                self.open_or_update_completions_menu(
 5788                    Some(CompletionsMenuSource::Words {
 5789                        ignore_threshold: false,
 5790                    }),
 5791                    None,
 5792                    trigger_in_words,
 5793                    window,
 5794                    cx,
 5795                );
 5796            }
 5797            _ => self.open_or_update_completions_menu(
 5798                None,
 5799                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5800                true,
 5801                window,
 5802                cx,
 5803            ),
 5804        }
 5805    }
 5806
 5807    /// If any empty selections is touching the start of its innermost containing autoclose
 5808    /// region, expand it to select the brackets.
 5809    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5810        let selections = self
 5811            .selections
 5812            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5813        let buffer = self.buffer.read(cx).read(cx);
 5814        let new_selections = self
 5815            .selections_with_autoclose_regions(selections, &buffer)
 5816            .map(|(mut selection, region)| {
 5817                if !selection.is_empty() {
 5818                    return selection;
 5819                }
 5820
 5821                if let Some(region) = region {
 5822                    let mut range = region.range.to_offset(&buffer);
 5823                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5824                        range.start -= region.pair.start.len();
 5825                        if buffer.contains_str_at(range.start, &region.pair.start)
 5826                            && buffer.contains_str_at(range.end, &region.pair.end)
 5827                        {
 5828                            range.end += region.pair.end.len();
 5829                            selection.start = range.start;
 5830                            selection.end = range.end;
 5831
 5832                            return selection;
 5833                        }
 5834                    }
 5835                }
 5836
 5837                let always_treat_brackets_as_autoclosed = buffer
 5838                    .language_settings_at(selection.start, cx)
 5839                    .always_treat_brackets_as_autoclosed;
 5840
 5841                if !always_treat_brackets_as_autoclosed {
 5842                    return selection;
 5843                }
 5844
 5845                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5846                    for (pair, enabled) in scope.brackets() {
 5847                        if !enabled || !pair.close {
 5848                            continue;
 5849                        }
 5850
 5851                        if buffer.contains_str_at(selection.start, &pair.end) {
 5852                            let pair_start_len = pair.start.len();
 5853                            if buffer.contains_str_at(
 5854                                selection.start.saturating_sub_usize(pair_start_len),
 5855                                &pair.start,
 5856                            ) {
 5857                                selection.start -= pair_start_len;
 5858                                selection.end += pair.end.len();
 5859
 5860                                return selection;
 5861                            }
 5862                        }
 5863                    }
 5864                }
 5865
 5866                selection
 5867            })
 5868            .collect();
 5869
 5870        drop(buffer);
 5871        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5872            selections.select(new_selections)
 5873        });
 5874    }
 5875
 5876    /// Iterate the given selections, and for each one, find the smallest surrounding
 5877    /// autoclose region. This uses the ordering of the selections and the autoclose
 5878    /// regions to avoid repeated comparisons.
 5879    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5880        &'a self,
 5881        selections: impl IntoIterator<Item = Selection<D>>,
 5882        buffer: &'a MultiBufferSnapshot,
 5883    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5884        let mut i = 0;
 5885        let mut regions = self.autoclose_regions.as_slice();
 5886        selections.into_iter().map(move |selection| {
 5887            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5888
 5889            let mut enclosing = None;
 5890            while let Some(pair_state) = regions.get(i) {
 5891                if pair_state.range.end.to_offset(buffer) < range.start {
 5892                    regions = &regions[i + 1..];
 5893                    i = 0;
 5894                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5895                    break;
 5896                } else {
 5897                    if pair_state.selection_id == selection.id {
 5898                        enclosing = Some(pair_state);
 5899                    }
 5900                    i += 1;
 5901                }
 5902            }
 5903
 5904            (selection, enclosing)
 5905        })
 5906    }
 5907
 5908    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5909    fn invalidate_autoclose_regions(
 5910        &mut self,
 5911        mut selections: &[Selection<Anchor>],
 5912        buffer: &MultiBufferSnapshot,
 5913    ) {
 5914        self.autoclose_regions.retain(|state| {
 5915            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5916                return false;
 5917            }
 5918
 5919            let mut i = 0;
 5920            while let Some(selection) = selections.get(i) {
 5921                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5922                    selections = &selections[1..];
 5923                    continue;
 5924                }
 5925                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5926                    break;
 5927                }
 5928                if selection.id == state.selection_id {
 5929                    return true;
 5930                } else {
 5931                    i += 1;
 5932                }
 5933            }
 5934            false
 5935        });
 5936    }
 5937
 5938    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5939        let offset = position.to_offset(buffer);
 5940        let (word_range, kind) =
 5941            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5942        if offset > word_range.start && kind == Some(CharKind::Word) {
 5943            Some(
 5944                buffer
 5945                    .text_for_range(word_range.start..offset)
 5946                    .collect::<String>(),
 5947            )
 5948        } else {
 5949            None
 5950        }
 5951    }
 5952
 5953    pub fn is_lsp_relevant(&self, file: Option<&Arc<dyn language::File>>, cx: &App) -> bool {
 5954        let Some(project) = self.project() else {
 5955            return false;
 5956        };
 5957        let Some(buffer_file) = project::File::from_dyn(file) else {
 5958            return false;
 5959        };
 5960        let Some(entry_id) = buffer_file.project_entry_id() else {
 5961            return false;
 5962        };
 5963        let project = project.read(cx);
 5964        let Some(buffer_worktree) = project.worktree_for_id(buffer_file.worktree_id(cx), cx) else {
 5965            return false;
 5966        };
 5967        let Some(worktree_entry) = buffer_worktree.read(cx).entry_for_id(entry_id) else {
 5968            return false;
 5969        };
 5970        !worktree_entry.is_ignored
 5971    }
 5972
 5973    pub fn visible_buffers(&self, cx: &mut Context<Editor>) -> Vec<Entity<Buffer>> {
 5974        let display_snapshot = self.display_snapshot(cx);
 5975        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5976        let multi_buffer = self.buffer().read(cx);
 5977        display_snapshot
 5978            .buffer_snapshot()
 5979            .range_to_buffer_ranges(visible_range)
 5980            .into_iter()
 5981            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5982            .filter_map(|(buffer_snapshot, _, _)| multi_buffer.buffer(buffer_snapshot.remote_id()))
 5983            .collect()
 5984    }
 5985
 5986    pub fn visible_buffer_ranges(
 5987        &self,
 5988        cx: &mut Context<Editor>,
 5989    ) -> Vec<(
 5990        BufferSnapshot,
 5991        Range<BufferOffset>,
 5992        ExcerptRange<text::Anchor>,
 5993    )> {
 5994        let display_snapshot = self.display_snapshot(cx);
 5995        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5996        display_snapshot
 5997            .buffer_snapshot()
 5998            .range_to_buffer_ranges(visible_range)
 5999            .into_iter()
 6000            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 6001            .collect()
 6002    }
 6003
 6004    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 6005        TextLayoutDetails {
 6006            text_system: window.text_system().clone(),
 6007            editor_style: self.style.clone().unwrap(),
 6008            rem_size: window.rem_size(),
 6009            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 6010            visible_rows: self.visible_line_count(),
 6011            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 6012        }
 6013    }
 6014
 6015    fn trigger_on_type_formatting(
 6016        &self,
 6017        input: String,
 6018        window: &mut Window,
 6019        cx: &mut Context<Self>,
 6020    ) -> Option<Task<Result<()>>> {
 6021        if input.chars().count() != 1 {
 6022            return None;
 6023        }
 6024
 6025        let project = self.project()?;
 6026        let position = self.selections.newest_anchor().head();
 6027        let (buffer, buffer_position) = self
 6028            .buffer
 6029            .read(cx)
 6030            .text_anchor_for_position(position, cx)?;
 6031
 6032        let settings = LanguageSettings::for_buffer_at(&buffer.read(cx), buffer_position, cx);
 6033        if !settings.use_on_type_format {
 6034            return None;
 6035        }
 6036
 6037        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 6038        // hence we do LSP request & edit on host side only — add formats to host's history.
 6039        let push_to_lsp_host_history = true;
 6040        // If this is not the host, append its history with new edits.
 6041        let push_to_client_history = project.read(cx).is_via_collab();
 6042
 6043        let on_type_formatting = project.update(cx, |project, cx| {
 6044            project.on_type_format(
 6045                buffer.clone(),
 6046                buffer_position,
 6047                input,
 6048                push_to_lsp_host_history,
 6049                cx,
 6050            )
 6051        });
 6052        Some(cx.spawn_in(window, async move |editor, cx| {
 6053            if let Some(transaction) = on_type_formatting.await? {
 6054                if push_to_client_history {
 6055                    buffer.update(cx, |buffer, _| {
 6056                        buffer.push_transaction(transaction, Instant::now());
 6057                        buffer.finalize_last_transaction();
 6058                    });
 6059                }
 6060                editor.update(cx, |editor, cx| {
 6061                    editor.refresh_document_highlights(cx);
 6062                })?;
 6063            }
 6064            Ok(())
 6065        }))
 6066    }
 6067
 6068    pub fn show_word_completions(
 6069        &mut self,
 6070        _: &ShowWordCompletions,
 6071        window: &mut Window,
 6072        cx: &mut Context<Self>,
 6073    ) {
 6074        self.open_or_update_completions_menu(
 6075            Some(CompletionsMenuSource::Words {
 6076                ignore_threshold: true,
 6077            }),
 6078            None,
 6079            false,
 6080            window,
 6081            cx,
 6082        );
 6083    }
 6084
 6085    pub fn show_completions(
 6086        &mut self,
 6087        _: &ShowCompletions,
 6088        window: &mut Window,
 6089        cx: &mut Context<Self>,
 6090    ) {
 6091        self.open_or_update_completions_menu(None, None, false, window, cx);
 6092    }
 6093
 6094    fn open_or_update_completions_menu(
 6095        &mut self,
 6096        requested_source: Option<CompletionsMenuSource>,
 6097        trigger: Option<String>,
 6098        trigger_in_words: bool,
 6099        window: &mut Window,
 6100        cx: &mut Context<Self>,
 6101    ) {
 6102        if self.pending_rename.is_some() {
 6103            return;
 6104        }
 6105
 6106        let completions_source = self
 6107            .context_menu
 6108            .borrow()
 6109            .as_ref()
 6110            .and_then(|menu| match menu {
 6111                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6112                CodeContextMenu::CodeActions(_) => None,
 6113            });
 6114
 6115        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6116
 6117        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6118        // inserted and selected. To handle that case, the start of the selection is used so that
 6119        // the menu starts with all choices.
 6120        let position = self
 6121            .selections
 6122            .newest_anchor()
 6123            .start
 6124            .bias_right(&multibuffer_snapshot);
 6125
 6126        if position.diff_base_anchor().is_some() {
 6127            return;
 6128        }
 6129        let multibuffer_position = multibuffer_snapshot.anchor_before(position);
 6130        let Some((buffer_position, _)) =
 6131            multibuffer_snapshot.anchor_to_buffer_anchor(multibuffer_position)
 6132        else {
 6133            return;
 6134        };
 6135        let Some(buffer) = self.buffer.read(cx).buffer(buffer_position.buffer_id) else {
 6136            return;
 6137        };
 6138        let buffer_snapshot = buffer.read(cx).snapshot();
 6139
 6140        let menu_is_open = matches!(
 6141            self.context_menu.borrow().as_ref(),
 6142            Some(CodeContextMenu::Completions(_))
 6143        );
 6144
 6145        let language = buffer_snapshot
 6146            .language_at(buffer_position)
 6147            .map(|language| language.name());
 6148        let language_settings = multibuffer_snapshot.language_settings_at(multibuffer_position, cx);
 6149        let completion_settings = language_settings.completions.clone();
 6150
 6151        let show_completions_on_input = self
 6152            .show_completions_on_input_override
 6153            .unwrap_or(language_settings.show_completions_on_input);
 6154        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6155            return;
 6156        }
 6157
 6158        let query: Option<Arc<String>> =
 6159            Self::completion_query(&multibuffer_snapshot, multibuffer_position)
 6160                .map(|query| query.into());
 6161
 6162        drop(multibuffer_snapshot);
 6163
 6164        // Hide the current completions menu when query is empty. Without this, cached
 6165        // completions from before the trigger char may be reused (#32774).
 6166        if query.is_none() && menu_is_open {
 6167            self.hide_context_menu(window, cx);
 6168        }
 6169
 6170        let mut ignore_word_threshold = false;
 6171        let provider = match requested_source {
 6172            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6173            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6174                ignore_word_threshold = ignore_threshold;
 6175                None
 6176            }
 6177            Some(CompletionsMenuSource::SnippetChoices)
 6178            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6179                log::error!("bug: SnippetChoices requested_source is not handled");
 6180                None
 6181            }
 6182        };
 6183
 6184        let sort_completions = provider
 6185            .as_ref()
 6186            .is_some_and(|provider| provider.sort_completions());
 6187
 6188        let filter_completions = provider
 6189            .as_ref()
 6190            .is_none_or(|provider| provider.filter_completions());
 6191
 6192        let was_snippets_only = matches!(
 6193            completions_source,
 6194            Some(CompletionsMenuSource::SnippetsOnly)
 6195        );
 6196
 6197        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6198            if filter_completions {
 6199                menu.filter(
 6200                    query.clone().unwrap_or_default(),
 6201                    buffer_position,
 6202                    &buffer,
 6203                    provider.clone(),
 6204                    window,
 6205                    cx,
 6206                );
 6207            }
 6208            // When `is_incomplete` is false, no need to re-query completions when the current query
 6209            // is a suffix of the initial query.
 6210            let was_complete = !menu.is_incomplete;
 6211            if was_complete && !was_snippets_only {
 6212                // If the new query is a suffix of the old query (typing more characters) and
 6213                // the previous result was complete, the existing completions can be filtered.
 6214                //
 6215                // Note that snippet completions are always complete.
 6216                let query_matches = match (&menu.initial_query, &query) {
 6217                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6218                    (None, _) => true,
 6219                    _ => false,
 6220                };
 6221                if query_matches {
 6222                    let position_matches = if menu.initial_position == position {
 6223                        true
 6224                    } else {
 6225                        let snapshot = self.buffer.read(cx).read(cx);
 6226                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6227                    };
 6228                    if position_matches {
 6229                        return;
 6230                    }
 6231                }
 6232            }
 6233        };
 6234
 6235        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6236            buffer_snapshot.surrounding_word(buffer_position, None)
 6237        {
 6238            let word_to_exclude = buffer_snapshot
 6239                .text_for_range(word_range.clone())
 6240                .collect::<String>();
 6241            (
 6242                buffer_snapshot.anchor_before(word_range.start)
 6243                    ..buffer_snapshot.anchor_after(buffer_position),
 6244                Some(word_to_exclude),
 6245            )
 6246        } else {
 6247            (buffer_position..buffer_position, None)
 6248        };
 6249
 6250        let show_completion_documentation = buffer_snapshot
 6251            .settings_at(buffer_position, cx)
 6252            .show_completion_documentation;
 6253
 6254        // The document can be large, so stay in reasonable bounds when searching for words,
 6255        // otherwise completion pop-up might be slow to appear.
 6256        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6257        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6258        let min_word_search = buffer_snapshot.clip_point(
 6259            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6260            Bias::Left,
 6261        );
 6262        let max_word_search = buffer_snapshot.clip_point(
 6263            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6264            Bias::Right,
 6265        );
 6266        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6267            ..buffer_snapshot.point_to_offset(max_word_search);
 6268
 6269        let skip_digits = query
 6270            .as_ref()
 6271            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6272
 6273        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6274            trigger.as_ref().is_none_or(|trigger| {
 6275                provider.is_completion_trigger(
 6276                    &buffer,
 6277                    buffer_position,
 6278                    trigger,
 6279                    trigger_in_words,
 6280                    cx,
 6281                )
 6282            })
 6283        });
 6284
 6285        let provider_responses = if let Some(provider) = &provider
 6286            && load_provider_completions
 6287        {
 6288            let trigger_character =
 6289                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6290            let completion_context = CompletionContext {
 6291                trigger_kind: match &trigger_character {
 6292                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6293                    None => CompletionTriggerKind::INVOKED,
 6294                },
 6295                trigger_character,
 6296            };
 6297
 6298            provider.completions(&buffer, buffer_position, completion_context, window, cx)
 6299        } else {
 6300            Task::ready(Ok(Vec::new()))
 6301        };
 6302
 6303        let load_word_completions = if !self.word_completions_enabled {
 6304            false
 6305        } else if requested_source
 6306            == Some(CompletionsMenuSource::Words {
 6307                ignore_threshold: true,
 6308            })
 6309        {
 6310            true
 6311        } else {
 6312            load_provider_completions
 6313                && completion_settings.words != WordsCompletionMode::Disabled
 6314                && (ignore_word_threshold || {
 6315                    let words_min_length = completion_settings.words_min_length;
 6316                    // check whether word has at least `words_min_length` characters
 6317                    let query_chars = query.iter().flat_map(|q| q.chars());
 6318                    query_chars.take(words_min_length).count() == words_min_length
 6319                })
 6320        };
 6321
 6322        let mut words = if load_word_completions {
 6323            cx.background_spawn({
 6324                let buffer_snapshot = buffer_snapshot.clone();
 6325                async move {
 6326                    buffer_snapshot.words_in_range(WordsQuery {
 6327                        fuzzy_contents: None,
 6328                        range: word_search_range,
 6329                        skip_digits,
 6330                    })
 6331                }
 6332            })
 6333        } else {
 6334            Task::ready(BTreeMap::default())
 6335        };
 6336
 6337        let snippets = if let Some(provider) = &provider
 6338            && provider.show_snippets()
 6339            && let Some(project) = self.project()
 6340        {
 6341            let char_classifier = buffer_snapshot
 6342                .char_classifier_at(buffer_position)
 6343                .scope_context(Some(CharScopeContext::Completion));
 6344            project.update(cx, |project, cx| {
 6345                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6346            })
 6347        } else {
 6348            Task::ready(Ok(CompletionResponse {
 6349                completions: Vec::new(),
 6350                display_options: Default::default(),
 6351                is_incomplete: false,
 6352            }))
 6353        };
 6354
 6355        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6356
 6357        let id = post_inc(&mut self.next_completion_id);
 6358        let task = cx.spawn_in(window, async move |editor, cx| {
 6359            let Ok(()) = editor.update(cx, |this, _| {
 6360                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6361            }) else {
 6362                return;
 6363            };
 6364
 6365            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6366            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6367            let mut completions = Vec::new();
 6368            let mut is_incomplete = false;
 6369            let mut display_options: Option<CompletionDisplayOptions> = None;
 6370            if let Some(provider_responses) = provider_responses.await.log_err()
 6371                && !provider_responses.is_empty()
 6372            {
 6373                for response in provider_responses {
 6374                    completions.extend(response.completions);
 6375                    is_incomplete = is_incomplete || response.is_incomplete;
 6376                    match display_options.as_mut() {
 6377                        None => {
 6378                            display_options = Some(response.display_options);
 6379                        }
 6380                        Some(options) => options.merge(&response.display_options),
 6381                    }
 6382                }
 6383                if completion_settings.words == WordsCompletionMode::Fallback {
 6384                    words = Task::ready(BTreeMap::default());
 6385                }
 6386            }
 6387            let display_options = display_options.unwrap_or_default();
 6388
 6389            let mut words = words.await;
 6390            if let Some(word_to_exclude) = &word_to_exclude {
 6391                words.remove(word_to_exclude);
 6392            }
 6393            for lsp_completion in &completions {
 6394                words.remove(&lsp_completion.new_text);
 6395            }
 6396            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6397                replace_range: word_replace_range.clone(),
 6398                new_text: word.clone(),
 6399                label: CodeLabel::plain(word, None),
 6400                match_start: None,
 6401                snippet_deduplication_key: None,
 6402                icon_path: None,
 6403                documentation: None,
 6404                source: CompletionSource::BufferWord {
 6405                    word_range,
 6406                    resolved: false,
 6407                },
 6408                insert_text_mode: Some(InsertTextMode::AS_IS),
 6409                confirm: None,
 6410            }));
 6411
 6412            completions.extend(
 6413                snippets
 6414                    .await
 6415                    .into_iter()
 6416                    .flat_map(|response| response.completions),
 6417            );
 6418
 6419            let menu = if completions.is_empty() {
 6420                None
 6421            } else {
 6422                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6423                    let languages = editor
 6424                        .workspace
 6425                        .as_ref()
 6426                        .and_then(|(workspace, _)| workspace.upgrade())
 6427                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6428                    let menu = CompletionsMenu::new(
 6429                        id,
 6430                        requested_source.unwrap_or(if load_provider_completions {
 6431                            CompletionsMenuSource::Normal
 6432                        } else {
 6433                            CompletionsMenuSource::SnippetsOnly
 6434                        }),
 6435                        sort_completions,
 6436                        show_completion_documentation,
 6437                        position,
 6438                        query.clone(),
 6439                        is_incomplete,
 6440                        buffer.clone(),
 6441                        completions.into(),
 6442                        editor
 6443                            .context_menu()
 6444                            .borrow_mut()
 6445                            .as_ref()
 6446                            .map(|menu| menu.primary_scroll_handle()),
 6447                        display_options,
 6448                        snippet_sort_order,
 6449                        languages,
 6450                        language,
 6451                        cx,
 6452                    );
 6453
 6454                    let query = if filter_completions { query } else { None };
 6455                    let matches_task = menu.do_async_filtering(
 6456                        query.unwrap_or_default(),
 6457                        buffer_position,
 6458                        &buffer,
 6459                        cx,
 6460                    );
 6461                    (menu, matches_task)
 6462                }) else {
 6463                    return;
 6464                };
 6465
 6466                let matches = matches_task.await;
 6467
 6468                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6469                    // Newer menu already set, so exit.
 6470                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6471                        editor.context_menu.borrow().as_ref()
 6472                        && prev_menu.id > id
 6473                    {
 6474                        return;
 6475                    };
 6476
 6477                    // Only valid to take prev_menu because either the new menu is immediately set
 6478                    // below, or the menu is hidden.
 6479                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6480                        editor.context_menu.borrow_mut().take()
 6481                    {
 6482                        let position_matches =
 6483                            if prev_menu.initial_position == menu.initial_position {
 6484                                true
 6485                            } else {
 6486                                let snapshot = editor.buffer.read(cx).read(cx);
 6487                                prev_menu.initial_position.to_offset(&snapshot)
 6488                                    == menu.initial_position.to_offset(&snapshot)
 6489                            };
 6490                        if position_matches {
 6491                            // Preserve markdown cache before `set_filter_results` because it will
 6492                            // try to populate the documentation cache.
 6493                            menu.preserve_markdown_cache(prev_menu);
 6494                        }
 6495                    };
 6496
 6497                    menu.set_filter_results(matches, provider, window, cx);
 6498                }) else {
 6499                    return;
 6500                };
 6501
 6502                menu.visible().then_some(menu)
 6503            };
 6504
 6505            editor
 6506                .update_in(cx, |editor, window, cx| {
 6507                    if editor.focus_handle.is_focused(window)
 6508                        && let Some(menu) = menu
 6509                    {
 6510                        *editor.context_menu.borrow_mut() =
 6511                            Some(CodeContextMenu::Completions(menu));
 6512
 6513                        crate::hover_popover::hide_hover(editor, cx);
 6514                        if editor.show_edit_predictions_in_menu() {
 6515                            editor.update_visible_edit_prediction(window, cx);
 6516                        } else {
 6517                            editor
 6518                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6519                        }
 6520
 6521                        cx.notify();
 6522                        return;
 6523                    }
 6524
 6525                    if editor.completion_tasks.len() <= 1 {
 6526                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6527                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6528                        // If it was already hidden and we don't show edit predictions in the menu,
 6529                        // we should also show the edit prediction when available.
 6530                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6531                            editor.update_visible_edit_prediction(window, cx);
 6532                        }
 6533                    }
 6534                })
 6535                .ok();
 6536        });
 6537
 6538        self.completion_tasks.push((id, task));
 6539    }
 6540
 6541    #[cfg(any(test, feature = "test-support"))]
 6542    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6543        let menu = self.context_menu.borrow();
 6544        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6545            let completions = menu.completions.borrow();
 6546            Some(completions.to_vec())
 6547        } else {
 6548            None
 6549        }
 6550    }
 6551
 6552    pub fn with_completions_menu_matching_id<R>(
 6553        &self,
 6554        id: CompletionId,
 6555        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6556    ) -> R {
 6557        let mut context_menu = self.context_menu.borrow_mut();
 6558        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6559            return f(None);
 6560        };
 6561        if completions_menu.id != id {
 6562            return f(None);
 6563        }
 6564        f(Some(completions_menu))
 6565    }
 6566
 6567    pub fn confirm_completion(
 6568        &mut self,
 6569        action: &ConfirmCompletion,
 6570        window: &mut Window,
 6571        cx: &mut Context<Self>,
 6572    ) -> Option<Task<Result<()>>> {
 6573        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6574        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6575    }
 6576
 6577    pub fn confirm_completion_insert(
 6578        &mut self,
 6579        _: &ConfirmCompletionInsert,
 6580        window: &mut Window,
 6581        cx: &mut Context<Self>,
 6582    ) -> Option<Task<Result<()>>> {
 6583        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6584        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6585    }
 6586
 6587    pub fn confirm_completion_replace(
 6588        &mut self,
 6589        _: &ConfirmCompletionReplace,
 6590        window: &mut Window,
 6591        cx: &mut Context<Self>,
 6592    ) -> Option<Task<Result<()>>> {
 6593        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6594        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6595    }
 6596
 6597    pub fn compose_completion(
 6598        &mut self,
 6599        action: &ComposeCompletion,
 6600        window: &mut Window,
 6601        cx: &mut Context<Self>,
 6602    ) -> Option<Task<Result<()>>> {
 6603        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6604        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6605    }
 6606
 6607    fn do_completion(
 6608        &mut self,
 6609        item_ix: Option<usize>,
 6610        intent: CompletionIntent,
 6611        window: &mut Window,
 6612        cx: &mut Context<Editor>,
 6613    ) -> Option<Task<Result<()>>> {
 6614        use language::ToOffset as _;
 6615
 6616        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6617        else {
 6618            return None;
 6619        };
 6620
 6621        let candidate_id = {
 6622            let entries = completions_menu.entries.borrow();
 6623            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6624            if self.show_edit_predictions_in_menu() {
 6625                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6626            }
 6627            mat.candidate_id
 6628        };
 6629
 6630        let completion = completions_menu
 6631            .completions
 6632            .borrow()
 6633            .get(candidate_id)?
 6634            .clone();
 6635        cx.stop_propagation();
 6636
 6637        let buffer_handle = completions_menu.buffer.clone();
 6638        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6639        let (initial_position, _) =
 6640            multibuffer_snapshot.anchor_to_buffer_anchor(completions_menu.initial_position)?;
 6641
 6642        let CompletionEdit {
 6643            new_text,
 6644            snippet,
 6645            replace_range,
 6646        } = process_completion_for_edit(&completion, intent, &buffer_handle, &initial_position, cx);
 6647
 6648        let buffer = buffer_handle.read(cx).snapshot();
 6649        let newest_selection = self.selections.newest_anchor();
 6650
 6651        let Some(replace_range_multibuffer) =
 6652            multibuffer_snapshot.buffer_anchor_range_to_anchor_range(replace_range.clone())
 6653        else {
 6654            return None;
 6655        };
 6656
 6657        let Some((buffer_snapshot, newest_range_buffer)) =
 6658            multibuffer_snapshot.anchor_range_to_buffer_anchor_range(newest_selection.range())
 6659        else {
 6660            return None;
 6661        };
 6662
 6663        let old_text = buffer
 6664            .text_for_range(replace_range.clone())
 6665            .collect::<String>();
 6666        let lookbehind = newest_range_buffer
 6667            .start
 6668            .to_offset(buffer_snapshot)
 6669            .saturating_sub(replace_range.start.to_offset(&buffer_snapshot));
 6670        let lookahead = replace_range
 6671            .end
 6672            .to_offset(&buffer_snapshot)
 6673            .saturating_sub(newest_range_buffer.end.to_offset(&buffer));
 6674        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6675        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6676
 6677        let selections = self
 6678            .selections
 6679            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6680        let mut ranges = Vec::new();
 6681        let mut all_commit_ranges = Vec::new();
 6682        let mut linked_edits = LinkedEdits::new();
 6683
 6684        let text: Arc<str> = new_text.clone().into();
 6685        for selection in &selections {
 6686            let range = if selection.id == newest_selection.id {
 6687                replace_range_multibuffer.clone()
 6688            } else {
 6689                let mut range = selection.range();
 6690
 6691                // if prefix is present, don't duplicate it
 6692                if multibuffer_snapshot
 6693                    .contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix)
 6694                {
 6695                    range.start = range.start.saturating_sub_usize(lookbehind);
 6696
 6697                    // if suffix is also present, mimic the newest cursor and replace it
 6698                    if selection.id != newest_selection.id
 6699                        && multibuffer_snapshot.contains_str_at(range.end, suffix)
 6700                    {
 6701                        range.end += lookahead;
 6702                    }
 6703                }
 6704                range.to_anchors(&multibuffer_snapshot)
 6705            };
 6706
 6707            ranges.push(range.clone());
 6708
 6709            let start_anchor = multibuffer_snapshot.anchor_before(range.start);
 6710            let end_anchor = multibuffer_snapshot.anchor_after(range.end);
 6711
 6712            if let Some((buffer_snapshot_2, anchor_range)) =
 6713                multibuffer_snapshot.anchor_range_to_buffer_anchor_range(start_anchor..end_anchor)
 6714                && buffer_snapshot_2.remote_id() == buffer_snapshot.remote_id()
 6715            {
 6716                all_commit_ranges.push(anchor_range.clone());
 6717                if !self.linked_edit_ranges.is_empty() {
 6718                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 6719                }
 6720            }
 6721        }
 6722
 6723        let common_prefix_len = old_text
 6724            .chars()
 6725            .zip(new_text.chars())
 6726            .take_while(|(a, b)| a == b)
 6727            .map(|(a, _)| a.len_utf8())
 6728            .sum::<usize>();
 6729
 6730        cx.emit(EditorEvent::InputHandled {
 6731            utf16_range_to_replace: None,
 6732            text: new_text[common_prefix_len..].into(),
 6733        });
 6734
 6735        let tx_id = self.transact(window, cx, |editor, window, cx| {
 6736            if let Some(mut snippet) = snippet {
 6737                snippet.text = new_text.to_string();
 6738                let offset_ranges = ranges
 6739                    .iter()
 6740                    .map(|range| range.to_offset(&multibuffer_snapshot))
 6741                    .collect::<Vec<_>>();
 6742                editor
 6743                    .insert_snippet(&offset_ranges, snippet, window, cx)
 6744                    .log_err();
 6745            } else {
 6746                editor.buffer.update(cx, |multi_buffer, cx| {
 6747                    let auto_indent = match completion.insert_text_mode {
 6748                        Some(InsertTextMode::AS_IS) => None,
 6749                        _ => editor.autoindent_mode.clone(),
 6750                    };
 6751                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6752                    multi_buffer.edit(edits, auto_indent, cx);
 6753                });
 6754            }
 6755            linked_edits.apply(cx);
 6756            editor.refresh_edit_prediction(true, false, window, cx);
 6757        });
 6758        self.invalidate_autoclose_regions(
 6759            &self.selections.disjoint_anchors_arc(),
 6760            &multibuffer_snapshot,
 6761        );
 6762
 6763        let show_new_completions_on_confirm = completion
 6764            .confirm
 6765            .as_ref()
 6766            .is_some_and(|confirm| confirm(intent, window, cx));
 6767        if show_new_completions_on_confirm {
 6768            self.open_or_update_completions_menu(None, None, false, window, cx);
 6769        }
 6770
 6771        let provider = self.completion_provider.as_ref()?;
 6772
 6773        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6774        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6775            let CompletionSource::Lsp {
 6776                lsp_completion,
 6777                server_id,
 6778                ..
 6779            } = &completion.source
 6780            else {
 6781                return None;
 6782            };
 6783            let lsp_command = lsp_completion.command.as_ref()?;
 6784            let available_commands = lsp_store
 6785                .read(cx)
 6786                .lsp_server_capabilities
 6787                .get(server_id)
 6788                .and_then(|server_capabilities| {
 6789                    server_capabilities
 6790                        .execute_command_provider
 6791                        .as_ref()
 6792                        .map(|options| options.commands.as_slice())
 6793                })?;
 6794            if available_commands.contains(&lsp_command.command) {
 6795                Some(CodeAction {
 6796                    server_id: *server_id,
 6797                    range: language::Anchor::min_min_range_for_buffer(buffer.remote_id()),
 6798                    lsp_action: LspAction::Command(lsp_command.clone()),
 6799                    resolved: false,
 6800                })
 6801            } else {
 6802                None
 6803            }
 6804        });
 6805
 6806        drop(completion);
 6807        let apply_edits = provider.apply_additional_edits_for_completion(
 6808            buffer_handle.clone(),
 6809            completions_menu.completions.clone(),
 6810            candidate_id,
 6811            true,
 6812            all_commit_ranges,
 6813            cx,
 6814        );
 6815
 6816        let editor_settings = EditorSettings::get_global(cx);
 6817        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6818            // After the code completion is finished, users often want to know what signatures are needed.
 6819            // so we should automatically call signature_help
 6820            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6821        }
 6822
 6823        Some(cx.spawn_in(window, async move |editor, cx| {
 6824            let additional_edits_tx = apply_edits.await?;
 6825
 6826            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6827                let title = command.lsp_action.title().to_owned();
 6828                let project_transaction = lsp_store
 6829                    .update(cx, |lsp_store, cx| {
 6830                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6831                    })
 6832                    .await
 6833                    .context("applying post-completion command")?;
 6834                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6835                    Self::open_project_transaction(
 6836                        &editor,
 6837                        workspace.downgrade(),
 6838                        project_transaction,
 6839                        title,
 6840                        cx,
 6841                    )
 6842                    .await?;
 6843                }
 6844            }
 6845
 6846            if let Some(tx_id) = tx_id
 6847                && let Some(additional_edits_tx) = additional_edits_tx
 6848            {
 6849                editor
 6850                    .update(cx, |editor, cx| {
 6851                        editor.buffer.update(cx, |buffer, cx| {
 6852                            buffer.merge_transactions(additional_edits_tx.id, tx_id, cx)
 6853                        });
 6854                    })
 6855                    .context("merge transactions")?;
 6856            }
 6857
 6858            Ok(())
 6859        }))
 6860    }
 6861
 6862    pub fn toggle_code_actions(
 6863        &mut self,
 6864        action: &ToggleCodeActions,
 6865        window: &mut Window,
 6866        cx: &mut Context<Self>,
 6867    ) {
 6868        let quick_launch = action.quick_launch;
 6869        let mut context_menu = self.context_menu.borrow_mut();
 6870        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6871            if code_actions.deployed_from == action.deployed_from {
 6872                // Toggle if we're selecting the same one
 6873                *context_menu = None;
 6874                cx.notify();
 6875                return;
 6876            } else {
 6877                // Otherwise, clear it and start a new one
 6878                *context_menu = None;
 6879                cx.notify();
 6880            }
 6881        }
 6882        drop(context_menu);
 6883        let snapshot = self.snapshot(window, cx);
 6884        let deployed_from = action.deployed_from.clone();
 6885        let action = action.clone();
 6886        self.completion_tasks.clear();
 6887        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6888
 6889        let multibuffer_point = match &action.deployed_from {
 6890            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6891                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6892            }
 6893            _ => self
 6894                .selections
 6895                .newest::<Point>(&snapshot.display_snapshot)
 6896                .head(),
 6897        };
 6898        let Some((buffer, buffer_row)) = snapshot
 6899            .buffer_snapshot()
 6900            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6901            .and_then(|(buffer_snapshot, range)| {
 6902                self.buffer()
 6903                    .read(cx)
 6904                    .buffer(buffer_snapshot.remote_id())
 6905                    .map(|buffer| (buffer, range.start.row))
 6906            })
 6907        else {
 6908            return;
 6909        };
 6910        let buffer_id = buffer.read(cx).remote_id();
 6911        let tasks = self
 6912            .runnables
 6913            .runnables((buffer_id, buffer_row))
 6914            .map(|t| Arc::new(t.to_owned()));
 6915
 6916        if !self.focus_handle.is_focused(window) {
 6917            return;
 6918        }
 6919        let project = self.project.clone();
 6920
 6921        let code_actions_task = match deployed_from {
 6922            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6923            _ => self.code_actions(buffer_row, window, cx),
 6924        };
 6925
 6926        let runnable_task = match deployed_from {
 6927            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6928            _ => {
 6929                let mut task_context_task = Task::ready(None);
 6930                if let Some(tasks) = &tasks
 6931                    && let Some(project) = project
 6932                {
 6933                    task_context_task =
 6934                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6935                }
 6936
 6937                cx.spawn_in(window, {
 6938                    let buffer = buffer.clone();
 6939                    async move |editor, cx| {
 6940                        let task_context = task_context_task.await;
 6941
 6942                        let resolved_tasks =
 6943                            tasks
 6944                                .zip(task_context.clone())
 6945                                .map(|(tasks, task_context)| ResolvedTasks {
 6946                                    templates: tasks.resolve(&task_context).collect(),
 6947                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6948                                        multibuffer_point.row,
 6949                                        tasks.column,
 6950                                    )),
 6951                                });
 6952                        let debug_scenarios = editor
 6953                            .update(cx, |editor, cx| {
 6954                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6955                            })?
 6956                            .await;
 6957                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6958                    }
 6959                })
 6960            }
 6961        };
 6962
 6963        cx.spawn_in(window, async move |editor, cx| {
 6964            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6965            let code_actions = code_actions_task.await;
 6966            let spawn_straight_away = quick_launch
 6967                && resolved_tasks
 6968                    .as_ref()
 6969                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6970                && code_actions
 6971                    .as_ref()
 6972                    .is_none_or(|actions| actions.is_empty())
 6973                && debug_scenarios.is_empty();
 6974
 6975            editor.update_in(cx, |editor, window, cx| {
 6976                crate::hover_popover::hide_hover(editor, cx);
 6977                let actions = CodeActionContents::new(
 6978                    resolved_tasks,
 6979                    code_actions,
 6980                    debug_scenarios,
 6981                    task_context.unwrap_or_default(),
 6982                );
 6983
 6984                // Don't show the menu if there are no actions available
 6985                if actions.is_empty() {
 6986                    cx.notify();
 6987                    return Task::ready(Ok(()));
 6988                }
 6989
 6990                *editor.context_menu.borrow_mut() =
 6991                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6992                        buffer,
 6993                        actions,
 6994                        selected_item: Default::default(),
 6995                        scroll_handle: UniformListScrollHandle::default(),
 6996                        deployed_from,
 6997                    }));
 6998                cx.notify();
 6999                if spawn_straight_away
 7000                    && let Some(task) = editor.confirm_code_action(
 7001                        &ConfirmCodeAction { item_ix: Some(0) },
 7002                        window,
 7003                        cx,
 7004                    )
 7005                {
 7006                    return task;
 7007                }
 7008
 7009                Task::ready(Ok(()))
 7010            })
 7011        })
 7012        .detach_and_log_err(cx);
 7013    }
 7014
 7015    fn debug_scenarios(
 7016        &mut self,
 7017        resolved_tasks: &Option<ResolvedTasks>,
 7018        buffer: &Entity<Buffer>,
 7019        cx: &mut App,
 7020    ) -> Task<Vec<task::DebugScenario>> {
 7021        maybe!({
 7022            let project = self.project()?;
 7023            let dap_store = project.read(cx).dap_store();
 7024            let mut scenarios = vec![];
 7025            let resolved_tasks = resolved_tasks.as_ref()?;
 7026            let buffer = buffer.read(cx);
 7027            let language = buffer.language()?;
 7028            let debug_adapter = LanguageSettings::for_buffer(&buffer, cx)
 7029                .debuggers
 7030                .first()
 7031                .map(SharedString::from)
 7032                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 7033
 7034            dap_store.update(cx, |dap_store, cx| {
 7035                for (_, task) in &resolved_tasks.templates {
 7036                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 7037                        task.original_task().clone(),
 7038                        debug_adapter.clone().into(),
 7039                        task.display_label().to_owned().into(),
 7040                        cx,
 7041                    );
 7042                    scenarios.push(maybe_scenario);
 7043                }
 7044            });
 7045            Some(cx.background_spawn(async move {
 7046                futures::future::join_all(scenarios)
 7047                    .await
 7048                    .into_iter()
 7049                    .flatten()
 7050                    .collect::<Vec<_>>()
 7051            }))
 7052        })
 7053        .unwrap_or_else(|| Task::ready(vec![]))
 7054    }
 7055
 7056    fn code_actions(
 7057        &mut self,
 7058        buffer_row: u32,
 7059        window: &mut Window,
 7060        cx: &mut Context<Self>,
 7061    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 7062        let mut task = self.code_actions_task.take();
 7063        cx.spawn_in(window, async move |editor, cx| {
 7064            while let Some(prev_task) = task {
 7065                prev_task.await.log_err();
 7066                task = editor
 7067                    .update(cx, |this, _| this.code_actions_task.take())
 7068                    .ok()?;
 7069            }
 7070
 7071            editor
 7072                .update(cx, |editor, cx| {
 7073                    editor
 7074                        .available_code_actions
 7075                        .clone()
 7076                        .and_then(|(location, code_actions)| {
 7077                            let snapshot = location.buffer.read(cx).snapshot();
 7078                            let point_range = location.range.to_point(&snapshot);
 7079                            let point_range = point_range.start.row..=point_range.end.row;
 7080                            if point_range.contains(&buffer_row) {
 7081                                Some(code_actions)
 7082                            } else {
 7083                                None
 7084                            }
 7085                        })
 7086                })
 7087                .ok()
 7088                .flatten()
 7089        })
 7090    }
 7091
 7092    pub fn confirm_code_action(
 7093        &mut self,
 7094        action: &ConfirmCodeAction,
 7095        window: &mut Window,
 7096        cx: &mut Context<Self>,
 7097    ) -> Option<Task<Result<()>>> {
 7098        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7099
 7100        let actions_menu =
 7101            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7102                menu
 7103            } else {
 7104                return None;
 7105            };
 7106
 7107        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7108        let action = actions_menu.actions.get(action_ix)?;
 7109        let title = action.label();
 7110        let buffer = actions_menu.buffer;
 7111        let workspace = self.workspace()?;
 7112
 7113        match action {
 7114            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7115                workspace.update(cx, |workspace, cx| {
 7116                    workspace.schedule_resolved_task(
 7117                        task_source_kind,
 7118                        resolved_task,
 7119                        false,
 7120                        window,
 7121                        cx,
 7122                    );
 7123
 7124                    Some(Task::ready(Ok(())))
 7125                })
 7126            }
 7127            CodeActionsItem::CodeAction { action, provider } => {
 7128                let apply_code_action =
 7129                    provider.apply_code_action(buffer, action, true, window, cx);
 7130                let workspace = workspace.downgrade();
 7131                Some(cx.spawn_in(window, async move |editor, cx| {
 7132                    let project_transaction = apply_code_action.await?;
 7133                    Self::open_project_transaction(
 7134                        &editor,
 7135                        workspace,
 7136                        project_transaction,
 7137                        title,
 7138                        cx,
 7139                    )
 7140                    .await
 7141                }))
 7142            }
 7143            CodeActionsItem::DebugScenario(scenario) => {
 7144                let context = actions_menu.actions.context.into();
 7145
 7146                workspace.update(cx, |workspace, cx| {
 7147                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7148                    workspace.start_debug_session(
 7149                        scenario,
 7150                        context,
 7151                        Some(buffer),
 7152                        None,
 7153                        window,
 7154                        cx,
 7155                    );
 7156                });
 7157                Some(Task::ready(Ok(())))
 7158            }
 7159        }
 7160    }
 7161
 7162    fn open_transaction_for_hidden_buffers(
 7163        workspace: Entity<Workspace>,
 7164        transaction: ProjectTransaction,
 7165        title: String,
 7166        window: &mut Window,
 7167        cx: &mut Context<Self>,
 7168    ) {
 7169        if transaction.0.is_empty() {
 7170            return;
 7171        }
 7172
 7173        let edited_buffers_already_open = {
 7174            let other_editors: Vec<Entity<Editor>> = workspace
 7175                .read(cx)
 7176                .panes()
 7177                .iter()
 7178                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7179                .filter(|editor| editor.entity_id() != cx.entity_id())
 7180                .collect();
 7181
 7182            transaction.0.keys().all(|buffer| {
 7183                other_editors.iter().any(|editor| {
 7184                    let multi_buffer = editor.read(cx).buffer();
 7185                    multi_buffer.read(cx).is_singleton()
 7186                        && multi_buffer
 7187                            .read(cx)
 7188                            .as_singleton()
 7189                            .map_or(false, |singleton| {
 7190                                singleton.entity_id() == buffer.entity_id()
 7191                            })
 7192                })
 7193            })
 7194        };
 7195        if !edited_buffers_already_open {
 7196            let workspace = workspace.downgrade();
 7197            cx.defer_in(window, move |_, window, cx| {
 7198                cx.spawn_in(window, async move |editor, cx| {
 7199                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7200                        .await
 7201                        .ok()
 7202                })
 7203                .detach();
 7204            });
 7205        }
 7206    }
 7207
 7208    pub async fn open_project_transaction(
 7209        editor: &WeakEntity<Editor>,
 7210        workspace: WeakEntity<Workspace>,
 7211        transaction: ProjectTransaction,
 7212        title: String,
 7213        cx: &mut AsyncWindowContext,
 7214    ) -> Result<()> {
 7215        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7216        cx.update(|_, cx| {
 7217            entries.sort_unstable_by_key(|(buffer, _)| {
 7218                buffer.read(cx).file().map(|f| f.path().clone())
 7219            });
 7220        })?;
 7221        if entries.is_empty() {
 7222            return Ok(());
 7223        }
 7224
 7225        // If the project transaction's edits are all contained within this editor, then
 7226        // avoid opening a new editor to display them.
 7227
 7228        if let [(buffer, transaction)] = &*entries {
 7229            let cursor_excerpt = editor.update(cx, |editor, cx| {
 7230                let snapshot = editor.buffer().read(cx).snapshot(cx);
 7231                let head = editor.selections.newest_anchor().head();
 7232                let (buffer_snapshot, excerpt_range) = snapshot.excerpt_containing(head..head)?;
 7233                if buffer_snapshot.remote_id() != buffer.read(cx).remote_id() {
 7234                    return None;
 7235                }
 7236                Some(excerpt_range)
 7237            })?;
 7238
 7239            if let Some(excerpt_range) = cursor_excerpt {
 7240                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7241                    let excerpt_range = excerpt_range.context.to_offset(buffer);
 7242                    buffer
 7243                        .edited_ranges_for_transaction::<usize>(transaction)
 7244                        .all(|range| {
 7245                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7246                        })
 7247                });
 7248
 7249                if all_edits_within_excerpt {
 7250                    return Ok(());
 7251                }
 7252            }
 7253        }
 7254
 7255        let mut ranges_to_highlight = Vec::new();
 7256        let excerpt_buffer = cx.new(|cx| {
 7257            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7258            for (buffer_handle, transaction) in &entries {
 7259                let edited_ranges = buffer_handle
 7260                    .read(cx)
 7261                    .edited_ranges_for_transaction::<Point>(transaction)
 7262                    .collect::<Vec<_>>();
 7263                multibuffer.set_excerpts_for_path(
 7264                    PathKey::for_buffer(buffer_handle, cx),
 7265                    buffer_handle.clone(),
 7266                    edited_ranges.clone(),
 7267                    multibuffer_context_lines(cx),
 7268                    cx,
 7269                );
 7270                let snapshot = multibuffer.snapshot(cx);
 7271                let buffer_snapshot = buffer_handle.read(cx).snapshot();
 7272                ranges_to_highlight.extend(edited_ranges.into_iter().filter_map(|range| {
 7273                    let text_range = buffer_snapshot.anchor_range_inside(range);
 7274                    let start = snapshot.anchor_in_buffer(text_range.start)?;
 7275                    let end = snapshot.anchor_in_buffer(text_range.end)?;
 7276                    Some(start..end)
 7277                }));
 7278            }
 7279            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7280            multibuffer
 7281        });
 7282
 7283        workspace.update_in(cx, |workspace, window, cx| {
 7284            let project = workspace.project().clone();
 7285            let editor =
 7286                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7287            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7288            editor.update(cx, |editor, cx| {
 7289                editor.highlight_background(
 7290                    HighlightKey::Editor,
 7291                    &ranges_to_highlight,
 7292                    |_, theme| theme.colors().editor_highlighted_line_background,
 7293                    cx,
 7294                );
 7295            });
 7296        })?;
 7297
 7298        Ok(())
 7299    }
 7300
 7301    pub fn clear_code_action_providers(&mut self) {
 7302        self.code_action_providers.clear();
 7303        self.available_code_actions.take();
 7304    }
 7305
 7306    pub fn add_code_action_provider(
 7307        &mut self,
 7308        provider: Rc<dyn CodeActionProvider>,
 7309        window: &mut Window,
 7310        cx: &mut Context<Self>,
 7311    ) {
 7312        if self
 7313            .code_action_providers
 7314            .iter()
 7315            .any(|existing_provider| existing_provider.id() == provider.id())
 7316        {
 7317            return;
 7318        }
 7319
 7320        self.code_action_providers.push(provider);
 7321        self.refresh_code_actions(window, cx);
 7322    }
 7323
 7324    pub fn remove_code_action_provider(
 7325        &mut self,
 7326        id: Arc<str>,
 7327        window: &mut Window,
 7328        cx: &mut Context<Self>,
 7329    ) {
 7330        self.code_action_providers
 7331            .retain(|provider| provider.id() != id);
 7332        self.refresh_code_actions(window, cx);
 7333    }
 7334
 7335    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7336        !self.code_action_providers.is_empty()
 7337            && EditorSettings::get_global(cx).toolbar.code_actions
 7338    }
 7339
 7340    pub fn has_available_code_actions(&self) -> bool {
 7341        self.available_code_actions
 7342            .as_ref()
 7343            .is_some_and(|(_, actions)| !actions.is_empty())
 7344    }
 7345
 7346    fn render_inline_code_actions(
 7347        &self,
 7348        icon_size: ui::IconSize,
 7349        display_row: DisplayRow,
 7350        is_active: bool,
 7351        cx: &mut Context<Self>,
 7352    ) -> AnyElement {
 7353        let show_tooltip = !self.context_menu_visible();
 7354        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7355            .icon_size(icon_size)
 7356            .shape(ui::IconButtonShape::Square)
 7357            .icon_color(ui::Color::Hidden)
 7358            .toggle_state(is_active)
 7359            .when(show_tooltip, |this| {
 7360                this.tooltip({
 7361                    let focus_handle = self.focus_handle.clone();
 7362                    move |_window, cx| {
 7363                        Tooltip::for_action_in(
 7364                            "Toggle Code Actions",
 7365                            &ToggleCodeActions {
 7366                                deployed_from: None,
 7367                                quick_launch: false,
 7368                            },
 7369                            &focus_handle,
 7370                            cx,
 7371                        )
 7372                    }
 7373                })
 7374            })
 7375            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7376                window.focus(&editor.focus_handle(cx), cx);
 7377                editor.toggle_code_actions(
 7378                    &crate::actions::ToggleCodeActions {
 7379                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7380                            display_row,
 7381                        )),
 7382                        quick_launch: false,
 7383                    },
 7384                    window,
 7385                    cx,
 7386                );
 7387            }))
 7388            .into_any_element()
 7389    }
 7390
 7391    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7392        &self.context_menu
 7393    }
 7394
 7395    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7396        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7397            cx.background_executor()
 7398                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7399                .await;
 7400
 7401            let (start_buffer, start, _, end, _newest_selection) = this
 7402                .update(cx, |this, cx| {
 7403                    let newest_selection = this.selections.newest_anchor().clone();
 7404                    if newest_selection.head().diff_base_anchor().is_some() {
 7405                        return None;
 7406                    }
 7407                    let display_snapshot = this.display_snapshot(cx);
 7408                    let newest_selection_adjusted =
 7409                        this.selections.newest_adjusted(&display_snapshot);
 7410                    let buffer = this.buffer.read(cx);
 7411
 7412                    let (start_buffer, start) =
 7413                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7414                    let (end_buffer, end) =
 7415                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7416
 7417                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7418                })?
 7419                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7420                .context(
 7421                    "Expected selection to lie in a single buffer when refreshing code actions",
 7422                )?;
 7423            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7424                let providers = this.code_action_providers.clone();
 7425                let tasks = this
 7426                    .code_action_providers
 7427                    .iter()
 7428                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7429                    .collect::<Vec<_>>();
 7430                (providers, tasks)
 7431            })?;
 7432
 7433            let mut actions = Vec::new();
 7434            for (provider, provider_actions) in
 7435                providers.into_iter().zip(future::join_all(tasks).await)
 7436            {
 7437                if let Some(provider_actions) = provider_actions.log_err() {
 7438                    actions.extend(provider_actions.into_iter().map(|action| {
 7439                        AvailableCodeAction {
 7440                            action,
 7441                            provider: provider.clone(),
 7442                        }
 7443                    }));
 7444                }
 7445            }
 7446
 7447            this.update(cx, |this, cx| {
 7448                this.available_code_actions = if actions.is_empty() {
 7449                    None
 7450                } else {
 7451                    Some((
 7452                        Location {
 7453                            buffer: start_buffer,
 7454                            range: start..end,
 7455                        },
 7456                        actions.into(),
 7457                    ))
 7458                };
 7459                cx.notify();
 7460            })
 7461        }));
 7462    }
 7463
 7464    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7465        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7466            self.show_git_blame_inline = false;
 7467
 7468            self.show_git_blame_inline_delay_task =
 7469                Some(cx.spawn_in(window, async move |this, cx| {
 7470                    cx.background_executor().timer(delay).await;
 7471
 7472                    this.update(cx, |this, cx| {
 7473                        this.show_git_blame_inline = true;
 7474                        cx.notify();
 7475                    })
 7476                    .log_err();
 7477                }));
 7478        }
 7479    }
 7480
 7481    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7482        let snapshot = self.snapshot(window, cx);
 7483        let cursor = self
 7484            .selections
 7485            .newest::<Point>(&snapshot.display_snapshot)
 7486            .head();
 7487        let Some((buffer, point)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor) else {
 7488            return;
 7489        };
 7490
 7491        if self.blame.is_none() {
 7492            self.start_git_blame(true, window, cx);
 7493        }
 7494        let Some(blame) = self.blame.as_ref() else {
 7495            return;
 7496        };
 7497
 7498        let row_info = RowInfo {
 7499            buffer_id: Some(buffer.remote_id()),
 7500            buffer_row: Some(point.row),
 7501            ..Default::default()
 7502        };
 7503        let Some((buffer, blame_entry)) = blame
 7504            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7505            .flatten()
 7506        else {
 7507            return;
 7508        };
 7509
 7510        let anchor = self.selections.newest_anchor().head();
 7511        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7512        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7513            self.show_blame_popover(
 7514                buffer,
 7515                &blame_entry,
 7516                position + last_bounds.origin,
 7517                true,
 7518                cx,
 7519            );
 7520        };
 7521    }
 7522
 7523    fn show_blame_popover(
 7524        &mut self,
 7525        buffer: BufferId,
 7526        blame_entry: &BlameEntry,
 7527        position: gpui::Point<Pixels>,
 7528        ignore_timeout: bool,
 7529        cx: &mut Context<Self>,
 7530    ) {
 7531        if let Some(state) = &mut self.inline_blame_popover {
 7532            state.hide_task.take();
 7533        } else {
 7534            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7535            let blame_entry = blame_entry.clone();
 7536            let show_task = cx.spawn(async move |editor, cx| {
 7537                if !ignore_timeout {
 7538                    cx.background_executor()
 7539                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7540                        .await;
 7541                }
 7542                editor
 7543                    .update(cx, |editor, cx| {
 7544                        editor.inline_blame_popover_show_task.take();
 7545                        let Some(blame) = editor.blame.as_ref() else {
 7546                            return;
 7547                        };
 7548                        let blame = blame.read(cx);
 7549                        let details = blame.details_for_entry(buffer, &blame_entry);
 7550                        let markdown = cx.new(|cx| {
 7551                            Markdown::new(
 7552                                details
 7553                                    .as_ref()
 7554                                    .map(|message| message.message.clone())
 7555                                    .unwrap_or_default(),
 7556                                None,
 7557                                None,
 7558                                cx,
 7559                            )
 7560                        });
 7561                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7562                            position,
 7563                            hide_task: None,
 7564                            popover_bounds: None,
 7565                            popover_state: InlineBlamePopoverState {
 7566                                scroll_handle: ScrollHandle::new(),
 7567                                commit_message: details,
 7568                                markdown,
 7569                            },
 7570                            keyboard_grace: ignore_timeout,
 7571                        });
 7572                        cx.notify();
 7573                    })
 7574                    .ok();
 7575            });
 7576            self.inline_blame_popover_show_task = Some(show_task);
 7577        }
 7578    }
 7579
 7580    pub fn has_mouse_context_menu(&self) -> bool {
 7581        self.mouse_context_menu.is_some()
 7582    }
 7583
 7584    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7585        self.inline_blame_popover_show_task.take();
 7586        if let Some(state) = &mut self.inline_blame_popover {
 7587            let hide_task = cx.spawn(async move |editor, cx| {
 7588                if !ignore_timeout {
 7589                    cx.background_executor()
 7590                        .timer(std::time::Duration::from_millis(100))
 7591                        .await;
 7592                }
 7593                editor
 7594                    .update(cx, |editor, cx| {
 7595                        editor.inline_blame_popover.take();
 7596                        cx.notify();
 7597                    })
 7598                    .ok();
 7599            });
 7600            state.hide_task = Some(hide_task);
 7601            true
 7602        } else {
 7603            false
 7604        }
 7605    }
 7606
 7607    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7608        if self.pending_rename.is_some() {
 7609            return None;
 7610        }
 7611
 7612        let provider = self.semantics_provider.clone()?;
 7613        let buffer = self.buffer.read(cx);
 7614        let newest_selection = self.selections.newest_anchor().clone();
 7615        let cursor_position = newest_selection.head();
 7616        let (cursor_buffer, cursor_buffer_position) =
 7617            buffer.text_anchor_for_position(cursor_position, cx)?;
 7618        let (tail_buffer, tail_buffer_position) =
 7619            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7620        if cursor_buffer != tail_buffer {
 7621            return None;
 7622        }
 7623
 7624        let snapshot = cursor_buffer.read(cx).snapshot();
 7625        let word_ranges = cx.background_spawn(async move {
 7626            // this might look odd to put on the background thread, but
 7627            // `surrounding_word` can be quite expensive as it calls into
 7628            // tree-sitter language scopes
 7629            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7630            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7631            (start_word_range, end_word_range)
 7632        });
 7633
 7634        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7635        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7636            let (start_word_range, end_word_range) = word_ranges.await;
 7637            if start_word_range != end_word_range {
 7638                this.update(cx, |this, cx| {
 7639                    this.document_highlights_task.take();
 7640                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7641                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7642                })
 7643                .ok();
 7644                return;
 7645            }
 7646            cx.background_executor()
 7647                .timer(Duration::from_millis(debounce))
 7648                .await;
 7649
 7650            let highlights = if let Some(highlights) = cx.update(|cx| {
 7651                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7652            }) {
 7653                highlights.await.log_err()
 7654            } else {
 7655                None
 7656            };
 7657
 7658            if let Some(highlights) = highlights {
 7659                this.update(cx, |this, cx| {
 7660                    if this.pending_rename.is_some() {
 7661                        return;
 7662                    }
 7663
 7664                    let buffer = this.buffer.read(cx);
 7665                    if buffer
 7666                        .text_anchor_for_position(cursor_position, cx)
 7667                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7668                    {
 7669                        return;
 7670                    }
 7671
 7672                    let mut write_ranges = Vec::new();
 7673                    let mut read_ranges = Vec::new();
 7674                    let multibuffer_snapshot = buffer.snapshot(cx);
 7675                    for highlight in highlights {
 7676                        for range in
 7677                            multibuffer_snapshot.buffer_range_to_excerpt_ranges(highlight.range)
 7678                        {
 7679                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7680                                write_ranges.push(range);
 7681                            } else {
 7682                                read_ranges.push(range);
 7683                            }
 7684                        }
 7685                    }
 7686
 7687                    this.highlight_background(
 7688                        HighlightKey::DocumentHighlightRead,
 7689                        &read_ranges,
 7690                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7691                        cx,
 7692                    );
 7693                    this.highlight_background(
 7694                        HighlightKey::DocumentHighlightWrite,
 7695                        &write_ranges,
 7696                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7697                        cx,
 7698                    );
 7699                    cx.notify();
 7700                })
 7701                .log_err();
 7702            }
 7703        }));
 7704        None
 7705    }
 7706
 7707    fn prepare_highlight_query_from_selection(
 7708        &mut self,
 7709        snapshot: &DisplaySnapshot,
 7710        cx: &mut Context<Editor>,
 7711    ) -> Option<(String, Range<Anchor>)> {
 7712        if matches!(self.mode, EditorMode::SingleLine) {
 7713            return None;
 7714        }
 7715        if !self.use_selection_highlight || !EditorSettings::get_global(cx).selection_highlight {
 7716            return None;
 7717        }
 7718        if self.selections.count() != 1 || self.selections.line_mode() {
 7719            return None;
 7720        }
 7721        let selection = self.selections.newest::<Point>(&snapshot);
 7722        // If the selection spans multiple rows OR it is empty
 7723        if selection.start.row != selection.end.row
 7724            || selection.start.column == selection.end.column
 7725        {
 7726            return None;
 7727        }
 7728        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7729        let query = snapshot
 7730            .buffer_snapshot()
 7731            .text_for_range(selection_anchor_range.clone())
 7732            .collect::<String>();
 7733        if query.trim().is_empty() {
 7734            return None;
 7735        }
 7736        Some((query, selection_anchor_range))
 7737    }
 7738
 7739    #[ztracing::instrument(skip_all)]
 7740    fn update_selection_occurrence_highlights(
 7741        &mut self,
 7742        multi_buffer_snapshot: MultiBufferSnapshot,
 7743        query_text: String,
 7744        query_range: Range<Anchor>,
 7745        multi_buffer_range_to_query: Range<Point>,
 7746        use_debounce: bool,
 7747        window: &mut Window,
 7748        cx: &mut Context<Editor>,
 7749    ) -> Task<()> {
 7750        cx.spawn_in(window, async move |editor, cx| {
 7751            if use_debounce {
 7752                cx.background_executor()
 7753                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7754                    .await;
 7755            }
 7756            let match_task = cx.background_spawn(async move {
 7757                let buffer_ranges = multi_buffer_snapshot
 7758                    .range_to_buffer_ranges(
 7759                        multi_buffer_range_to_query.start..multi_buffer_range_to_query.end,
 7760                    )
 7761                    .into_iter()
 7762                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7763                let mut match_ranges = Vec::new();
 7764                let Ok(regex) = project::search::SearchQuery::text(
 7765                    query_text,
 7766                    false,
 7767                    false,
 7768                    false,
 7769                    Default::default(),
 7770                    Default::default(),
 7771                    false,
 7772                    None,
 7773                ) else {
 7774                    return Vec::default();
 7775                };
 7776                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7777                for (buffer_snapshot, search_range, _) in buffer_ranges {
 7778                    match_ranges.extend(
 7779                        regex
 7780                            .search(
 7781                                &buffer_snapshot,
 7782                                Some(search_range.start.0..search_range.end.0),
 7783                            )
 7784                            .await
 7785                            .into_iter()
 7786                            .filter_map(|match_range| {
 7787                                let match_start = buffer_snapshot
 7788                                    .anchor_after(search_range.start + match_range.start);
 7789                                let match_end = buffer_snapshot
 7790                                    .anchor_before(search_range.start + match_range.end);
 7791                                {
 7792                                    let range = multi_buffer_snapshot
 7793                                        .anchor_in_buffer(match_start)?
 7794                                        ..multi_buffer_snapshot.anchor_in_buffer(match_end)?;
 7795                                    Some(range).filter(|match_anchor_range| {
 7796                                        match_anchor_range != &query_range
 7797                                    })
 7798                                }
 7799                            }),
 7800                    );
 7801                }
 7802                match_ranges
 7803            });
 7804            let match_ranges = match_task.await;
 7805            editor
 7806                .update_in(cx, |editor, _, cx| {
 7807                    if use_debounce {
 7808                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7809                        editor.debounced_selection_highlight_complete = true;
 7810                    } else if editor.debounced_selection_highlight_complete {
 7811                        return;
 7812                    }
 7813                    if !match_ranges.is_empty() {
 7814                        editor.highlight_background(
 7815                            HighlightKey::SelectedTextHighlight,
 7816                            &match_ranges,
 7817                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7818                            cx,
 7819                        )
 7820                    }
 7821                })
 7822                .log_err();
 7823        })
 7824    }
 7825
 7826    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7827        struct NewlineFold;
 7828        let type_id = std::any::TypeId::of::<NewlineFold>();
 7829        if !self.mode.is_single_line() {
 7830            return;
 7831        }
 7832        let snapshot = self.snapshot(window, cx);
 7833        if snapshot.buffer_snapshot().max_point().row == 0 {
 7834            return;
 7835        }
 7836        let task = cx.background_spawn(async move {
 7837            let new_newlines = snapshot
 7838                .buffer_chars_at(MultiBufferOffset(0))
 7839                .filter_map(|(c, i)| {
 7840                    if c == '\n' {
 7841                        Some(
 7842                            snapshot.buffer_snapshot().anchor_after(i)
 7843                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7844                        )
 7845                    } else {
 7846                        None
 7847                    }
 7848                })
 7849                .collect::<Vec<_>>();
 7850            let existing_newlines = snapshot
 7851                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7852                .filter_map(|fold| {
 7853                    if fold.placeholder.type_tag == Some(type_id) {
 7854                        Some(fold.range.start..fold.range.end)
 7855                    } else {
 7856                        None
 7857                    }
 7858                })
 7859                .collect::<Vec<_>>();
 7860
 7861            (new_newlines, existing_newlines)
 7862        });
 7863        self.folding_newlines = cx.spawn(async move |this, cx| {
 7864            let (new_newlines, existing_newlines) = task.await;
 7865            if new_newlines == existing_newlines {
 7866                return;
 7867            }
 7868            let placeholder = FoldPlaceholder {
 7869                render: Arc::new(move |_, _, cx| {
 7870                    div()
 7871                        .bg(cx.theme().status().hint_background)
 7872                        .border_b_1()
 7873                        .size_full()
 7874                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7875                        .border_color(cx.theme().status().hint)
 7876                        .child("\\n")
 7877                        .into_any()
 7878                }),
 7879                constrain_width: false,
 7880                merge_adjacent: false,
 7881                type_tag: Some(type_id),
 7882                collapsed_text: None,
 7883            };
 7884            let creases = new_newlines
 7885                .into_iter()
 7886                .map(|range| Crease::simple(range, placeholder.clone()))
 7887                .collect();
 7888            this.update(cx, |this, cx| {
 7889                this.display_map.update(cx, |display_map, cx| {
 7890                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7891                    display_map.fold(creases, cx);
 7892                });
 7893            })
 7894            .ok();
 7895        });
 7896    }
 7897
 7898    #[ztracing::instrument(skip_all)]
 7899    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7900        if !self.lsp_data_enabled() {
 7901            return;
 7902        }
 7903        let cursor = self.selections.newest_anchor().head();
 7904        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7905
 7906        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7907            self.outline_symbols_at_cursor =
 7908                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7909            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7910            cx.notify();
 7911        } else {
 7912            let syntax = cx.theme().syntax().clone();
 7913            let background_task = cx.background_spawn(async move {
 7914                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7915            });
 7916            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7917                cx.spawn(async move |this, cx| {
 7918                    let symbols = background_task.await;
 7919                    this.update(cx, |this, cx| {
 7920                        this.outline_symbols_at_cursor = symbols;
 7921                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7922                        cx.notify();
 7923                    })
 7924                    .ok();
 7925                });
 7926        }
 7927    }
 7928
 7929    #[ztracing::instrument(skip_all)]
 7930    fn refresh_selected_text_highlights(
 7931        &mut self,
 7932        snapshot: &DisplaySnapshot,
 7933        on_buffer_edit: bool,
 7934        window: &mut Window,
 7935        cx: &mut Context<Editor>,
 7936    ) {
 7937        let Some((query_text, query_range)) =
 7938            self.prepare_highlight_query_from_selection(snapshot, cx)
 7939        else {
 7940            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7941            self.quick_selection_highlight_task.take();
 7942            self.debounced_selection_highlight_task.take();
 7943            self.debounced_selection_highlight_complete = false;
 7944            return;
 7945        };
 7946        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7947        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7948        let query_changed = self
 7949            .quick_selection_highlight_task
 7950            .as_ref()
 7951            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7952        if query_changed {
 7953            self.debounced_selection_highlight_complete = false;
 7954        }
 7955        if on_buffer_edit || query_changed {
 7956            self.quick_selection_highlight_task = Some((
 7957                query_range.clone(),
 7958                self.update_selection_occurrence_highlights(
 7959                    snapshot.buffer.clone(),
 7960                    query_text.clone(),
 7961                    query_range.clone(),
 7962                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7963                    false,
 7964                    window,
 7965                    cx,
 7966                ),
 7967            ));
 7968        }
 7969        if on_buffer_edit
 7970            || self
 7971                .debounced_selection_highlight_task
 7972                .as_ref()
 7973                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7974        {
 7975            let multi_buffer_start = multi_buffer_snapshot
 7976                .anchor_before(MultiBufferOffset(0))
 7977                .to_point(&multi_buffer_snapshot);
 7978            let multi_buffer_end = multi_buffer_snapshot
 7979                .anchor_after(multi_buffer_snapshot.len())
 7980                .to_point(&multi_buffer_snapshot);
 7981            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7982            self.debounced_selection_highlight_task = Some((
 7983                query_range.clone(),
 7984                self.update_selection_occurrence_highlights(
 7985                    snapshot.buffer.clone(),
 7986                    query_text,
 7987                    query_range,
 7988                    multi_buffer_full_range,
 7989                    true,
 7990                    window,
 7991                    cx,
 7992                ),
 7993            ));
 7994        }
 7995    }
 7996
 7997    pub fn multi_buffer_visible_range(
 7998        &self,
 7999        display_snapshot: &DisplaySnapshot,
 8000        cx: &App,
 8001    ) -> Range<Point> {
 8002        let visible_start = self
 8003            .scroll_manager
 8004            .native_anchor(display_snapshot, cx)
 8005            .anchor
 8006            .to_point(display_snapshot.buffer_snapshot())
 8007            .to_display_point(display_snapshot);
 8008
 8009        let mut target_end = visible_start;
 8010        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 8011
 8012        visible_start.to_point(display_snapshot)
 8013            ..display_snapshot
 8014                .clip_point(target_end, Bias::Right)
 8015                .to_point(display_snapshot)
 8016    }
 8017
 8018    pub fn refresh_edit_prediction(
 8019        &mut self,
 8020        debounce: bool,
 8021        user_requested: bool,
 8022        window: &mut Window,
 8023        cx: &mut Context<Self>,
 8024    ) -> Option<()> {
 8025        if self.leader_id.is_some() {
 8026            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8027            return None;
 8028        }
 8029
 8030        let cursor = self.selections.newest_anchor().head();
 8031        let (buffer, cursor_buffer_position) =
 8032            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8033
 8034        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8035            return None;
 8036        }
 8037
 8038        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 8039            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8040            return None;
 8041        }
 8042
 8043        self.update_visible_edit_prediction(window, cx);
 8044
 8045        if !user_requested
 8046            && (!self.should_show_edit_predictions()
 8047                || !self.is_focused(window)
 8048                || buffer.read(cx).is_empty())
 8049        {
 8050            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8051            return None;
 8052        }
 8053
 8054        self.edit_prediction_provider()?
 8055            .refresh(buffer, cursor_buffer_position, debounce, cx);
 8056        Some(())
 8057    }
 8058
 8059    fn show_edit_predictions_in_menu(&self) -> bool {
 8060        match self.edit_prediction_settings {
 8061            EditPredictionSettings::Disabled => false,
 8062            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8063        }
 8064    }
 8065
 8066    pub fn edit_predictions_enabled(&self) -> bool {
 8067        match self.edit_prediction_settings {
 8068            EditPredictionSettings::Disabled => false,
 8069            EditPredictionSettings::Enabled { .. } => true,
 8070        }
 8071    }
 8072
 8073    fn edit_prediction_requires_modifier(&self) -> bool {
 8074        match self.edit_prediction_settings {
 8075            EditPredictionSettings::Disabled => false,
 8076            EditPredictionSettings::Enabled {
 8077                preview_requires_modifier,
 8078                ..
 8079            } => preview_requires_modifier,
 8080        }
 8081    }
 8082
 8083    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8084        if self.edit_prediction_provider.is_none() {
 8085            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8086            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8087            return;
 8088        }
 8089
 8090        let selection = self.selections.newest_anchor();
 8091        let cursor = selection.head();
 8092
 8093        if let Some((buffer, cursor_buffer_position)) =
 8094            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8095        {
 8096            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8097                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8098                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8099                return;
 8100            }
 8101            self.edit_prediction_settings =
 8102                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8103        }
 8104    }
 8105
 8106    fn edit_prediction_settings_at_position(
 8107        &self,
 8108        buffer: &Entity<Buffer>,
 8109        buffer_position: language::Anchor,
 8110        cx: &App,
 8111    ) -> EditPredictionSettings {
 8112        if !self.mode.is_full()
 8113            || !self.show_edit_predictions_override.unwrap_or(true)
 8114            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8115        {
 8116            return EditPredictionSettings::Disabled;
 8117        }
 8118
 8119        if !LanguageSettings::for_buffer(&buffer.read(cx), cx).show_edit_predictions {
 8120            return EditPredictionSettings::Disabled;
 8121        };
 8122
 8123        let by_provider = matches!(
 8124            self.menu_edit_predictions_policy,
 8125            MenuEditPredictionsPolicy::ByProvider
 8126        );
 8127
 8128        let show_in_menu = by_provider
 8129            && self
 8130                .edit_prediction_provider
 8131                .as_ref()
 8132                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8133
 8134        let file = buffer.read(cx).file();
 8135        let preview_requires_modifier =
 8136            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8137
 8138        EditPredictionSettings::Enabled {
 8139            show_in_menu,
 8140            preview_requires_modifier,
 8141        }
 8142    }
 8143
 8144    fn should_show_edit_predictions(&self) -> bool {
 8145        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8146    }
 8147
 8148    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8149        matches!(
 8150            self.edit_prediction_preview,
 8151            EditPredictionPreview::Active { .. }
 8152        )
 8153    }
 8154
 8155    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8156        let cursor = self.selections.newest_anchor().head();
 8157        if let Some((buffer, cursor_position)) =
 8158            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8159        {
 8160            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8161        } else {
 8162            false
 8163        }
 8164    }
 8165
 8166    pub fn supports_minimap(&self, cx: &App) -> bool {
 8167        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8168    }
 8169
 8170    fn edit_predictions_enabled_in_buffer(
 8171        &self,
 8172        buffer: &Entity<Buffer>,
 8173        buffer_position: language::Anchor,
 8174        cx: &App,
 8175    ) -> bool {
 8176        maybe!({
 8177            if self.read_only(cx) || self.leader_id.is_some() {
 8178                return Some(false);
 8179            }
 8180            let provider = self.edit_prediction_provider()?;
 8181            if !provider.is_enabled(buffer, buffer_position, cx) {
 8182                return Some(false);
 8183            }
 8184            let buffer = buffer.read(cx);
 8185            let Some(file) = buffer.file() else {
 8186                return Some(true);
 8187            };
 8188            let settings = all_language_settings(Some(file), cx);
 8189            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8190        })
 8191        .unwrap_or(false)
 8192    }
 8193
 8194    pub fn show_edit_prediction(
 8195        &mut self,
 8196        _: &ShowEditPrediction,
 8197        window: &mut Window,
 8198        cx: &mut Context<Self>,
 8199    ) {
 8200        if !self.has_active_edit_prediction() {
 8201            self.refresh_edit_prediction(false, true, window, cx);
 8202            return;
 8203        }
 8204
 8205        self.update_visible_edit_prediction(window, cx);
 8206    }
 8207
 8208    pub fn display_cursor_names(
 8209        &mut self,
 8210        _: &DisplayCursorNames,
 8211        window: &mut Window,
 8212        cx: &mut Context<Self>,
 8213    ) {
 8214        self.show_cursor_names(window, cx);
 8215    }
 8216
 8217    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8218        self.show_cursor_names = true;
 8219        cx.notify();
 8220        cx.spawn_in(window, async move |this, cx| {
 8221            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8222            this.update(cx, |this, cx| {
 8223                this.show_cursor_names = false;
 8224                cx.notify()
 8225            })
 8226            .ok()
 8227        })
 8228        .detach();
 8229    }
 8230
 8231    pub fn accept_partial_edit_prediction(
 8232        &mut self,
 8233        granularity: EditPredictionGranularity,
 8234        window: &mut Window,
 8235        cx: &mut Context<Self>,
 8236    ) {
 8237        if self.show_edit_predictions_in_menu() {
 8238            self.hide_context_menu(window, cx);
 8239        }
 8240
 8241        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8242            return;
 8243        };
 8244
 8245        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8246            return;
 8247        }
 8248
 8249        match &active_edit_prediction.completion {
 8250            EditPrediction::MoveWithin { target, .. } => {
 8251                let target = *target;
 8252
 8253                if matches!(granularity, EditPredictionGranularity::Full) {
 8254                    if let Some(position_map) = &self.last_position_map {
 8255                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8256                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8257
 8258                        if is_visible || !self.edit_prediction_requires_modifier() {
 8259                            self.unfold_ranges(&[target..target], true, false, cx);
 8260                            self.change_selections(
 8261                                SelectionEffects::scroll(Autoscroll::newest()),
 8262                                window,
 8263                                cx,
 8264                                |selections| {
 8265                                    selections.select_anchor_ranges([target..target]);
 8266                                },
 8267                            );
 8268                            self.clear_row_highlights::<EditPredictionPreview>();
 8269                            self.edit_prediction_preview
 8270                                .set_previous_scroll_position(None);
 8271                        } else {
 8272                            // Highlight and request scroll
 8273                            self.edit_prediction_preview
 8274                                .set_previous_scroll_position(Some(
 8275                                    position_map.snapshot.scroll_anchor,
 8276                                ));
 8277                            self.highlight_rows::<EditPredictionPreview>(
 8278                                target..target,
 8279                                cx.theme().colors().editor_highlighted_line_background,
 8280                                RowHighlightOptions {
 8281                                    autoscroll: true,
 8282                                    ..Default::default()
 8283                                },
 8284                                cx,
 8285                            );
 8286                            self.request_autoscroll(Autoscroll::fit(), cx);
 8287                        }
 8288                    }
 8289                } else {
 8290                    self.change_selections(
 8291                        SelectionEffects::scroll(Autoscroll::newest()),
 8292                        window,
 8293                        cx,
 8294                        |selections| {
 8295                            selections.select_anchor_ranges([target..target]);
 8296                        },
 8297                    );
 8298                }
 8299            }
 8300            EditPrediction::MoveOutside { snapshot, target } => {
 8301                if let Some(workspace) = self.workspace() {
 8302                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8303                        .detach_and_log_err(cx);
 8304                }
 8305            }
 8306            EditPrediction::Edit {
 8307                edits,
 8308                cursor_position,
 8309                ..
 8310            } => {
 8311                self.report_edit_prediction_event(
 8312                    active_edit_prediction.completion_id.clone(),
 8313                    true,
 8314                    cx,
 8315                );
 8316
 8317                match granularity {
 8318                    EditPredictionGranularity::Full => {
 8319                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8320
 8321                        // Compute fallback cursor position BEFORE applying the edit,
 8322                        // so the anchor tracks through the edit correctly
 8323                        let fallback_cursor_target = {
 8324                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8325                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8326                        };
 8327
 8328                        self.buffer.update(cx, |buffer, cx| {
 8329                            buffer.edit(edits.iter().cloned(), None, cx)
 8330                        });
 8331
 8332                        if let Some(provider) = self.edit_prediction_provider() {
 8333                            provider.accept(cx);
 8334                        }
 8335
 8336                        // Resolve cursor position after the edit is applied
 8337                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8338                            // The anchor tracks through the edit, then we add the offset
 8339                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8340                            let base_offset = anchor.to_offset(&snapshot).0;
 8341                            let target_offset =
 8342                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8343                            snapshot.anchor_after(target_offset)
 8344                        } else {
 8345                            fallback_cursor_target
 8346                        };
 8347
 8348                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8349                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8350                        });
 8351
 8352                        let selections = self.selections.disjoint_anchors_arc();
 8353                        if let Some(transaction_id_now) =
 8354                            self.buffer.read(cx).last_transaction_id(cx)
 8355                        {
 8356                            if transaction_id_prev != Some(transaction_id_now) {
 8357                                self.selection_history
 8358                                    .insert_transaction(transaction_id_now, selections);
 8359                            }
 8360                        }
 8361
 8362                        self.update_visible_edit_prediction(window, cx);
 8363                        if self.active_edit_prediction.is_none() {
 8364                            self.refresh_edit_prediction(true, true, window, cx);
 8365                        }
 8366                        cx.notify();
 8367                    }
 8368                    _ => {
 8369                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8370                        let cursor_offset = self
 8371                            .selections
 8372                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8373                            .head();
 8374
 8375                        let insertion = edits.iter().find_map(|(range, text)| {
 8376                            let range = range.to_offset(&snapshot);
 8377                            if range.is_empty() && range.start == cursor_offset {
 8378                                Some(text)
 8379                            } else {
 8380                                None
 8381                            }
 8382                        });
 8383
 8384                        if let Some(text) = insertion {
 8385                            let text_to_insert = match granularity {
 8386                                EditPredictionGranularity::Word => {
 8387                                    let mut partial = text
 8388                                        .chars()
 8389                                        .by_ref()
 8390                                        .take_while(|c| c.is_alphabetic())
 8391                                        .collect::<String>();
 8392                                    if partial.is_empty() {
 8393                                        partial = text
 8394                                            .chars()
 8395                                            .by_ref()
 8396                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8397                                            .collect::<String>();
 8398                                    }
 8399                                    partial
 8400                                }
 8401                                EditPredictionGranularity::Line => {
 8402                                    if let Some(line) = text.split_inclusive('\n').next() {
 8403                                        line.to_string()
 8404                                    } else {
 8405                                        text.to_string()
 8406                                    }
 8407                                }
 8408                                EditPredictionGranularity::Full => unreachable!(),
 8409                            };
 8410
 8411                            cx.emit(EditorEvent::InputHandled {
 8412                                utf16_range_to_replace: None,
 8413                                text: text_to_insert.clone().into(),
 8414                            });
 8415
 8416                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8417                            self.refresh_edit_prediction(true, true, window, cx);
 8418                            cx.notify();
 8419                        } else {
 8420                            self.accept_partial_edit_prediction(
 8421                                EditPredictionGranularity::Full,
 8422                                window,
 8423                                cx,
 8424                            );
 8425                        }
 8426                    }
 8427                }
 8428            }
 8429        }
 8430    }
 8431
 8432    pub fn accept_next_word_edit_prediction(
 8433        &mut self,
 8434        _: &AcceptNextWordEditPrediction,
 8435        window: &mut Window,
 8436        cx: &mut Context<Self>,
 8437    ) {
 8438        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8439    }
 8440
 8441    pub fn accept_next_line_edit_prediction(
 8442        &mut self,
 8443        _: &AcceptNextLineEditPrediction,
 8444        window: &mut Window,
 8445        cx: &mut Context<Self>,
 8446    ) {
 8447        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8448    }
 8449
 8450    pub fn accept_edit_prediction(
 8451        &mut self,
 8452        _: &AcceptEditPrediction,
 8453        window: &mut Window,
 8454        cx: &mut Context<Self>,
 8455    ) {
 8456        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8457    }
 8458
 8459    fn discard_edit_prediction(
 8460        &mut self,
 8461        reason: EditPredictionDiscardReason,
 8462        cx: &mut Context<Self>,
 8463    ) -> bool {
 8464        if reason == EditPredictionDiscardReason::Rejected {
 8465            let completion_id = self
 8466                .active_edit_prediction
 8467                .as_ref()
 8468                .and_then(|active_completion| active_completion.completion_id.clone());
 8469
 8470            self.report_edit_prediction_event(completion_id, false, cx);
 8471        }
 8472
 8473        if let Some(provider) = self.edit_prediction_provider() {
 8474            provider.discard(reason, cx);
 8475        }
 8476
 8477        self.take_active_edit_prediction(reason == EditPredictionDiscardReason::Ignored, cx)
 8478    }
 8479
 8480    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8481        let Some(provider) = self.edit_prediction_provider() else {
 8482            return;
 8483        };
 8484
 8485        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 8486        let Some((position, _)) =
 8487            buffer_snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())
 8488        else {
 8489            return;
 8490        };
 8491        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
 8492            return;
 8493        };
 8494
 8495        let extension = buffer
 8496            .read(cx)
 8497            .file()
 8498            .and_then(|file| Some(file.path().extension()?.to_string()));
 8499
 8500        let event_type = match accepted {
 8501            true => "Edit Prediction Accepted",
 8502            false => "Edit Prediction Discarded",
 8503        };
 8504        telemetry::event!(
 8505            event_type,
 8506            provider = provider.name(),
 8507            prediction_id = id,
 8508            suggestion_accepted = accepted,
 8509            file_extension = extension,
 8510        );
 8511    }
 8512
 8513    fn open_editor_at_anchor(
 8514        snapshot: &language::BufferSnapshot,
 8515        target: language::Anchor,
 8516        workspace: &Entity<Workspace>,
 8517        window: &mut Window,
 8518        cx: &mut App,
 8519    ) -> Task<Result<()>> {
 8520        workspace.update(cx, |workspace, cx| {
 8521            let path = snapshot.file().map(|file| file.full_path(cx));
 8522            let Some(path) =
 8523                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8524            else {
 8525                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8526            };
 8527            let target = text::ToPoint::to_point(&target, snapshot);
 8528            let item = workspace.open_path(path, None, true, window, cx);
 8529            window.spawn(cx, async move |cx| {
 8530                let Some(editor) = item.await?.downcast::<Editor>() else {
 8531                    return Ok(());
 8532                };
 8533                editor
 8534                    .update_in(cx, |editor, window, cx| {
 8535                        editor.go_to_singleton_buffer_point(target, window, cx);
 8536                    })
 8537                    .ok();
 8538                anyhow::Ok(())
 8539            })
 8540        })
 8541    }
 8542
 8543    pub fn has_active_edit_prediction(&self) -> bool {
 8544        self.active_edit_prediction.is_some()
 8545    }
 8546
 8547    fn take_active_edit_prediction(
 8548        &mut self,
 8549        preserve_stale_in_menu: bool,
 8550        cx: &mut Context<Self>,
 8551    ) -> bool {
 8552        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8553            if !preserve_stale_in_menu {
 8554                self.stale_edit_prediction_in_menu = None;
 8555            }
 8556            return false;
 8557        };
 8558
 8559        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8560        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8561        self.stale_edit_prediction_in_menu =
 8562            preserve_stale_in_menu.then_some(active_edit_prediction);
 8563        true
 8564    }
 8565
 8566    /// Returns true when we're displaying the edit prediction popover below the cursor
 8567    /// like we are not previewing and the LSP autocomplete menu is visible
 8568    /// or we are in `when_holding_modifier` mode.
 8569    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8570        if self.edit_prediction_preview_is_active()
 8571            || !self.show_edit_predictions_in_menu()
 8572            || !self.edit_predictions_enabled()
 8573        {
 8574            return false;
 8575        }
 8576
 8577        if self.has_visible_completions_menu() {
 8578            return true;
 8579        }
 8580
 8581        has_completion && self.edit_prediction_requires_modifier()
 8582    }
 8583
 8584    fn handle_modifiers_changed(
 8585        &mut self,
 8586        modifiers: Modifiers,
 8587        position_map: &PositionMap,
 8588        window: &mut Window,
 8589        cx: &mut Context<Self>,
 8590    ) {
 8591        self.update_edit_prediction_settings(cx);
 8592
 8593        // Ensure that the edit prediction preview is updated, even when not
 8594        // enabled, if there's an active edit prediction preview.
 8595        if self.show_edit_predictions_in_menu()
 8596            || self.edit_prediction_requires_modifier()
 8597            || matches!(
 8598                self.edit_prediction_preview,
 8599                EditPredictionPreview::Active { .. }
 8600            )
 8601        {
 8602            self.update_edit_prediction_preview(&modifiers, window, cx);
 8603        }
 8604
 8605        self.update_selection_mode(&modifiers, position_map, window, cx);
 8606
 8607        let mouse_position = window.mouse_position();
 8608        if !position_map.text_hitbox.is_hovered(window) {
 8609            return;
 8610        }
 8611
 8612        self.update_hovered_link(
 8613            position_map.point_for_position(mouse_position),
 8614            Some(mouse_position),
 8615            &position_map.snapshot,
 8616            modifiers,
 8617            window,
 8618            cx,
 8619        )
 8620    }
 8621
 8622    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8623        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8624            MultiCursorModifier::Alt => modifiers.secondary(),
 8625            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8626        }
 8627    }
 8628
 8629    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8630        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8631            MultiCursorModifier::Alt => modifiers.alt,
 8632            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8633        }
 8634    }
 8635
 8636    fn columnar_selection_mode(
 8637        modifiers: &Modifiers,
 8638        cx: &mut Context<Self>,
 8639    ) -> Option<ColumnarMode> {
 8640        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8641            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8642                Some(ColumnarMode::FromMouse)
 8643            } else if Self::is_alt_pressed(modifiers, cx) {
 8644                Some(ColumnarMode::FromSelection)
 8645            } else {
 8646                None
 8647            }
 8648        } else {
 8649            None
 8650        }
 8651    }
 8652
 8653    fn update_selection_mode(
 8654        &mut self,
 8655        modifiers: &Modifiers,
 8656        position_map: &PositionMap,
 8657        window: &mut Window,
 8658        cx: &mut Context<Self>,
 8659    ) {
 8660        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8661            return;
 8662        };
 8663        if self.selections.pending_anchor().is_none() {
 8664            return;
 8665        }
 8666
 8667        let mouse_position = window.mouse_position();
 8668        let point_for_position = position_map.point_for_position(mouse_position);
 8669        let position = point_for_position.previous_valid;
 8670
 8671        self.select(
 8672            SelectPhase::BeginColumnar {
 8673                position,
 8674                reset: false,
 8675                mode,
 8676                goal_column: point_for_position.exact_unclipped.column(),
 8677            },
 8678            window,
 8679            cx,
 8680        );
 8681    }
 8682
 8683    fn update_edit_prediction_preview(
 8684        &mut self,
 8685        modifiers: &Modifiers,
 8686        window: &mut Window,
 8687        cx: &mut Context<Self>,
 8688    ) {
 8689        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8690
 8691        if modifiers_held {
 8692            if matches!(
 8693                self.edit_prediction_preview,
 8694                EditPredictionPreview::Inactive { .. }
 8695            ) {
 8696                self.edit_prediction_preview = EditPredictionPreview::Active {
 8697                    previous_scroll_position: None,
 8698                    since: Instant::now(),
 8699                };
 8700
 8701                self.update_visible_edit_prediction(window, cx);
 8702                cx.notify();
 8703            }
 8704        } else if let EditPredictionPreview::Active {
 8705            previous_scroll_position,
 8706            since,
 8707        } = self.edit_prediction_preview
 8708        {
 8709            if let (Some(previous_scroll_position), Some(position_map)) =
 8710                (previous_scroll_position, self.last_position_map.as_ref())
 8711            {
 8712                self.set_scroll_position(
 8713                    previous_scroll_position
 8714                        .scroll_position(&position_map.snapshot.display_snapshot),
 8715                    window,
 8716                    cx,
 8717                );
 8718            }
 8719
 8720            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8721                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8722            };
 8723            self.clear_row_highlights::<EditPredictionPreview>();
 8724            self.update_visible_edit_prediction(window, cx);
 8725            cx.notify();
 8726        }
 8727    }
 8728
 8729    fn update_visible_edit_prediction(
 8730        &mut self,
 8731        _window: &mut Window,
 8732        cx: &mut Context<Self>,
 8733    ) -> Option<()> {
 8734        if self.ime_transaction.is_some() {
 8735            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8736            return None;
 8737        }
 8738
 8739        let selection = self.selections.newest_anchor();
 8740        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8741        let cursor = selection.head();
 8742        let (cursor_text_anchor, _) = multibuffer.anchor_to_buffer_anchor(cursor)?;
 8743        let buffer = self.buffer.read(cx).buffer(cursor_text_anchor.buffer_id)?;
 8744
 8745        // Check project-level disable_ai setting for the current buffer
 8746        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8747            return None;
 8748        }
 8749        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8750
 8751        let show_in_menu = self.show_edit_predictions_in_menu();
 8752        let completions_menu_has_precedence = !show_in_menu
 8753            && (self.context_menu.borrow().is_some()
 8754                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8755
 8756        if completions_menu_has_precedence
 8757            || !offset_selection.is_empty()
 8758            || self
 8759                .active_edit_prediction
 8760                .as_ref()
 8761                .is_some_and(|completion| {
 8762                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8763                        return false;
 8764                    };
 8765                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8766                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8767                    !invalidation_range.contains(&offset_selection.head())
 8768                })
 8769        {
 8770            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8771            return None;
 8772        }
 8773
 8774        self.take_active_edit_prediction(true, cx);
 8775        let Some(provider) = self.edit_prediction_provider() else {
 8776            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8777            return None;
 8778        };
 8779
 8780        self.edit_prediction_settings =
 8781            self.edit_prediction_settings_at_position(&buffer, cursor_text_anchor, cx);
 8782
 8783        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8784
 8785        if self.in_leading_whitespace {
 8786            let cursor_point = cursor.to_point(&multibuffer);
 8787            let mut suggested_indent = None;
 8788            multibuffer.suggested_indents_callback(
 8789                cursor_point.row..cursor_point.row + 1,
 8790                &mut |_, indent| {
 8791                    suggested_indent = Some(indent);
 8792                    ControlFlow::Break(())
 8793                },
 8794                cx,
 8795            );
 8796
 8797            if let Some(indent) = suggested_indent
 8798                && indent.len == cursor_point.column
 8799            {
 8800                self.in_leading_whitespace = false;
 8801            }
 8802        }
 8803
 8804        let edit_prediction = provider.suggest(&buffer, cursor_text_anchor, cx)?;
 8805
 8806        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8807        {
 8808            edit_prediction_types::EditPrediction::Local {
 8809                id,
 8810                edits,
 8811                cursor_position,
 8812                edit_preview,
 8813            } => (id, edits, cursor_position, edit_preview),
 8814            edit_prediction_types::EditPrediction::Jump {
 8815                id,
 8816                snapshot,
 8817                target,
 8818            } => {
 8819                if let Some(provider) = &self.edit_prediction_provider {
 8820                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8821                }
 8822                self.stale_edit_prediction_in_menu = None;
 8823                self.active_edit_prediction = Some(EditPredictionState {
 8824                    inlay_ids: vec![],
 8825                    completion: EditPrediction::MoveOutside { snapshot, target },
 8826                    completion_id: id,
 8827                    invalidation_range: None,
 8828                });
 8829                cx.notify();
 8830                return Some(());
 8831            }
 8832        };
 8833
 8834        let edits = edits
 8835            .into_iter()
 8836            .flat_map(|(range, new_text)| {
 8837                Some((
 8838                    multibuffer.buffer_anchor_range_to_anchor_range(range)?,
 8839                    new_text,
 8840                ))
 8841            })
 8842            .collect::<Vec<_>>();
 8843        if edits.is_empty() {
 8844            return None;
 8845        }
 8846
 8847        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8848            let anchor = multibuffer.anchor_in_excerpt(predicted.anchor)?;
 8849            Some((anchor, predicted.offset))
 8850        });
 8851
 8852        let first_edit_start = edits.first().unwrap().0.start;
 8853        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8854        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8855
 8856        let last_edit_end = edits.last().unwrap().0.end;
 8857        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8858        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8859
 8860        let cursor_row = cursor.to_point(&multibuffer).row;
 8861
 8862        let snapshot = multibuffer
 8863            .buffer_for_id(cursor_text_anchor.buffer_id)
 8864            .cloned()?;
 8865
 8866        let mut inlay_ids = Vec::new();
 8867        let invalidation_row_range;
 8868        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8869            Some(cursor_row..edit_end_row)
 8870        } else if cursor_row > edit_end_row {
 8871            Some(edit_start_row..cursor_row)
 8872        } else {
 8873            None
 8874        };
 8875        let supports_jump = self
 8876            .edit_prediction_provider
 8877            .as_ref()
 8878            .map(|provider| provider.provider.supports_jump_to_edit())
 8879            .unwrap_or(true);
 8880
 8881        let is_move = supports_jump
 8882            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8883        let completion = if is_move {
 8884            if let Some(provider) = &self.edit_prediction_provider {
 8885                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8886            }
 8887            invalidation_row_range =
 8888                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8889            let target = first_edit_start;
 8890            EditPrediction::MoveWithin { target, snapshot }
 8891        } else {
 8892            let show_completions_in_menu = self.has_visible_completions_menu();
 8893            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8894                && !self.edit_predictions_hidden_for_vim_mode;
 8895
 8896            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8897                if provider.show_tab_accept_marker() {
 8898                    EditDisplayMode::TabAccept
 8899                } else {
 8900                    EditDisplayMode::Inline
 8901                }
 8902            } else {
 8903                EditDisplayMode::DiffPopover
 8904            };
 8905
 8906            let report_shown = match display_mode {
 8907                EditDisplayMode::DiffPopover | EditDisplayMode::Inline => {
 8908                    show_completions_in_buffer || show_completions_in_menu
 8909                }
 8910                EditDisplayMode::TabAccept => {
 8911                    show_completions_in_menu || self.edit_prediction_preview_is_active()
 8912                }
 8913            };
 8914
 8915            if report_shown && let Some(provider) = &self.edit_prediction_provider {
 8916                let suggestion_display_type = match display_mode {
 8917                    EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8918                    EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8919                        SuggestionDisplayType::GhostText
 8920                    }
 8921                };
 8922                provider.provider.did_show(suggestion_display_type, cx);
 8923            }
 8924
 8925            if show_completions_in_buffer {
 8926                if edits
 8927                    .iter()
 8928                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8929                {
 8930                    let mut inlays = Vec::new();
 8931                    for (range, new_text) in &edits {
 8932                        let inlay = Inlay::edit_prediction(
 8933                            post_inc(&mut self.next_inlay_id),
 8934                            range.start,
 8935                            new_text.as_ref(),
 8936                        );
 8937                        inlay_ids.push(inlay.id);
 8938                        inlays.push(inlay);
 8939                    }
 8940
 8941                    self.splice_inlays(&[], inlays, cx);
 8942                } else {
 8943                    let background_color = cx.theme().status().deleted_background;
 8944                    self.highlight_text(
 8945                        HighlightKey::EditPredictionHighlight,
 8946                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8947                        HighlightStyle {
 8948                            background_color: Some(background_color),
 8949                            ..Default::default()
 8950                        },
 8951                        cx,
 8952                    );
 8953                }
 8954            }
 8955
 8956            invalidation_row_range = edit_start_row..edit_end_row;
 8957
 8958            EditPrediction::Edit {
 8959                edits,
 8960                cursor_position,
 8961                edit_preview,
 8962                display_mode,
 8963                snapshot,
 8964            }
 8965        };
 8966
 8967        let invalidation_range = multibuffer
 8968            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8969            ..multibuffer.anchor_after(Point::new(
 8970                invalidation_row_range.end,
 8971                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8972            ));
 8973
 8974        self.stale_edit_prediction_in_menu = None;
 8975        self.active_edit_prediction = Some(EditPredictionState {
 8976            inlay_ids,
 8977            completion,
 8978            completion_id,
 8979            invalidation_range: Some(invalidation_range),
 8980        });
 8981
 8982        cx.notify();
 8983
 8984        Some(())
 8985    }
 8986
 8987    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8988        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8989    }
 8990
 8991    /// Get all display points of breakpoints that will be rendered within editor
 8992    ///
 8993    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8994    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8995    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8996    fn active_breakpoints(
 8997        &self,
 8998        range: Range<DisplayRow>,
 8999        window: &mut Window,
 9000        cx: &mut Context<Self>,
 9001    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 9002        let mut breakpoint_display_points = HashMap::default();
 9003
 9004        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 9005            return breakpoint_display_points;
 9006        };
 9007
 9008        let snapshot = self.snapshot(window, cx);
 9009
 9010        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 9011
 9012        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 9013            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 9014
 9015        for (buffer_snapshot, range, _) in
 9016            multi_buffer_snapshot.range_to_buffer_ranges(range.start..range.end)
 9017        {
 9018            let Some(buffer) = self.buffer().read(cx).buffer(buffer_snapshot.remote_id()) else {
 9019                continue;
 9020            };
 9021            let breakpoints = breakpoint_store.read(cx).breakpoints(
 9022                &buffer,
 9023                Some(
 9024                    buffer_snapshot.anchor_before(range.start)
 9025                        ..buffer_snapshot.anchor_after(range.end),
 9026                ),
 9027                &buffer_snapshot,
 9028                cx,
 9029            );
 9030            for (breakpoint, state) in breakpoints {
 9031                let Some(multi_buffer_anchor) =
 9032                    multi_buffer_snapshot.anchor_in_excerpt(breakpoint.position)
 9033                else {
 9034                    continue;
 9035                };
 9036                let position = multi_buffer_anchor
 9037                    .to_point(&multi_buffer_snapshot)
 9038                    .to_display_point(&snapshot);
 9039
 9040                breakpoint_display_points.insert(
 9041                    position.row(),
 9042                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 9043                );
 9044            }
 9045        }
 9046
 9047        breakpoint_display_points
 9048    }
 9049
 9050    fn breakpoint_context_menu(
 9051        &self,
 9052        anchor: Anchor,
 9053        window: &mut Window,
 9054        cx: &mut Context<Self>,
 9055    ) -> Entity<ui::ContextMenu> {
 9056        let weak_editor = cx.weak_entity();
 9057        let focus_handle = self.focus_handle(cx);
 9058
 9059        let row = self
 9060            .buffer
 9061            .read(cx)
 9062            .snapshot(cx)
 9063            .summary_for_anchor::<Point>(&anchor)
 9064            .row;
 9065
 9066        let breakpoint = self
 9067            .breakpoint_at_row(row, window, cx)
 9068            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9069
 9070        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9071            "Edit Log Breakpoint"
 9072        } else {
 9073            "Set Log Breakpoint"
 9074        };
 9075
 9076        let condition_breakpoint_msg = if breakpoint
 9077            .as_ref()
 9078            .is_some_and(|bp| bp.1.condition.is_some())
 9079        {
 9080            "Edit Condition Breakpoint"
 9081        } else {
 9082            "Set Condition Breakpoint"
 9083        };
 9084
 9085        let hit_condition_breakpoint_msg = if breakpoint
 9086            .as_ref()
 9087            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9088        {
 9089            "Edit Hit Condition Breakpoint"
 9090        } else {
 9091            "Set Hit Condition Breakpoint"
 9092        };
 9093
 9094        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9095            "Unset Breakpoint"
 9096        } else {
 9097            "Set Breakpoint"
 9098        };
 9099
 9100        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9101
 9102        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9103            BreakpointState::Enabled => Some("Disable"),
 9104            BreakpointState::Disabled => Some("Enable"),
 9105        });
 9106
 9107        let (anchor, breakpoint) =
 9108            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9109
 9110        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9111            menu.on_blur_subscription(Subscription::new(|| {}))
 9112                .context(focus_handle)
 9113                .when(run_to_cursor, |this| {
 9114                    let weak_editor = weak_editor.clone();
 9115                    this.entry("Run to Cursor", None, move |window, cx| {
 9116                        weak_editor
 9117                            .update(cx, |editor, cx| {
 9118                                editor.change_selections(
 9119                                    SelectionEffects::no_scroll(),
 9120                                    window,
 9121                                    cx,
 9122                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9123                                );
 9124                            })
 9125                            .ok();
 9126
 9127                        window.dispatch_action(Box::new(RunToCursor), cx);
 9128                    })
 9129                    .separator()
 9130                })
 9131                .when_some(toggle_state_msg, |this, msg| {
 9132                    this.entry(msg, None, {
 9133                        let weak_editor = weak_editor.clone();
 9134                        let breakpoint = breakpoint.clone();
 9135                        move |_window, cx| {
 9136                            weak_editor
 9137                                .update(cx, |this, cx| {
 9138                                    this.edit_breakpoint_at_anchor(
 9139                                        anchor,
 9140                                        breakpoint.as_ref().clone(),
 9141                                        BreakpointEditAction::InvertState,
 9142                                        cx,
 9143                                    );
 9144                                })
 9145                                .log_err();
 9146                        }
 9147                    })
 9148                })
 9149                .entry(set_breakpoint_msg, None, {
 9150                    let weak_editor = weak_editor.clone();
 9151                    let breakpoint = breakpoint.clone();
 9152                    move |_window, cx| {
 9153                        weak_editor
 9154                            .update(cx, |this, cx| {
 9155                                this.edit_breakpoint_at_anchor(
 9156                                    anchor,
 9157                                    breakpoint.as_ref().clone(),
 9158                                    BreakpointEditAction::Toggle,
 9159                                    cx,
 9160                                );
 9161                            })
 9162                            .log_err();
 9163                    }
 9164                })
 9165                .entry(log_breakpoint_msg, None, {
 9166                    let breakpoint = breakpoint.clone();
 9167                    let weak_editor = weak_editor.clone();
 9168                    move |window, cx| {
 9169                        weak_editor
 9170                            .update(cx, |this, cx| {
 9171                                this.add_edit_breakpoint_block(
 9172                                    anchor,
 9173                                    breakpoint.as_ref(),
 9174                                    BreakpointPromptEditAction::Log,
 9175                                    window,
 9176                                    cx,
 9177                                );
 9178                            })
 9179                            .log_err();
 9180                    }
 9181                })
 9182                .entry(condition_breakpoint_msg, None, {
 9183                    let breakpoint = breakpoint.clone();
 9184                    let weak_editor = weak_editor.clone();
 9185                    move |window, cx| {
 9186                        weak_editor
 9187                            .update(cx, |this, cx| {
 9188                                this.add_edit_breakpoint_block(
 9189                                    anchor,
 9190                                    breakpoint.as_ref(),
 9191                                    BreakpointPromptEditAction::Condition,
 9192                                    window,
 9193                                    cx,
 9194                                );
 9195                            })
 9196                            .log_err();
 9197                    }
 9198                })
 9199                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9200                    weak_editor
 9201                        .update(cx, |this, cx| {
 9202                            this.add_edit_breakpoint_block(
 9203                                anchor,
 9204                                breakpoint.as_ref(),
 9205                                BreakpointPromptEditAction::HitCondition,
 9206                                window,
 9207                                cx,
 9208                            );
 9209                        })
 9210                        .log_err();
 9211                })
 9212        })
 9213    }
 9214
 9215    fn render_breakpoint(
 9216        &self,
 9217        position: Anchor,
 9218        row: DisplayRow,
 9219        breakpoint: &Breakpoint,
 9220        state: Option<BreakpointSessionState>,
 9221        cx: &mut Context<Self>,
 9222    ) -> IconButton {
 9223        let is_rejected = state.is_some_and(|s| !s.verified);
 9224        // Is it a breakpoint that shows up when hovering over gutter?
 9225        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9226            (false, false),
 9227            |PhantomBreakpointIndicator {
 9228                 is_active,
 9229                 display_row,
 9230                 collides_with_existing_breakpoint,
 9231             }| {
 9232                (
 9233                    is_active && display_row == row,
 9234                    collides_with_existing_breakpoint,
 9235                )
 9236            },
 9237        );
 9238
 9239        let (color, icon) = {
 9240            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9241                (false, false) => ui::IconName::DebugBreakpoint,
 9242                (true, false) => ui::IconName::DebugLogBreakpoint,
 9243                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9244                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9245            };
 9246
 9247            let theme_colors = cx.theme().colors();
 9248
 9249            let color = if is_phantom {
 9250                if collides_with_existing {
 9251                    Color::Custom(
 9252                        theme_colors
 9253                            .debugger_accent
 9254                            .blend(theme_colors.text.opacity(0.6)),
 9255                    )
 9256                } else {
 9257                    Color::Hint
 9258                }
 9259            } else if is_rejected {
 9260                Color::Disabled
 9261            } else {
 9262                Color::Debugger
 9263            };
 9264
 9265            (color, icon)
 9266        };
 9267
 9268        let breakpoint = Arc::from(breakpoint.clone());
 9269
 9270        let alt_as_text = gpui::Keystroke {
 9271            modifiers: Modifiers::secondary_key(),
 9272            ..Default::default()
 9273        };
 9274        let primary_action_text = if breakpoint.is_disabled() {
 9275            "Enable breakpoint"
 9276        } else if is_phantom && !collides_with_existing {
 9277            "Set breakpoint"
 9278        } else {
 9279            "Unset breakpoint"
 9280        };
 9281        let focus_handle = self.focus_handle.clone();
 9282
 9283        let meta = if is_rejected {
 9284            SharedString::from("No executable code is associated with this line.")
 9285        } else if collides_with_existing && !breakpoint.is_disabled() {
 9286            SharedString::from(format!(
 9287                "{alt_as_text}-click to disable,\nright-click for more options."
 9288            ))
 9289        } else {
 9290            SharedString::from("Right-click for more options.")
 9291        };
 9292        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9293            .icon_size(IconSize::XSmall)
 9294            .size(ui::ButtonSize::None)
 9295            .when(is_rejected, |this| {
 9296                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9297            })
 9298            .icon_color(color)
 9299            .style(ButtonStyle::Transparent)
 9300            .on_click(cx.listener({
 9301                move |editor, event: &ClickEvent, window, cx| {
 9302                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9303                        BreakpointEditAction::InvertState
 9304                    } else {
 9305                        BreakpointEditAction::Toggle
 9306                    };
 9307
 9308                    window.focus(&editor.focus_handle(cx), cx);
 9309                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9310                    editor.edit_breakpoint_at_anchor(
 9311                        position,
 9312                        breakpoint.as_ref().clone(),
 9313                        edit_action,
 9314                        cx,
 9315                    );
 9316                }
 9317            }))
 9318            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9319                editor.set_breakpoint_context_menu(
 9320                    row,
 9321                    Some(position),
 9322                    event.position(),
 9323                    window,
 9324                    cx,
 9325                );
 9326            }))
 9327            .tooltip(move |_window, cx| {
 9328                Tooltip::with_meta_in(
 9329                    primary_action_text,
 9330                    Some(&ToggleBreakpoint),
 9331                    meta.clone(),
 9332                    &focus_handle,
 9333                    cx,
 9334                )
 9335            })
 9336    }
 9337
 9338    fn build_tasks_context(
 9339        project: &Entity<Project>,
 9340        buffer: &Entity<Buffer>,
 9341        buffer_row: u32,
 9342        tasks: &Arc<RunnableTasks>,
 9343        cx: &mut Context<Self>,
 9344    ) -> Task<Option<task::TaskContext>> {
 9345        let position = Point::new(buffer_row, tasks.column);
 9346        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9347        let location = Location {
 9348            buffer: buffer.clone(),
 9349            range: range_start..range_start,
 9350        };
 9351        // Fill in the environmental variables from the tree-sitter captures
 9352        let mut captured_task_variables = TaskVariables::default();
 9353        for (capture_name, value) in tasks.extra_variables.clone() {
 9354            captured_task_variables.insert(
 9355                task::VariableName::Custom(capture_name.into()),
 9356                value.clone(),
 9357            );
 9358        }
 9359        project.update(cx, |project, cx| {
 9360            project.task_store().update(cx, |task_store, cx| {
 9361                task_store.task_context_for_location(captured_task_variables, location, cx)
 9362            })
 9363        })
 9364    }
 9365
 9366    pub fn context_menu_visible(&self) -> bool {
 9367        !self.edit_prediction_preview_is_active()
 9368            && self
 9369                .context_menu
 9370                .borrow()
 9371                .as_ref()
 9372                .is_some_and(|menu| menu.visible())
 9373    }
 9374
 9375    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9376        self.context_menu
 9377            .borrow()
 9378            .as_ref()
 9379            .map(|menu| menu.origin())
 9380    }
 9381
 9382    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9383        self.context_menu_options = Some(options);
 9384    }
 9385
 9386    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9387    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9388
 9389    fn render_edit_prediction_popover(
 9390        &mut self,
 9391        text_bounds: &Bounds<Pixels>,
 9392        content_origin: gpui::Point<Pixels>,
 9393        right_margin: Pixels,
 9394        editor_snapshot: &EditorSnapshot,
 9395        visible_row_range: Range<DisplayRow>,
 9396        scroll_top: ScrollOffset,
 9397        scroll_bottom: ScrollOffset,
 9398        line_layouts: &[LineWithInvisibles],
 9399        line_height: Pixels,
 9400        scroll_position: gpui::Point<ScrollOffset>,
 9401        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9402        newest_selection_head: Option<DisplayPoint>,
 9403        editor_width: Pixels,
 9404        style: &EditorStyle,
 9405        window: &mut Window,
 9406        cx: &mut App,
 9407    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9408        if self.mode().is_minimap() {
 9409            return None;
 9410        }
 9411        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9412
 9413        if self.edit_prediction_visible_in_cursor_popover(true) {
 9414            return None;
 9415        }
 9416
 9417        match &active_edit_prediction.completion {
 9418            EditPrediction::MoveWithin { target, .. } => {
 9419                let target_display_point = target.to_display_point(editor_snapshot);
 9420
 9421                if self.edit_prediction_requires_modifier() {
 9422                    if !self.edit_prediction_preview_is_active() {
 9423                        return None;
 9424                    }
 9425
 9426                    self.render_edit_prediction_modifier_jump_popover(
 9427                        text_bounds,
 9428                        content_origin,
 9429                        visible_row_range,
 9430                        line_layouts,
 9431                        line_height,
 9432                        scroll_pixel_position,
 9433                        newest_selection_head,
 9434                        target_display_point,
 9435                        window,
 9436                        cx,
 9437                    )
 9438                } else {
 9439                    self.render_edit_prediction_eager_jump_popover(
 9440                        text_bounds,
 9441                        content_origin,
 9442                        editor_snapshot,
 9443                        visible_row_range,
 9444                        scroll_top,
 9445                        scroll_bottom,
 9446                        line_height,
 9447                        scroll_pixel_position,
 9448                        target_display_point,
 9449                        editor_width,
 9450                        window,
 9451                        cx,
 9452                    )
 9453                }
 9454            }
 9455            EditPrediction::Edit {
 9456                display_mode: EditDisplayMode::Inline,
 9457                ..
 9458            } => None,
 9459            EditPrediction::Edit {
 9460                display_mode: EditDisplayMode::TabAccept,
 9461                edits,
 9462                ..
 9463            } => {
 9464                let range = &edits.first()?.0;
 9465                let target_display_point = range.end.to_display_point(editor_snapshot);
 9466
 9467                self.render_edit_prediction_end_of_line_popover(
 9468                    "Accept",
 9469                    editor_snapshot,
 9470                    visible_row_range,
 9471                    target_display_point,
 9472                    line_height,
 9473                    scroll_pixel_position,
 9474                    content_origin,
 9475                    editor_width,
 9476                    window,
 9477                    cx,
 9478                )
 9479            }
 9480            EditPrediction::Edit {
 9481                edits,
 9482                edit_preview,
 9483                display_mode: EditDisplayMode::DiffPopover,
 9484                snapshot,
 9485                ..
 9486            } => self.render_edit_prediction_diff_popover(
 9487                text_bounds,
 9488                content_origin,
 9489                right_margin,
 9490                editor_snapshot,
 9491                visible_row_range,
 9492                line_layouts,
 9493                line_height,
 9494                scroll_position,
 9495                scroll_pixel_position,
 9496                newest_selection_head,
 9497                editor_width,
 9498                style,
 9499                edits,
 9500                edit_preview,
 9501                snapshot,
 9502                window,
 9503                cx,
 9504            ),
 9505            EditPrediction::MoveOutside { snapshot, .. } => {
 9506                let mut element = self
 9507                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9508                    .into_any();
 9509
 9510                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9511                let origin_x = text_bounds.size.width - size.width - px(30.);
 9512                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9513                element.prepaint_at(origin, window, cx);
 9514
 9515                Some((element, origin))
 9516            }
 9517        }
 9518    }
 9519
 9520    fn render_edit_prediction_modifier_jump_popover(
 9521        &mut self,
 9522        text_bounds: &Bounds<Pixels>,
 9523        content_origin: gpui::Point<Pixels>,
 9524        visible_row_range: Range<DisplayRow>,
 9525        line_layouts: &[LineWithInvisibles],
 9526        line_height: Pixels,
 9527        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9528        newest_selection_head: Option<DisplayPoint>,
 9529        target_display_point: DisplayPoint,
 9530        window: &mut Window,
 9531        cx: &mut App,
 9532    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9533        let scrolled_content_origin =
 9534            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9535
 9536        const SCROLL_PADDING_Y: Pixels = px(12.);
 9537
 9538        if target_display_point.row() < visible_row_range.start {
 9539            return self.render_edit_prediction_scroll_popover(
 9540                &|_| SCROLL_PADDING_Y,
 9541                IconName::ArrowUp,
 9542                visible_row_range,
 9543                line_layouts,
 9544                newest_selection_head,
 9545                scrolled_content_origin,
 9546                window,
 9547                cx,
 9548            );
 9549        } else if target_display_point.row() >= visible_row_range.end {
 9550            return self.render_edit_prediction_scroll_popover(
 9551                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9552                IconName::ArrowDown,
 9553                visible_row_range,
 9554                line_layouts,
 9555                newest_selection_head,
 9556                scrolled_content_origin,
 9557                window,
 9558                cx,
 9559            );
 9560        }
 9561
 9562        const POLE_WIDTH: Pixels = px(2.);
 9563
 9564        let line_layout =
 9565            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9566        let target_column = target_display_point.column() as usize;
 9567
 9568        let target_x = line_layout.x_for_index(target_column);
 9569        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9570            - scroll_pixel_position.y;
 9571
 9572        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9573
 9574        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9575        border_color.l += 0.001;
 9576
 9577        let mut element = v_flex()
 9578            .items_end()
 9579            .when(flag_on_right, |el| el.items_start())
 9580            .child(if flag_on_right {
 9581                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9582                    .rounded_bl(px(0.))
 9583                    .rounded_tl(px(0.))
 9584                    .border_l_2()
 9585                    .border_color(border_color)
 9586            } else {
 9587                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9588                    .rounded_br(px(0.))
 9589                    .rounded_tr(px(0.))
 9590                    .border_r_2()
 9591                    .border_color(border_color)
 9592            })
 9593            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9594            .into_any();
 9595
 9596        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9597
 9598        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9599            - point(
 9600                if flag_on_right {
 9601                    POLE_WIDTH
 9602                } else {
 9603                    size.width - POLE_WIDTH
 9604                },
 9605                size.height - line_height,
 9606            );
 9607
 9608        origin.x = origin.x.max(content_origin.x);
 9609
 9610        element.prepaint_at(origin, window, cx);
 9611
 9612        Some((element, origin))
 9613    }
 9614
 9615    fn render_edit_prediction_scroll_popover(
 9616        &mut self,
 9617        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9618        scroll_icon: IconName,
 9619        visible_row_range: Range<DisplayRow>,
 9620        line_layouts: &[LineWithInvisibles],
 9621        newest_selection_head: Option<DisplayPoint>,
 9622        scrolled_content_origin: gpui::Point<Pixels>,
 9623        window: &mut Window,
 9624        cx: &mut App,
 9625    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9626        let mut element = self
 9627            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9628            .into_any();
 9629
 9630        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9631
 9632        let cursor = newest_selection_head?;
 9633        let cursor_row_layout =
 9634            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9635        let cursor_column = cursor.column() as usize;
 9636
 9637        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9638
 9639        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9640
 9641        element.prepaint_at(origin, window, cx);
 9642        Some((element, origin))
 9643    }
 9644
 9645    fn render_edit_prediction_eager_jump_popover(
 9646        &mut self,
 9647        text_bounds: &Bounds<Pixels>,
 9648        content_origin: gpui::Point<Pixels>,
 9649        editor_snapshot: &EditorSnapshot,
 9650        visible_row_range: Range<DisplayRow>,
 9651        scroll_top: ScrollOffset,
 9652        scroll_bottom: ScrollOffset,
 9653        line_height: Pixels,
 9654        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9655        target_display_point: DisplayPoint,
 9656        editor_width: Pixels,
 9657        window: &mut Window,
 9658        cx: &mut App,
 9659    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9660        if target_display_point.row().as_f64() < scroll_top {
 9661            let mut element = self
 9662                .render_edit_prediction_line_popover(
 9663                    "Jump to Edit",
 9664                    Some(IconName::ArrowUp),
 9665                    window,
 9666                    cx,
 9667                )
 9668                .into_any();
 9669
 9670            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9671            let offset = point(
 9672                (text_bounds.size.width - size.width) / 2.,
 9673                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9674            );
 9675
 9676            let origin = text_bounds.origin + offset;
 9677            element.prepaint_at(origin, window, cx);
 9678            Some((element, origin))
 9679        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9680            let mut element = self
 9681                .render_edit_prediction_line_popover(
 9682                    "Jump to Edit",
 9683                    Some(IconName::ArrowDown),
 9684                    window,
 9685                    cx,
 9686                )
 9687                .into_any();
 9688
 9689            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9690            let offset = point(
 9691                (text_bounds.size.width - size.width) / 2.,
 9692                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9693            );
 9694
 9695            let origin = text_bounds.origin + offset;
 9696            element.prepaint_at(origin, window, cx);
 9697            Some((element, origin))
 9698        } else {
 9699            self.render_edit_prediction_end_of_line_popover(
 9700                "Jump to Edit",
 9701                editor_snapshot,
 9702                visible_row_range,
 9703                target_display_point,
 9704                line_height,
 9705                scroll_pixel_position,
 9706                content_origin,
 9707                editor_width,
 9708                window,
 9709                cx,
 9710            )
 9711        }
 9712    }
 9713
 9714    fn render_edit_prediction_end_of_line_popover(
 9715        self: &mut Editor,
 9716        label: &'static str,
 9717        editor_snapshot: &EditorSnapshot,
 9718        visible_row_range: Range<DisplayRow>,
 9719        target_display_point: DisplayPoint,
 9720        line_height: Pixels,
 9721        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9722        content_origin: gpui::Point<Pixels>,
 9723        editor_width: Pixels,
 9724        window: &mut Window,
 9725        cx: &mut App,
 9726    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9727        let target_line_end = DisplayPoint::new(
 9728            target_display_point.row(),
 9729            editor_snapshot.line_len(target_display_point.row()),
 9730        );
 9731
 9732        let mut element = self
 9733            .render_edit_prediction_line_popover(label, None, window, cx)
 9734            .into_any();
 9735
 9736        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9737
 9738        let line_origin =
 9739            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9740
 9741        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9742        let mut origin = start_point
 9743            + line_origin
 9744            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9745        origin.x = origin.x.max(content_origin.x);
 9746
 9747        let max_x = content_origin.x + editor_width - size.width;
 9748
 9749        if origin.x > max_x {
 9750            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9751
 9752            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9753                origin.y += offset;
 9754                IconName::ArrowUp
 9755            } else {
 9756                origin.y -= offset;
 9757                IconName::ArrowDown
 9758            };
 9759
 9760            element = self
 9761                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9762                .into_any();
 9763
 9764            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9765
 9766            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9767        }
 9768
 9769        element.prepaint_at(origin, window, cx);
 9770        Some((element, origin))
 9771    }
 9772
 9773    fn render_edit_prediction_diff_popover(
 9774        self: &Editor,
 9775        text_bounds: &Bounds<Pixels>,
 9776        content_origin: gpui::Point<Pixels>,
 9777        right_margin: Pixels,
 9778        editor_snapshot: &EditorSnapshot,
 9779        visible_row_range: Range<DisplayRow>,
 9780        line_layouts: &[LineWithInvisibles],
 9781        line_height: Pixels,
 9782        scroll_position: gpui::Point<ScrollOffset>,
 9783        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9784        newest_selection_head: Option<DisplayPoint>,
 9785        editor_width: Pixels,
 9786        style: &EditorStyle,
 9787        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9788        edit_preview: &Option<language::EditPreview>,
 9789        snapshot: &language::BufferSnapshot,
 9790        window: &mut Window,
 9791        cx: &mut App,
 9792    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9793        let edit_start = edits
 9794            .first()
 9795            .unwrap()
 9796            .0
 9797            .start
 9798            .to_display_point(editor_snapshot);
 9799        let edit_end = edits
 9800            .last()
 9801            .unwrap()
 9802            .0
 9803            .end
 9804            .to_display_point(editor_snapshot);
 9805
 9806        let is_visible = visible_row_range.contains(&edit_start.row())
 9807            || visible_row_range.contains(&edit_end.row());
 9808        if !is_visible {
 9809            return None;
 9810        }
 9811
 9812        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9813            crate::edit_prediction_edit_text(
 9814                snapshot,
 9815                edits,
 9816                edit_preview,
 9817                false,
 9818                editor_snapshot.buffer_snapshot(),
 9819                cx,
 9820            )
 9821        } else {
 9822            // Fallback for providers without edit_preview
 9823            crate::edit_prediction_fallback_text(edits, cx)
 9824        };
 9825
 9826        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9827        let line_count = highlighted_edits.text.lines().count();
 9828
 9829        const BORDER_WIDTH: Pixels = px(1.);
 9830
 9831        let keybind = self.render_edit_prediction_keybind(window, cx);
 9832        let has_keybind = keybind.is_some();
 9833
 9834        let mut element = h_flex()
 9835            .items_start()
 9836            .child(
 9837                h_flex()
 9838                    .bg(cx.theme().colors().editor_background)
 9839                    .border(BORDER_WIDTH)
 9840                    .shadow_xs()
 9841                    .border_color(cx.theme().colors().border)
 9842                    .rounded_l_lg()
 9843                    .when(line_count > 1, |el| el.rounded_br_lg())
 9844                    .pr_1()
 9845                    .child(styled_text),
 9846            )
 9847            .child(
 9848                h_flex()
 9849                    .h(line_height + BORDER_WIDTH * 2.)
 9850                    .px_1p5()
 9851                    .gap_1()
 9852                    // Workaround: For some reason, there's a gap if we don't do this
 9853                    .ml(-BORDER_WIDTH)
 9854                    .shadow(vec![gpui::BoxShadow {
 9855                        color: gpui::black().opacity(0.05),
 9856                        offset: point(px(1.), px(1.)),
 9857                        blur_radius: px(2.),
 9858                        spread_radius: px(0.),
 9859                    }])
 9860                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9861                    .border(BORDER_WIDTH)
 9862                    .border_color(cx.theme().colors().border)
 9863                    .rounded_r_lg()
 9864                    .id("edit_prediction_diff_popover_keybind")
 9865                    .when(!has_keybind, |el| {
 9866                        let status_colors = cx.theme().status();
 9867
 9868                        el.bg(status_colors.error_background)
 9869                            .border_color(status_colors.error.opacity(0.6))
 9870                            .child(Icon::new(IconName::Info).color(Color::Error))
 9871                            .cursor_default()
 9872                            .hoverable_tooltip(move |_window, cx| {
 9873                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9874                            })
 9875                    })
 9876                    .children(keybind),
 9877            )
 9878            .into_any();
 9879
 9880        let longest_row =
 9881            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9882        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9883            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9884        } else {
 9885            layout_line(
 9886                longest_row,
 9887                editor_snapshot,
 9888                style,
 9889                editor_width,
 9890                |_| false,
 9891                window,
 9892                cx,
 9893            )
 9894            .width
 9895        };
 9896
 9897        let viewport_bounds =
 9898            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9899                right: -right_margin,
 9900                ..Default::default()
 9901            });
 9902
 9903        let x_after_longest = Pixels::from(
 9904            ScrollPixelOffset::from(
 9905                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9906            ) - scroll_pixel_position.x,
 9907        );
 9908
 9909        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9910
 9911        // Fully visible if it can be displayed within the window (allow overlapping other
 9912        // panes). However, this is only allowed if the popover starts within text_bounds.
 9913        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9914            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9915
 9916        let mut origin = if can_position_to_the_right {
 9917            point(
 9918                x_after_longest,
 9919                text_bounds.origin.y
 9920                    + Pixels::from(
 9921                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9922                            - scroll_pixel_position.y,
 9923                    ),
 9924            )
 9925        } else {
 9926            let cursor_row = newest_selection_head.map(|head| head.row());
 9927            let above_edit = edit_start
 9928                .row()
 9929                .0
 9930                .checked_sub(line_count as u32)
 9931                .map(DisplayRow);
 9932            let below_edit = Some(edit_end.row() + 1);
 9933            let above_cursor =
 9934                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9935            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9936
 9937            // Place the edit popover adjacent to the edit if there is a location
 9938            // available that is onscreen and does not obscure the cursor. Otherwise,
 9939            // place it adjacent to the cursor.
 9940            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9941                .into_iter()
 9942                .flatten()
 9943                .find(|&start_row| {
 9944                    let end_row = start_row + line_count as u32;
 9945                    visible_row_range.contains(&start_row)
 9946                        && visible_row_range.contains(&end_row)
 9947                        && cursor_row
 9948                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9949                })?;
 9950
 9951            content_origin
 9952                + point(
 9953                    Pixels::from(-scroll_pixel_position.x),
 9954                    Pixels::from(
 9955                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9956                    ),
 9957                )
 9958        };
 9959
 9960        origin.x -= BORDER_WIDTH;
 9961
 9962        window.with_content_mask(
 9963            Some(gpui::ContentMask {
 9964                bounds: *text_bounds,
 9965            }),
 9966            |window| {
 9967                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9968            },
 9969        );
 9970
 9971        // Do not return an element, since it will already be drawn due to defer_draw.
 9972        None
 9973    }
 9974
 9975    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9976        px(30.)
 9977    }
 9978
 9979    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9980        if self.read_only(cx) {
 9981            cx.theme().players().read_only()
 9982        } else {
 9983            self.style.as_ref().unwrap().local_player
 9984        }
 9985    }
 9986
 9987    fn render_edit_prediction_inline_keystroke(
 9988        &self,
 9989        keystroke: &gpui::KeybindingKeystroke,
 9990        modifiers_color: Color,
 9991        cx: &App,
 9992    ) -> AnyElement {
 9993        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9994
 9995        h_flex()
 9996            .px_0p5()
 9997            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9998            .font(
 9999                theme_settings::ThemeSettings::get_global(cx)
10000                    .buffer_font
10001                    .clone(),
10002            )
10003            .text_size(TextSize::XSmall.rems(cx))
10004            .child(h_flex().children(ui::render_modifiers(
10005                keystroke.modifiers(),
10006                PlatformStyle::platform(),
10007                Some(modifiers_color),
10008                Some(IconSize::XSmall.rems().into()),
10009                true,
10010            )))
10011            .when(is_platform_style_mac, |parent| {
10012                parent.child(keystroke.key().to_string())
10013            })
10014            .when(!is_platform_style_mac, |parent| {
10015                parent.child(
10016                    Key::new(ui::utils::capitalize(keystroke.key()), Some(Color::Default))
10017                        .size(Some(IconSize::XSmall.rems().into())),
10018                )
10019            })
10020            .into_any()
10021    }
10022
10023    fn render_edit_prediction_popover_keystroke(
10024        &self,
10025        keystroke: &gpui::KeybindingKeystroke,
10026        color: Color,
10027        cx: &App,
10028    ) -> AnyElement {
10029        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10030
10031        if keystroke.modifiers().modified() {
10032            h_flex()
10033                .font(
10034                    theme_settings::ThemeSettings::get_global(cx)
10035                        .buffer_font
10036                        .clone(),
10037                )
10038                .when(is_platform_style_mac, |parent| parent.gap_1())
10039                .child(h_flex().children(ui::render_modifiers(
10040                    keystroke.modifiers(),
10041                    PlatformStyle::platform(),
10042                    Some(color),
10043                    None,
10044                    false,
10045                )))
10046                .into_any()
10047        } else {
10048            Key::new(ui::utils::capitalize(keystroke.key()), Some(color))
10049                .size(Some(IconSize::XSmall.rems().into()))
10050                .into_any_element()
10051        }
10052    }
10053
10054    fn render_edit_prediction_keybind(
10055        &self,
10056        window: &mut Window,
10057        cx: &mut App,
10058    ) -> Option<AnyElement> {
10059        let keybind_display =
10060            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
10061        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
10062
10063        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
10064            Color::Accent
10065        } else {
10066            Color::Muted
10067        };
10068
10069        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
10070    }
10071
10072    fn render_edit_prediction_line_popover(
10073        &self,
10074        label: impl Into<SharedString>,
10075        icon: Option<IconName>,
10076        window: &mut Window,
10077        cx: &mut App,
10078    ) -> Stateful<Div> {
10079        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10080
10081        let keybind = self.render_edit_prediction_keybind(window, cx);
10082        let has_keybind = keybind.is_some();
10083        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10084
10085        h_flex()
10086            .id("ep-line-popover")
10087            .py_0p5()
10088            .pl_1()
10089            .pr(padding_right)
10090            .gap_1()
10091            .rounded_md()
10092            .border_1()
10093            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10094            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10095            .shadow_xs()
10096            .when(!has_keybind, |el| {
10097                let status_colors = cx.theme().status();
10098
10099                el.bg(status_colors.error_background)
10100                    .border_color(status_colors.error.opacity(0.6))
10101                    .pl_2()
10102                    .child(Icon::new(icons.error).color(Color::Error))
10103                    .cursor_default()
10104                    .hoverable_tooltip(move |_window, cx| {
10105                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10106                    })
10107            })
10108            .children(keybind)
10109            .child(
10110                Label::new(label)
10111                    .size(LabelSize::Small)
10112                    .when(!has_keybind, |el| {
10113                        el.color(cx.theme().status().error.into()).strikethrough()
10114                    }),
10115            )
10116            .when(!has_keybind, |el| {
10117                el.child(
10118                    h_flex().ml_1().child(
10119                        Icon::new(IconName::Info)
10120                            .size(IconSize::Small)
10121                            .color(cx.theme().status().error.into()),
10122                    ),
10123                )
10124            })
10125            .when_some(icon, |element, icon| {
10126                element.child(
10127                    div()
10128                        .mt(px(1.5))
10129                        .child(Icon::new(icon).size(IconSize::Small)),
10130                )
10131            })
10132    }
10133
10134    fn render_edit_prediction_jump_outside_popover(
10135        &self,
10136        snapshot: &BufferSnapshot,
10137        window: &mut Window,
10138        cx: &mut App,
10139    ) -> Stateful<Div> {
10140        let keybind = self.render_edit_prediction_keybind(window, cx);
10141        let has_keybind = keybind.is_some();
10142        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10143
10144        let file_name = snapshot
10145            .file()
10146            .map(|file| SharedString::new(file.file_name(cx)))
10147            .unwrap_or(SharedString::new_static("untitled"));
10148
10149        h_flex()
10150            .id("ep-jump-outside-popover")
10151            .py_1()
10152            .px_2()
10153            .gap_1()
10154            .rounded_md()
10155            .border_1()
10156            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10157            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10158            .shadow_xs()
10159            .when(!has_keybind, |el| {
10160                let status_colors = cx.theme().status();
10161
10162                el.bg(status_colors.error_background)
10163                    .border_color(status_colors.error.opacity(0.6))
10164                    .pl_2()
10165                    .child(Icon::new(icons.error).color(Color::Error))
10166                    .cursor_default()
10167                    .hoverable_tooltip(move |_window, cx| {
10168                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10169                    })
10170            })
10171            .children(keybind)
10172            .child(
10173                Label::new(file_name)
10174                    .size(LabelSize::Small)
10175                    .buffer_font(cx)
10176                    .when(!has_keybind, |el| {
10177                        el.color(cx.theme().status().error.into()).strikethrough()
10178                    }),
10179            )
10180            .when(!has_keybind, |el| {
10181                el.child(
10182                    h_flex().ml_1().child(
10183                        Icon::new(IconName::Info)
10184                            .size(IconSize::Small)
10185                            .color(cx.theme().status().error.into()),
10186                    ),
10187                )
10188            })
10189            .child(
10190                div()
10191                    .mt(px(1.5))
10192                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10193            )
10194    }
10195
10196    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10197        let accent_color = cx.theme().colors().text_accent;
10198        let editor_bg_color = cx.theme().colors().editor_background;
10199        editor_bg_color.blend(accent_color.opacity(0.1))
10200    }
10201
10202    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
10203        let accent_color = cx.theme().colors().text_accent;
10204        let editor_bg_color = cx.theme().colors().editor_background;
10205        editor_bg_color.blend(accent_color.opacity(0.6))
10206    }
10207    fn get_prediction_provider_icons(
10208        provider: &Option<RegisteredEditPredictionDelegate>,
10209        cx: &App,
10210    ) -> edit_prediction_types::EditPredictionIconSet {
10211        match provider {
10212            Some(provider) => provider.provider.icons(cx),
10213            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10214        }
10215    }
10216
10217    fn render_edit_prediction_cursor_popover(
10218        &self,
10219        min_width: Pixels,
10220        max_width: Pixels,
10221        cursor_point: Point,
10222        style: &EditorStyle,
10223        window: &mut Window,
10224        cx: &mut Context<Editor>,
10225    ) -> Option<AnyElement> {
10226        let provider = self.edit_prediction_provider.as_ref()?;
10227        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10228
10229        let is_refreshing = provider.provider.is_refreshing(cx);
10230
10231        fn pending_completion_container(icon: IconName) -> Div {
10232            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10233        }
10234
10235        let completion = match &self.active_edit_prediction {
10236            Some(prediction) => {
10237                if !self.has_visible_completions_menu() {
10238                    const RADIUS: Pixels = px(6.);
10239                    const BORDER_WIDTH: Pixels = px(1.);
10240                    let keybind_display = self.edit_prediction_keybind_display(
10241                        EditPredictionKeybindSurface::CursorPopoverCompact,
10242                        window,
10243                        cx,
10244                    );
10245
10246                    return Some(
10247                        h_flex()
10248                            .elevation_2(cx)
10249                            .border(BORDER_WIDTH)
10250                            .border_color(cx.theme().colors().border)
10251                            .when(keybind_display.missing_accept_keystroke, |el| {
10252                                el.border_color(cx.theme().status().error)
10253                            })
10254                            .rounded(RADIUS)
10255                            .rounded_tl(px(0.))
10256                            .overflow_hidden()
10257                            .child(div().px_1p5().child(match &prediction.completion {
10258                                EditPrediction::MoveWithin { target, snapshot } => {
10259                                    use text::ToPoint as _;
10260                                    if target.text_anchor_in(&snapshot).to_point(snapshot).row
10261                                        > cursor_point.row
10262                                    {
10263                                        Icon::new(icons.down)
10264                                    } else {
10265                                        Icon::new(icons.up)
10266                                    }
10267                                }
10268                                EditPrediction::MoveOutside { .. } => {
10269                                    // TODO [zeta2] custom icon for external jump?
10270                                    Icon::new(icons.base)
10271                                }
10272                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10273                            }))
10274                            .child(
10275                                h_flex()
10276                                    .gap_1()
10277                                    .py_1()
10278                                    .px_2()
10279                                    .rounded_r(RADIUS - BORDER_WIDTH)
10280                                    .border_l_1()
10281                                    .border_color(cx.theme().colors().border)
10282                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10283                                    .when(keybind_display.show_hold_label, |el| {
10284                                        el.child(
10285                                            Label::new("Hold")
10286                                                .size(LabelSize::Small)
10287                                                .when(
10288                                                    keybind_display.missing_accept_keystroke,
10289                                                    |el| el.strikethrough(),
10290                                                )
10291                                                .line_height_style(LineHeightStyle::UiLabel),
10292                                        )
10293                                    })
10294                                    .id("edit_prediction_cursor_popover_keybind")
10295                                    .when(keybind_display.missing_accept_keystroke, |el| {
10296                                        let status_colors = cx.theme().status();
10297
10298                                        el.bg(status_colors.error_background)
10299                                            .border_color(status_colors.error.opacity(0.6))
10300                                            .child(Icon::new(IconName::Info).color(Color::Error))
10301                                            .cursor_default()
10302                                            .hoverable_tooltip(move |_window, cx| {
10303                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10304                                                    .into()
10305                                            })
10306                                    })
10307                                    .when_some(
10308                                        keybind_display.displayed_keystroke.as_ref(),
10309                                        |el, compact_keystroke| {
10310                                            el.child(self.render_edit_prediction_popover_keystroke(
10311                                                compact_keystroke,
10312                                                Color::Default,
10313                                                cx,
10314                                            ))
10315                                        },
10316                                    ),
10317                            )
10318                            .into_any(),
10319                    );
10320                }
10321
10322                self.render_edit_prediction_cursor_popover_preview(
10323                    prediction,
10324                    cursor_point,
10325                    style,
10326                    cx,
10327                )?
10328            }
10329
10330            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10331                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10332                    stale_completion,
10333                    cursor_point,
10334                    style,
10335                    cx,
10336                )?,
10337
10338                None => pending_completion_container(icons.base)
10339                    .child(Label::new("...").size(LabelSize::Small)),
10340            },
10341
10342            None => pending_completion_container(icons.base)
10343                .child(Label::new("...").size(LabelSize::Small)),
10344        };
10345
10346        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10347            completion
10348                .with_animation(
10349                    "loading-completion",
10350                    Animation::new(Duration::from_secs(2))
10351                        .repeat()
10352                        .with_easing(pulsating_between(0.4, 0.8)),
10353                    |label, delta| label.opacity(delta),
10354                )
10355                .into_any_element()
10356        } else {
10357            completion.into_any_element()
10358        };
10359
10360        let has_completion = self.active_edit_prediction.is_some();
10361        let keybind_display = self.edit_prediction_keybind_display(
10362            EditPredictionKeybindSurface::CursorPopoverExpanded,
10363            window,
10364            cx,
10365        );
10366
10367        Some(
10368            h_flex()
10369                .min_w(min_width)
10370                .max_w(max_width)
10371                .flex_1()
10372                .elevation_2(cx)
10373                .border_color(cx.theme().colors().border)
10374                .child(
10375                    div()
10376                        .flex_1()
10377                        .py_1()
10378                        .px_2()
10379                        .overflow_hidden()
10380                        .child(completion),
10381                )
10382                .when_some(
10383                    keybind_display.displayed_keystroke.as_ref(),
10384                    |el, keystroke| {
10385                        let key_color = if !has_completion {
10386                            Color::Muted
10387                        } else {
10388                            Color::Default
10389                        };
10390
10391                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10392                            el.child(
10393                                h_flex()
10394                                    .h_full()
10395                                    .border_l_1()
10396                                    .rounded_r_lg()
10397                                    .border_color(cx.theme().colors().border)
10398                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10399                                    .gap_1()
10400                                    .py_1()
10401                                    .px_2()
10402                                    .child(self.render_edit_prediction_popover_keystroke(
10403                                        keystroke, key_color, cx,
10404                                    ))
10405                                    .child(Label::new("Preview").into_any_element())
10406                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10407                            )
10408                        } else {
10409                            el.child(
10410                                h_flex()
10411                                    .h_full()
10412                                    .border_l_1()
10413                                    .rounded_r_lg()
10414                                    .border_color(cx.theme().colors().border)
10415                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10416                                    .gap_1()
10417                                    .py_1()
10418                                    .px_2()
10419                                    .child(self.render_edit_prediction_popover_keystroke(
10420                                        keystroke, key_color, cx,
10421                                    ))
10422                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10423                            )
10424                        }
10425                    },
10426                )
10427                .into_any(),
10428        )
10429    }
10430
10431    fn render_edit_prediction_cursor_popover_preview(
10432        &self,
10433        completion: &EditPredictionState,
10434        cursor_point: Point,
10435        style: &EditorStyle,
10436        cx: &mut Context<Editor>,
10437    ) -> Option<Div> {
10438        use text::ToPoint as _;
10439
10440        fn render_relative_row_jump(
10441            prefix: impl Into<String>,
10442            current_row: u32,
10443            target_row: u32,
10444        ) -> Div {
10445            let (row_diff, arrow) = if target_row < current_row {
10446                (current_row - target_row, IconName::ArrowUp)
10447            } else {
10448                (target_row - current_row, IconName::ArrowDown)
10449            };
10450
10451            h_flex()
10452                .child(
10453                    Label::new(format!("{}{}", prefix.into(), row_diff))
10454                        .color(Color::Muted)
10455                        .size(LabelSize::Small),
10456                )
10457                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10458        }
10459
10460        let supports_jump = self
10461            .edit_prediction_provider
10462            .as_ref()
10463            .map(|provider| provider.provider.supports_jump_to_edit())
10464            .unwrap_or(true);
10465
10466        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10467
10468        match &completion.completion {
10469            EditPrediction::MoveWithin {
10470                target, snapshot, ..
10471            } => {
10472                if !supports_jump {
10473                    return None;
10474                }
10475                let (target, _) = self.display_snapshot(cx).anchor_to_buffer_anchor(*target)?;
10476
10477                Some(
10478                    h_flex()
10479                        .px_2()
10480                        .gap_2()
10481                        .flex_1()
10482                        .child(if target.to_point(snapshot).row > cursor_point.row {
10483                            Icon::new(icons.down)
10484                        } else {
10485                            Icon::new(icons.up)
10486                        })
10487                        .child(Label::new("Jump to Edit")),
10488                )
10489            }
10490            EditPrediction::MoveOutside { snapshot, .. } => {
10491                let file_name = snapshot
10492                    .file()
10493                    .map(|file| file.file_name(cx))
10494                    .unwrap_or("untitled");
10495                Some(
10496                    h_flex()
10497                        .px_2()
10498                        .gap_2()
10499                        .flex_1()
10500                        .child(Icon::new(icons.base))
10501                        .child(Label::new(format!("Jump to {file_name}"))),
10502                )
10503            }
10504            EditPrediction::Edit {
10505                edits,
10506                edit_preview,
10507                snapshot,
10508                ..
10509            } => {
10510                let first_edit_row = self
10511                    .display_snapshot(cx)
10512                    .anchor_to_buffer_anchor(edits.first()?.0.start)?
10513                    .0
10514                    .to_point(snapshot)
10515                    .row;
10516
10517                let (highlighted_edits, has_more_lines) =
10518                    if let Some(edit_preview) = edit_preview.as_ref() {
10519                        crate::edit_prediction_edit_text(
10520                            snapshot,
10521                            edits,
10522                            edit_preview,
10523                            true,
10524                            &self.display_snapshot(cx),
10525                            cx,
10526                        )
10527                        .first_line_preview()
10528                    } else {
10529                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10530                    };
10531
10532                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10533                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10534
10535                let preview = h_flex()
10536                    .gap_1()
10537                    .min_w_16()
10538                    .child(styled_text)
10539                    .when(has_more_lines, |parent| parent.child(""));
10540
10541                let left = if supports_jump && first_edit_row != cursor_point.row {
10542                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10543                        .into_any_element()
10544                } else {
10545                    Icon::new(icons.base).into_any_element()
10546                };
10547
10548                Some(
10549                    h_flex()
10550                        .h_full()
10551                        .flex_1()
10552                        .gap_2()
10553                        .pr_1()
10554                        .overflow_x_hidden()
10555                        .font(
10556                            theme_settings::ThemeSettings::get_global(cx)
10557                                .buffer_font
10558                                .clone(),
10559                        )
10560                        .child(left)
10561                        .child(preview),
10562                )
10563            }
10564        }
10565    }
10566
10567    pub fn render_context_menu(
10568        &mut self,
10569        max_height_in_lines: u32,
10570        window: &mut Window,
10571        cx: &mut Context<Editor>,
10572    ) -> Option<AnyElement> {
10573        let menu = self.context_menu.borrow();
10574        let menu = menu.as_ref()?;
10575        if !menu.visible() {
10576            return None;
10577        };
10578        self.style
10579            .as_ref()
10580            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10581    }
10582
10583    fn render_context_menu_aside(
10584        &mut self,
10585        max_size: Size<Pixels>,
10586        window: &mut Window,
10587        cx: &mut Context<Editor>,
10588    ) -> Option<AnyElement> {
10589        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10590            if menu.visible() {
10591                menu.render_aside(max_size, window, cx)
10592            } else {
10593                None
10594            }
10595        })
10596    }
10597
10598    fn hide_context_menu(
10599        &mut self,
10600        window: &mut Window,
10601        cx: &mut Context<Self>,
10602    ) -> Option<CodeContextMenu> {
10603        cx.notify();
10604        self.completion_tasks.clear();
10605        let context_menu = self.context_menu.borrow_mut().take();
10606        self.stale_edit_prediction_in_menu.take();
10607        self.update_visible_edit_prediction(window, cx);
10608        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10609            && let Some(completion_provider) = &self.completion_provider
10610        {
10611            completion_provider.selection_changed(None, window, cx);
10612        }
10613        context_menu
10614    }
10615
10616    fn show_snippet_choices(
10617        &mut self,
10618        choices: &Vec<String>,
10619        selection: Range<Anchor>,
10620        cx: &mut Context<Self>,
10621    ) {
10622        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
10623        let Some((buffer_snapshot, range)) =
10624            buffer_snapshot.anchor_range_to_buffer_anchor_range(selection.clone())
10625        else {
10626            return;
10627        };
10628        let Some(buffer) = self.buffer.read(cx).buffer(buffer_snapshot.remote_id()) else {
10629            return;
10630        };
10631
10632        let id = post_inc(&mut self.next_completion_id);
10633        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10634        let mut context_menu = self.context_menu.borrow_mut();
10635        let old_menu = context_menu.take();
10636        *context_menu = Some(CodeContextMenu::Completions(
10637            CompletionsMenu::new_snippet_choices(
10638                id,
10639                true,
10640                choices,
10641                selection.start,
10642                range,
10643                buffer,
10644                old_menu.map(|menu| menu.primary_scroll_handle()),
10645                snippet_sort_order,
10646            ),
10647        ));
10648    }
10649
10650    pub fn insert_snippet(
10651        &mut self,
10652        insertion_ranges: &[Range<MultiBufferOffset>],
10653        snippet: Snippet,
10654        window: &mut Window,
10655        cx: &mut Context<Self>,
10656    ) -> Result<()> {
10657        struct Tabstop<T> {
10658            is_end_tabstop: bool,
10659            ranges: Vec<Range<T>>,
10660            choices: Option<Vec<String>>,
10661        }
10662
10663        let tabstops = self.buffer.update(cx, |buffer, cx| {
10664            let snippet_text: Arc<str> = snippet.text.clone().into();
10665            let edits = insertion_ranges
10666                .iter()
10667                .cloned()
10668                .map(|range| (range, snippet_text.clone()));
10669            let autoindent_mode = AutoindentMode::Block {
10670                original_indent_columns: Vec::new(),
10671            };
10672            buffer.edit(edits, Some(autoindent_mode), cx);
10673
10674            let snapshot = &*buffer.read(cx);
10675            let snippet = &snippet;
10676            snippet
10677                .tabstops
10678                .iter()
10679                .map(|tabstop| {
10680                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10681                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10682                    });
10683                    let mut tabstop_ranges = tabstop
10684                        .ranges
10685                        .iter()
10686                        .flat_map(|tabstop_range| {
10687                            let mut delta = 0_isize;
10688                            insertion_ranges.iter().map(move |insertion_range| {
10689                                let insertion_start = insertion_range.start + delta;
10690                                delta += snippet.text.len() as isize
10691                                    - (insertion_range.end - insertion_range.start) as isize;
10692
10693                                let start =
10694                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10695                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10696                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10697                            })
10698                        })
10699                        .collect::<Vec<_>>();
10700                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10701
10702                    Tabstop {
10703                        is_end_tabstop,
10704                        ranges: tabstop_ranges,
10705                        choices: tabstop.choices.clone(),
10706                    }
10707                })
10708                .collect::<Vec<_>>()
10709        });
10710        if let Some(tabstop) = tabstops.first() {
10711            self.change_selections(Default::default(), window, cx, |s| {
10712                // Reverse order so that the first range is the newest created selection.
10713                // Completions will use it and autoscroll will prioritize it.
10714                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10715            });
10716
10717            if let Some(choices) = &tabstop.choices
10718                && let Some(selection) = tabstop.ranges.first()
10719            {
10720                self.show_snippet_choices(choices, selection.clone(), cx)
10721            }
10722
10723            // If we're already at the last tabstop and it's at the end of the snippet,
10724            // we're done, we don't need to keep the state around.
10725            if !tabstop.is_end_tabstop {
10726                let choices = tabstops
10727                    .iter()
10728                    .map(|tabstop| tabstop.choices.clone())
10729                    .collect();
10730
10731                let ranges = tabstops
10732                    .into_iter()
10733                    .map(|tabstop| tabstop.ranges)
10734                    .collect::<Vec<_>>();
10735
10736                self.snippet_stack.push(SnippetState {
10737                    active_index: 0,
10738                    ranges,
10739                    choices,
10740                });
10741            }
10742
10743            // Check whether the just-entered snippet ends with an auto-closable bracket.
10744            if self.autoclose_regions.is_empty() {
10745                let snapshot = self.buffer.read(cx).snapshot(cx);
10746                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10747                    let selection_head = selection.head();
10748                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10749                        continue;
10750                    };
10751
10752                    let mut bracket_pair = None;
10753                    let max_lookup_length = scope
10754                        .brackets()
10755                        .map(|(pair, _)| {
10756                            pair.start
10757                                .as_str()
10758                                .chars()
10759                                .count()
10760                                .max(pair.end.as_str().chars().count())
10761                        })
10762                        .max();
10763                    if let Some(max_lookup_length) = max_lookup_length {
10764                        let next_text = snapshot
10765                            .chars_at(selection_head)
10766                            .take(max_lookup_length)
10767                            .collect::<String>();
10768                        let prev_text = snapshot
10769                            .reversed_chars_at(selection_head)
10770                            .take(max_lookup_length)
10771                            .collect::<String>();
10772
10773                        for (pair, enabled) in scope.brackets() {
10774                            if enabled
10775                                && pair.close
10776                                && prev_text.starts_with(pair.start.as_str())
10777                                && next_text.starts_with(pair.end.as_str())
10778                            {
10779                                bracket_pair = Some(pair.clone());
10780                                break;
10781                            }
10782                        }
10783                    }
10784
10785                    if let Some(pair) = bracket_pair {
10786                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10787                        let autoclose_enabled =
10788                            self.use_autoclose && snapshot_settings.use_autoclose;
10789                        if autoclose_enabled {
10790                            let start = snapshot.anchor_after(selection_head);
10791                            let end = snapshot.anchor_after(selection_head);
10792                            self.autoclose_regions.push(AutocloseRegion {
10793                                selection_id: selection.id,
10794                                range: start..end,
10795                                pair,
10796                            });
10797                        }
10798                    }
10799                }
10800            }
10801        }
10802        Ok(())
10803    }
10804
10805    pub fn move_to_next_snippet_tabstop(
10806        &mut self,
10807        window: &mut Window,
10808        cx: &mut Context<Self>,
10809    ) -> bool {
10810        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10811    }
10812
10813    pub fn move_to_prev_snippet_tabstop(
10814        &mut self,
10815        window: &mut Window,
10816        cx: &mut Context<Self>,
10817    ) -> bool {
10818        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10819    }
10820
10821    pub fn move_to_snippet_tabstop(
10822        &mut self,
10823        bias: Bias,
10824        window: &mut Window,
10825        cx: &mut Context<Self>,
10826    ) -> bool {
10827        if let Some(mut snippet) = self.snippet_stack.pop() {
10828            match bias {
10829                Bias::Left => {
10830                    if snippet.active_index > 0 {
10831                        snippet.active_index -= 1;
10832                    } else {
10833                        self.snippet_stack.push(snippet);
10834                        return false;
10835                    }
10836                }
10837                Bias::Right => {
10838                    if snippet.active_index + 1 < snippet.ranges.len() {
10839                        snippet.active_index += 1;
10840                    } else {
10841                        self.snippet_stack.push(snippet);
10842                        return false;
10843                    }
10844                }
10845            }
10846            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10847                self.change_selections(Default::default(), window, cx, |s| {
10848                    // Reverse order so that the first range is the newest created selection.
10849                    // Completions will use it and autoscroll will prioritize it.
10850                    s.select_ranges(current_ranges.iter().rev().cloned())
10851                });
10852
10853                if let Some(choices) = &snippet.choices[snippet.active_index]
10854                    && let Some(selection) = current_ranges.first()
10855                {
10856                    self.show_snippet_choices(choices, selection.clone(), cx);
10857                }
10858
10859                // If snippet state is not at the last tabstop, push it back on the stack
10860                if snippet.active_index + 1 < snippet.ranges.len() {
10861                    self.snippet_stack.push(snippet);
10862                }
10863                return true;
10864            }
10865        }
10866
10867        false
10868    }
10869
10870    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10871        self.transact(window, cx, |this, window, cx| {
10872            this.select_all(&SelectAll, window, cx);
10873            this.insert("", window, cx);
10874        });
10875    }
10876
10877    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10878        if self.read_only(cx) {
10879            return;
10880        }
10881        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10882        self.transact(window, cx, |this, window, cx| {
10883            this.select_autoclose_pair(window, cx);
10884
10885            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10886
10887            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10888            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10889            for selection in &mut selections {
10890                if selection.is_empty() {
10891                    let old_head = selection.head();
10892                    let mut new_head =
10893                        movement::left(&display_map, old_head.to_display_point(&display_map))
10894                            .to_point(&display_map);
10895                    if let Some((buffer, line_buffer_range)) = display_map
10896                        .buffer_snapshot()
10897                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10898                    {
10899                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10900                        let indent_len = match indent_size.kind {
10901                            IndentKind::Space => {
10902                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10903                            }
10904                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10905                        };
10906                        if old_head.column <= indent_size.len && old_head.column > 0 {
10907                            let indent_len = indent_len.get();
10908                            new_head = cmp::min(
10909                                new_head,
10910                                MultiBufferPoint::new(
10911                                    old_head.row,
10912                                    ((old_head.column - 1) / indent_len) * indent_len,
10913                                ),
10914                            );
10915                        }
10916                    }
10917
10918                    selection.set_head(new_head, SelectionGoal::None);
10919                }
10920            }
10921
10922            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10923            this.insert("", window, cx);
10924            linked_edits.apply_with_left_expansion(cx);
10925            this.refresh_edit_prediction(true, false, window, cx);
10926            refresh_linked_ranges(this, window, cx);
10927        });
10928    }
10929
10930    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10931        if self.read_only(cx) {
10932            return;
10933        }
10934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10935        self.transact(window, cx, |this, window, cx| {
10936            this.change_selections(Default::default(), window, cx, |s| {
10937                s.move_with(&mut |map, selection| {
10938                    if selection.is_empty() {
10939                        let cursor = movement::right(map, selection.head());
10940                        selection.end = cursor;
10941                        selection.reversed = true;
10942                        selection.goal = SelectionGoal::None;
10943                    }
10944                })
10945            });
10946            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10947            this.insert("", window, cx);
10948            linked_edits.apply(cx);
10949            this.refresh_edit_prediction(true, false, window, cx);
10950            refresh_linked_ranges(this, window, cx);
10951        });
10952    }
10953
10954    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10955        if self.mode.is_single_line() {
10956            cx.propagate();
10957            return;
10958        }
10959
10960        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10961        if self.move_to_prev_snippet_tabstop(window, cx) {
10962            return;
10963        }
10964        self.outdent(&Outdent, window, cx);
10965    }
10966
10967    pub fn next_snippet_tabstop(
10968        &mut self,
10969        _: &NextSnippetTabstop,
10970        window: &mut Window,
10971        cx: &mut Context<Self>,
10972    ) {
10973        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10974            cx.propagate();
10975            return;
10976        }
10977
10978        if self.move_to_next_snippet_tabstop(window, cx) {
10979            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10980            return;
10981        }
10982        cx.propagate();
10983    }
10984
10985    pub fn previous_snippet_tabstop(
10986        &mut self,
10987        _: &PreviousSnippetTabstop,
10988        window: &mut Window,
10989        cx: &mut Context<Self>,
10990    ) {
10991        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10992            cx.propagate();
10993            return;
10994        }
10995
10996        if self.move_to_prev_snippet_tabstop(window, cx) {
10997            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10998            return;
10999        }
11000        cx.propagate();
11001    }
11002
11003    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
11004        if self.mode.is_single_line() {
11005            cx.propagate();
11006            return;
11007        }
11008
11009        if self.move_to_next_snippet_tabstop(window, cx) {
11010            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11011            return;
11012        }
11013        if self.read_only(cx) {
11014            return;
11015        }
11016        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11017        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
11018        let buffer = self.buffer.read(cx);
11019        let snapshot = buffer.snapshot(cx);
11020        let rows_iter = selections.iter().map(|s| s.head().row);
11021        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
11022
11023        let has_some_cursor_in_whitespace = selections
11024            .iter()
11025            .filter(|selection| selection.is_empty())
11026            .any(|selection| {
11027                let cursor = selection.head();
11028                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11029                cursor.column < current_indent.len
11030            });
11031
11032        let mut edits = Vec::new();
11033        let mut prev_edited_row = 0;
11034        let mut row_delta = 0;
11035        for selection in &mut selections {
11036            if selection.start.row != prev_edited_row {
11037                row_delta = 0;
11038            }
11039            prev_edited_row = selection.end.row;
11040
11041            // If cursor is after a list prefix, make selection non-empty to trigger line indent
11042            if selection.is_empty() {
11043                let cursor = selection.head();
11044                let settings = buffer.language_settings_at(cursor, cx);
11045                if settings.indent_list_on_tab {
11046                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
11047                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
11048                            row_delta = Self::indent_selection(
11049                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
11050                            );
11051                            continue;
11052                        }
11053                    }
11054                }
11055            }
11056
11057            // If the selection is non-empty, then increase the indentation of the selected lines.
11058            if !selection.is_empty() {
11059                row_delta =
11060                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11061                continue;
11062            }
11063
11064            let cursor = selection.head();
11065            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11066            if let Some(suggested_indent) =
11067                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
11068            {
11069                // Don't do anything if already at suggested indent
11070                // and there is any other cursor which is not
11071                if has_some_cursor_in_whitespace
11072                    && cursor.column == current_indent.len
11073                    && current_indent.len == suggested_indent.len
11074                {
11075                    continue;
11076                }
11077
11078                // Adjust line and move cursor to suggested indent
11079                // if cursor is not at suggested indent
11080                if cursor.column < suggested_indent.len
11081                    && cursor.column <= current_indent.len
11082                    && current_indent.len <= suggested_indent.len
11083                {
11084                    selection.start = Point::new(cursor.row, suggested_indent.len);
11085                    selection.end = selection.start;
11086                    if row_delta == 0 {
11087                        edits.extend(Buffer::edit_for_indent_size_adjustment(
11088                            cursor.row,
11089                            current_indent,
11090                            suggested_indent,
11091                        ));
11092                        row_delta = suggested_indent.len - current_indent.len;
11093                    }
11094                    continue;
11095                }
11096
11097                // If current indent is more than suggested indent
11098                // only move cursor to current indent and skip indent
11099                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11100                    selection.start = Point::new(cursor.row, current_indent.len);
11101                    selection.end = selection.start;
11102                    continue;
11103                }
11104            }
11105
11106            // Otherwise, insert a hard or soft tab.
11107            let settings = buffer.language_settings_at(cursor, cx);
11108            let tab_size = if settings.hard_tabs {
11109                IndentSize::tab()
11110            } else {
11111                let tab_size = settings.tab_size.get();
11112                let indent_remainder = snapshot
11113                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11114                    .flat_map(str::chars)
11115                    .fold(row_delta % tab_size, |counter: u32, c| {
11116                        if c == '\t' {
11117                            0
11118                        } else {
11119                            (counter + 1) % tab_size
11120                        }
11121                    });
11122
11123                let chars_to_next_tab_stop = tab_size - indent_remainder;
11124                IndentSize::spaces(chars_to_next_tab_stop)
11125            };
11126            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11127            selection.end = selection.start;
11128            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11129            row_delta += tab_size.len;
11130        }
11131
11132        self.transact(window, cx, |this, window, cx| {
11133            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11134            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11135            this.refresh_edit_prediction(true, false, window, cx);
11136        });
11137    }
11138
11139    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11140        if self.read_only(cx) {
11141            return;
11142        }
11143        if self.mode.is_single_line() {
11144            cx.propagate();
11145            return;
11146        }
11147
11148        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11149        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11150        let mut prev_edited_row = 0;
11151        let mut row_delta = 0;
11152        let mut edits = Vec::new();
11153        let buffer = self.buffer.read(cx);
11154        let snapshot = buffer.snapshot(cx);
11155        for selection in &mut selections {
11156            if selection.start.row != prev_edited_row {
11157                row_delta = 0;
11158            }
11159            prev_edited_row = selection.end.row;
11160
11161            row_delta =
11162                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11163        }
11164
11165        self.transact(window, cx, |this, window, cx| {
11166            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11167            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11168        });
11169    }
11170
11171    fn indent_selection(
11172        buffer: &MultiBuffer,
11173        snapshot: &MultiBufferSnapshot,
11174        selection: &mut Selection<Point>,
11175        edits: &mut Vec<(Range<Point>, String)>,
11176        delta_for_start_row: u32,
11177        cx: &App,
11178    ) -> u32 {
11179        let settings = buffer.language_settings_at(selection.start, cx);
11180        let tab_size = settings.tab_size.get();
11181        let indent_kind = if settings.hard_tabs {
11182            IndentKind::Tab
11183        } else {
11184            IndentKind::Space
11185        };
11186        let mut start_row = selection.start.row;
11187        let mut end_row = selection.end.row + 1;
11188
11189        // If a selection ends at the beginning of a line, don't indent
11190        // that last line.
11191        if selection.end.column == 0 && selection.end.row > selection.start.row {
11192            end_row -= 1;
11193        }
11194
11195        // Avoid re-indenting a row that has already been indented by a
11196        // previous selection, but still update this selection's column
11197        // to reflect that indentation.
11198        if delta_for_start_row > 0 {
11199            start_row += 1;
11200            selection.start.column += delta_for_start_row;
11201            if selection.end.row == selection.start.row {
11202                selection.end.column += delta_for_start_row;
11203            }
11204        }
11205
11206        let mut delta_for_end_row = 0;
11207        let has_multiple_rows = start_row + 1 != end_row;
11208        for row in start_row..end_row {
11209            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11210            let indent_delta = match (current_indent.kind, indent_kind) {
11211                (IndentKind::Space, IndentKind::Space) => {
11212                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11213                    IndentSize::spaces(columns_to_next_tab_stop)
11214                }
11215                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11216                (_, IndentKind::Tab) => IndentSize::tab(),
11217            };
11218
11219            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11220                0
11221            } else {
11222                selection.start.column
11223            };
11224            let row_start = Point::new(row, start);
11225            edits.push((
11226                row_start..row_start,
11227                indent_delta.chars().collect::<String>(),
11228            ));
11229
11230            // Update this selection's endpoints to reflect the indentation.
11231            if row == selection.start.row {
11232                selection.start.column += indent_delta.len;
11233            }
11234            if row == selection.end.row {
11235                selection.end.column += indent_delta.len;
11236                delta_for_end_row = indent_delta.len;
11237            }
11238        }
11239
11240        if selection.start.row == selection.end.row {
11241            delta_for_start_row + delta_for_end_row
11242        } else {
11243            delta_for_end_row
11244        }
11245    }
11246
11247    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11248        if self.read_only(cx) {
11249            return;
11250        }
11251        if self.mode.is_single_line() {
11252            cx.propagate();
11253            return;
11254        }
11255
11256        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11257        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11258        let selections = self.selections.all::<Point>(&display_map);
11259        let mut deletion_ranges = Vec::new();
11260        let mut last_outdent = None;
11261        {
11262            let buffer = self.buffer.read(cx);
11263            let snapshot = buffer.snapshot(cx);
11264            for selection in &selections {
11265                let settings = buffer.language_settings_at(selection.start, cx);
11266                let tab_size = settings.tab_size.get();
11267                let mut rows = selection.spanned_rows(false, &display_map);
11268
11269                // Avoid re-outdenting a row that has already been outdented by a
11270                // previous selection.
11271                if let Some(last_row) = last_outdent
11272                    && last_row == rows.start
11273                {
11274                    rows.start = rows.start.next_row();
11275                }
11276                let has_multiple_rows = rows.len() > 1;
11277                for row in rows.iter_rows() {
11278                    let indent_size = snapshot.indent_size_for_line(row);
11279                    if indent_size.len > 0 {
11280                        let deletion_len = match indent_size.kind {
11281                            IndentKind::Space => {
11282                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11283                                if columns_to_prev_tab_stop == 0 {
11284                                    tab_size
11285                                } else {
11286                                    columns_to_prev_tab_stop
11287                                }
11288                            }
11289                            IndentKind::Tab => 1,
11290                        };
11291                        let start = if has_multiple_rows
11292                            || deletion_len > selection.start.column
11293                            || indent_size.len < selection.start.column
11294                        {
11295                            0
11296                        } else {
11297                            selection.start.column - deletion_len
11298                        };
11299                        deletion_ranges.push(
11300                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11301                        );
11302                        last_outdent = Some(row);
11303                    }
11304                }
11305            }
11306        }
11307
11308        self.transact(window, cx, |this, window, cx| {
11309            this.buffer.update(cx, |buffer, cx| {
11310                let empty_str: Arc<str> = Arc::default();
11311                buffer.edit(
11312                    deletion_ranges
11313                        .into_iter()
11314                        .map(|range| (range, empty_str.clone())),
11315                    None,
11316                    cx,
11317                );
11318            });
11319            let selections = this
11320                .selections
11321                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11322            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11323        });
11324    }
11325
11326    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11327        if self.read_only(cx) {
11328            return;
11329        }
11330        if self.mode.is_single_line() {
11331            cx.propagate();
11332            return;
11333        }
11334
11335        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11336        let selections = self
11337            .selections
11338            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11339            .into_iter()
11340            .map(|s| s.range());
11341
11342        self.transact(window, cx, |this, window, cx| {
11343            this.buffer.update(cx, |buffer, cx| {
11344                buffer.autoindent_ranges(selections, cx);
11345            });
11346            let selections = this
11347                .selections
11348                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11349            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11350        });
11351    }
11352
11353    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11354        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11355        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11356        let selections = self.selections.all::<Point>(&display_map);
11357
11358        let mut new_cursors = Vec::new();
11359        let mut edit_ranges = Vec::new();
11360        let mut selections = selections.iter().peekable();
11361        while let Some(selection) = selections.next() {
11362            let mut rows = selection.spanned_rows(false, &display_map);
11363
11364            // Accumulate contiguous regions of rows that we want to delete.
11365            while let Some(next_selection) = selections.peek() {
11366                let next_rows = next_selection.spanned_rows(false, &display_map);
11367                if next_rows.start <= rows.end {
11368                    rows.end = next_rows.end;
11369                    selections.next().unwrap();
11370                } else {
11371                    break;
11372                }
11373            }
11374
11375            let buffer = display_map.buffer_snapshot();
11376            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11377            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11378                // If there's a line after the range, delete the \n from the end of the row range
11379                (
11380                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11381                    rows.end,
11382                )
11383            } else {
11384                // If there isn't a line after the range, delete the \n from the line before the
11385                // start of the row range
11386                edit_start = edit_start.saturating_sub_usize(1);
11387                (buffer.len(), rows.start.previous_row())
11388            };
11389
11390            let text_layout_details = self.text_layout_details(window, cx);
11391            let x = display_map.x_for_display_point(
11392                selection.head().to_display_point(&display_map),
11393                &text_layout_details,
11394            );
11395            let row = Point::new(target_row.0, 0)
11396                .to_display_point(&display_map)
11397                .row();
11398            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11399
11400            new_cursors.push((
11401                selection.id,
11402                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11403                SelectionGoal::None,
11404            ));
11405            edit_ranges.push(edit_start..edit_end);
11406        }
11407
11408        self.transact(window, cx, |this, window, cx| {
11409            let buffer = this.buffer.update(cx, |buffer, cx| {
11410                let empty_str: Arc<str> = Arc::default();
11411                buffer.edit(
11412                    edit_ranges
11413                        .into_iter()
11414                        .map(|range| (range, empty_str.clone())),
11415                    None,
11416                    cx,
11417                );
11418                buffer.snapshot(cx)
11419            });
11420            let new_selections = new_cursors
11421                .into_iter()
11422                .map(|(id, cursor, goal)| {
11423                    let cursor = cursor.to_point(&buffer);
11424                    Selection {
11425                        id,
11426                        start: cursor,
11427                        end: cursor,
11428                        reversed: false,
11429                        goal,
11430                    }
11431                })
11432                .collect();
11433
11434            this.change_selections(Default::default(), window, cx, |s| {
11435                s.select(new_selections);
11436            });
11437        });
11438    }
11439
11440    pub fn join_lines_impl(
11441        &mut self,
11442        insert_whitespace: bool,
11443        window: &mut Window,
11444        cx: &mut Context<Self>,
11445    ) {
11446        if self.read_only(cx) {
11447            return;
11448        }
11449        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11450        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11451            let start = MultiBufferRow(selection.start.row);
11452            // Treat single line selections as if they include the next line. Otherwise this action
11453            // would do nothing for single line selections individual cursors.
11454            let end = if selection.start.row == selection.end.row {
11455                MultiBufferRow(selection.start.row + 1)
11456            } else if selection.end.column == 0 {
11457                // If the selection ends at the start of a line, it's logically at the end of the
11458                // previous line (plus its newline).
11459                // Don't include the end line unless there's only one line selected.
11460                if selection.start.row + 1 == selection.end.row {
11461                    MultiBufferRow(selection.end.row)
11462                } else {
11463                    MultiBufferRow(selection.end.row - 1)
11464                }
11465            } else {
11466                MultiBufferRow(selection.end.row)
11467            };
11468
11469            if let Some(last_row_range) = row_ranges.last_mut()
11470                && start <= last_row_range.end
11471            {
11472                last_row_range.end = end;
11473                continue;
11474            }
11475            row_ranges.push(start..end);
11476        }
11477
11478        let snapshot = self.buffer.read(cx).snapshot(cx);
11479        let mut cursor_positions = Vec::new();
11480        for row_range in &row_ranges {
11481            let anchor = snapshot.anchor_before(Point::new(
11482                row_range.end.previous_row().0,
11483                snapshot.line_len(row_range.end.previous_row()),
11484            ));
11485            cursor_positions.push(anchor..anchor);
11486        }
11487
11488        self.transact(window, cx, |this, window, cx| {
11489            for row_range in row_ranges.into_iter().rev() {
11490                for row in row_range.iter_rows().rev() {
11491                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11492                    let next_line_row = row.next_row();
11493                    let indent = snapshot.indent_size_for_line(next_line_row);
11494                    let mut join_start_column = indent.len;
11495
11496                    if let Some(language_scope) =
11497                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11498                    {
11499                        let line_end =
11500                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11501                        let line_text_after_indent = snapshot
11502                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11503                            .collect::<String>();
11504
11505                        if !line_text_after_indent.is_empty() {
11506                            let block_prefix = language_scope
11507                                .block_comment()
11508                                .map(|c| c.prefix.as_ref())
11509                                .filter(|p| !p.is_empty());
11510                            let doc_prefix = language_scope
11511                                .documentation_comment()
11512                                .map(|c| c.prefix.as_ref())
11513                                .filter(|p| !p.is_empty());
11514                            let all_prefixes = language_scope
11515                                .line_comment_prefixes()
11516                                .iter()
11517                                .map(|p| p.as_ref())
11518                                .chain(block_prefix)
11519                                .chain(doc_prefix)
11520                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11521
11522                            let mut longest_prefix_len = None;
11523                            for prefix in all_prefixes {
11524                                let trimmed = prefix.trim_end();
11525                                if line_text_after_indent.starts_with(trimmed) {
11526                                    let candidate_len =
11527                                        if line_text_after_indent.starts_with(prefix) {
11528                                            prefix.len()
11529                                        } else {
11530                                            trimmed.len()
11531                                        };
11532                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11533                                        longest_prefix_len = Some(candidate_len);
11534                                    }
11535                                }
11536                            }
11537
11538                            if let Some(prefix_len) = longest_prefix_len {
11539                                join_start_column =
11540                                    join_start_column.saturating_add(prefix_len as u32);
11541                            }
11542                        }
11543                    }
11544
11545                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11546
11547                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11548                        && insert_whitespace
11549                    {
11550                        " "
11551                    } else {
11552                        ""
11553                    };
11554
11555                    this.buffer.update(cx, |buffer, cx| {
11556                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11557                    });
11558                }
11559            }
11560
11561            this.change_selections(Default::default(), window, cx, |s| {
11562                s.select_anchor_ranges(cursor_positions)
11563            });
11564        });
11565    }
11566
11567    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11569        self.join_lines_impl(true, window, cx);
11570    }
11571
11572    pub fn sort_lines_case_sensitive(
11573        &mut self,
11574        _: &SortLinesCaseSensitive,
11575        window: &mut Window,
11576        cx: &mut Context<Self>,
11577    ) {
11578        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11579    }
11580
11581    pub fn sort_lines_by_length(
11582        &mut self,
11583        _: &SortLinesByLength,
11584        window: &mut Window,
11585        cx: &mut Context<Self>,
11586    ) {
11587        self.manipulate_immutable_lines(window, cx, |lines| {
11588            lines.sort_by_key(|&line| line.chars().count())
11589        })
11590    }
11591
11592    pub fn sort_lines_case_insensitive(
11593        &mut self,
11594        _: &SortLinesCaseInsensitive,
11595        window: &mut Window,
11596        cx: &mut Context<Self>,
11597    ) {
11598        self.manipulate_immutable_lines(window, cx, |lines| {
11599            lines.sort_by_key(|line| line.to_lowercase())
11600        })
11601    }
11602
11603    pub fn unique_lines_case_insensitive(
11604        &mut self,
11605        _: &UniqueLinesCaseInsensitive,
11606        window: &mut Window,
11607        cx: &mut Context<Self>,
11608    ) {
11609        self.manipulate_immutable_lines(window, cx, |lines| {
11610            let mut seen = HashSet::default();
11611            lines.retain(|line| seen.insert(line.to_lowercase()));
11612        })
11613    }
11614
11615    pub fn unique_lines_case_sensitive(
11616        &mut self,
11617        _: &UniqueLinesCaseSensitive,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        self.manipulate_immutable_lines(window, cx, |lines| {
11622            let mut seen = HashSet::default();
11623            lines.retain(|line| seen.insert(*line));
11624        })
11625    }
11626
11627    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11628        let snapshot = self.buffer.read(cx).snapshot(cx);
11629        for selection in self.selections.disjoint_anchors_arc().iter() {
11630            if snapshot
11631                .language_at(selection.start)
11632                .and_then(|lang| lang.config().wrap_characters.as_ref())
11633                .is_some()
11634            {
11635                return true;
11636            }
11637        }
11638        false
11639    }
11640
11641    fn wrap_selections_in_tag(
11642        &mut self,
11643        _: &WrapSelectionsInTag,
11644        window: &mut Window,
11645        cx: &mut Context<Self>,
11646    ) {
11647        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11648
11649        let snapshot = self.buffer.read(cx).snapshot(cx);
11650
11651        let mut edits = Vec::new();
11652        let mut boundaries = Vec::new();
11653
11654        for selection in self
11655            .selections
11656            .all_adjusted(&self.display_snapshot(cx))
11657            .iter()
11658        {
11659            let Some(wrap_config) = snapshot
11660                .language_at(selection.start)
11661                .and_then(|lang| lang.config().wrap_characters.clone())
11662            else {
11663                continue;
11664            };
11665
11666            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11667            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11668
11669            let start_before = snapshot.anchor_before(selection.start);
11670            let end_after = snapshot.anchor_after(selection.end);
11671
11672            edits.push((start_before..start_before, open_tag));
11673            edits.push((end_after..end_after, close_tag));
11674
11675            boundaries.push((
11676                start_before,
11677                end_after,
11678                wrap_config.start_prefix.len(),
11679                wrap_config.end_suffix.len(),
11680            ));
11681        }
11682
11683        if edits.is_empty() {
11684            return;
11685        }
11686
11687        self.transact(window, cx, |this, window, cx| {
11688            let buffer = this.buffer.update(cx, |buffer, cx| {
11689                buffer.edit(edits, None, cx);
11690                buffer.snapshot(cx)
11691            });
11692
11693            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11694            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11695                boundaries.into_iter()
11696            {
11697                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11698                let close_offset = end_after
11699                    .to_offset(&buffer)
11700                    .saturating_sub_usize(end_suffix_len);
11701                new_selections.push(open_offset..open_offset);
11702                new_selections.push(close_offset..close_offset);
11703            }
11704
11705            this.change_selections(Default::default(), window, cx, |s| {
11706                s.select_ranges(new_selections);
11707            });
11708
11709            this.request_autoscroll(Autoscroll::fit(), cx);
11710        });
11711    }
11712
11713    pub fn toggle_read_only(
11714        &mut self,
11715        _: &workspace::ToggleReadOnlyFile,
11716        _: &mut Window,
11717        cx: &mut Context<Self>,
11718    ) {
11719        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11720            buffer.update(cx, |buffer, cx| {
11721                buffer.set_capability(
11722                    match buffer.capability() {
11723                        Capability::ReadWrite => Capability::Read,
11724                        Capability::Read => Capability::ReadWrite,
11725                        Capability::ReadOnly => Capability::ReadOnly,
11726                    },
11727                    cx,
11728                );
11729            })
11730        }
11731    }
11732
11733    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11734        let Some(project) = self.project.clone() else {
11735            return;
11736        };
11737        let task = self.reload(project, window, cx);
11738        self.detach_and_notify_err(task, window, cx);
11739    }
11740
11741    pub fn restore_file(
11742        &mut self,
11743        _: &::git::RestoreFile,
11744        window: &mut Window,
11745        cx: &mut Context<Self>,
11746    ) {
11747        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11748        let mut buffer_ids = HashSet::default();
11749        let snapshot = self.buffer().read(cx).snapshot(cx);
11750        for selection in self
11751            .selections
11752            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11753        {
11754            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11755        }
11756
11757        let ranges = buffer_ids
11758            .into_iter()
11759            .flat_map(|buffer_id| snapshot.range_for_buffer(buffer_id))
11760            .collect::<Vec<_>>();
11761
11762        self.restore_hunks_in_ranges(ranges, window, cx);
11763    }
11764
11765    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11766        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11767        let selections = self
11768            .selections
11769            .all(&self.display_snapshot(cx))
11770            .into_iter()
11771            .map(|s| s.range())
11772            .collect();
11773        self.restore_hunks_in_ranges(selections, window, cx);
11774    }
11775
11776    /// Restores the diff hunks in the editor's selections and moves the cursor
11777    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11778    /// not all diff hunks are expanded.
11779    pub fn restore_and_next(
11780        &mut self,
11781        _: &::git::RestoreAndNext,
11782        window: &mut Window,
11783        cx: &mut Context<Self>,
11784    ) {
11785        let selections = self
11786            .selections
11787            .all(&self.display_snapshot(cx))
11788            .into_iter()
11789            .map(|selection| selection.range())
11790            .collect();
11791
11792        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11793        self.restore_hunks_in_ranges(selections, window, cx);
11794
11795        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11796        let wrap_around = !all_diff_hunks_expanded;
11797        let snapshot = self.snapshot(window, cx);
11798        let position = self
11799            .selections
11800            .newest::<Point>(&snapshot.display_snapshot)
11801            .head();
11802
11803        self.go_to_hunk_before_or_after_position(
11804            &snapshot,
11805            position,
11806            Direction::Next,
11807            wrap_around,
11808            window,
11809            cx,
11810        );
11811    }
11812
11813    pub fn restore_hunks_in_ranges(
11814        &mut self,
11815        ranges: Vec<Range<Point>>,
11816        window: &mut Window,
11817        cx: &mut Context<Editor>,
11818    ) {
11819        if self.delegate_stage_and_restore {
11820            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11821            if !hunks.is_empty() {
11822                cx.emit(EditorEvent::RestoreRequested { hunks });
11823            }
11824            return;
11825        }
11826        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11827        self.transact(window, cx, |editor, window, cx| {
11828            editor.restore_diff_hunks(hunks, cx);
11829            let selections = editor
11830                .selections
11831                .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
11832            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11833                s.select(selections);
11834            });
11835        });
11836    }
11837
11838    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11839        let mut revert_changes = HashMap::default();
11840        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11841        for (buffer_id, hunks) in &chunk_by {
11842            let hunks = hunks.collect::<Vec<_>>();
11843            for hunk in &hunks {
11844                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11845            }
11846            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11847        }
11848        if !revert_changes.is_empty() {
11849            self.buffer().update(cx, |multi_buffer, cx| {
11850                for (buffer_id, changes) in revert_changes {
11851                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11852                        buffer.update(cx, |buffer, cx| {
11853                            buffer.edit(
11854                                changes
11855                                    .into_iter()
11856                                    .map(|(range, text)| (range, text.to_string())),
11857                                None,
11858                                cx,
11859                            );
11860                        });
11861                    }
11862                }
11863            });
11864        }
11865    }
11866
11867    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11868        if let Some(status) = self
11869            .addons
11870            .iter()
11871            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11872        {
11873            return Some(status);
11874        }
11875        self.project
11876            .as_ref()?
11877            .read(cx)
11878            .status_for_buffer_id(buffer_id, cx)
11879    }
11880
11881    pub fn open_active_item_in_terminal(
11882        &mut self,
11883        _: &OpenInTerminal,
11884        window: &mut Window,
11885        cx: &mut Context<Self>,
11886    ) {
11887        if let Some(working_directory) = self.active_buffer(cx).and_then(|buffer| {
11888            let project_path = buffer.read(cx).project_path(cx)?;
11889            let project = self.project()?.read(cx);
11890            let entry = project.entry_for_path(&project_path, cx)?;
11891            let parent = match &entry.canonical_path {
11892                Some(canonical_path) => canonical_path.to_path_buf(),
11893                None => project.absolute_path(&project_path, cx)?,
11894            }
11895            .parent()?
11896            .to_path_buf();
11897            Some(parent)
11898        }) {
11899            window.dispatch_action(
11900                OpenTerminal {
11901                    working_directory,
11902                    local: false,
11903                }
11904                .boxed_clone(),
11905                cx,
11906            );
11907        }
11908    }
11909
11910    fn set_breakpoint_context_menu(
11911        &mut self,
11912        display_row: DisplayRow,
11913        position: Option<Anchor>,
11914        clicked_point: gpui::Point<Pixels>,
11915        window: &mut Window,
11916        cx: &mut Context<Self>,
11917    ) {
11918        let source = self
11919            .buffer
11920            .read(cx)
11921            .snapshot(cx)
11922            .anchor_before(Point::new(display_row.0, 0u32));
11923
11924        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11925
11926        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11927            self,
11928            source,
11929            clicked_point,
11930            context_menu,
11931            window,
11932            cx,
11933        );
11934    }
11935
11936    fn add_edit_breakpoint_block(
11937        &mut self,
11938        anchor: Anchor,
11939        breakpoint: &Breakpoint,
11940        edit_action: BreakpointPromptEditAction,
11941        window: &mut Window,
11942        cx: &mut Context<Self>,
11943    ) {
11944        let weak_editor = cx.weak_entity();
11945        let bp_prompt = cx.new(|cx| {
11946            BreakpointPromptEditor::new(
11947                weak_editor,
11948                anchor,
11949                breakpoint.clone(),
11950                edit_action,
11951                window,
11952                cx,
11953            )
11954        });
11955
11956        let height = bp_prompt.update(cx, |this, cx| {
11957            this.prompt
11958                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11959        });
11960        let cloned_prompt = bp_prompt.clone();
11961        let blocks = vec![BlockProperties {
11962            style: BlockStyle::Sticky,
11963            placement: BlockPlacement::Above(anchor),
11964            height: Some(height),
11965            render: Arc::new(move |cx| {
11966                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11967                cloned_prompt.clone().into_any_element()
11968            }),
11969            priority: 0,
11970        }];
11971
11972        let focus_handle = bp_prompt.focus_handle(cx);
11973        window.focus(&focus_handle, cx);
11974
11975        let block_ids = self.insert_blocks(blocks, None, cx);
11976        bp_prompt.update(cx, |prompt, _| {
11977            prompt.add_block_ids(block_ids);
11978        });
11979    }
11980
11981    pub(crate) fn breakpoint_at_row(
11982        &self,
11983        row: u32,
11984        window: &mut Window,
11985        cx: &mut Context<Self>,
11986    ) -> Option<(Anchor, Breakpoint)> {
11987        let snapshot = self.snapshot(window, cx);
11988        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11989
11990        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11991    }
11992
11993    pub(crate) fn breakpoint_at_anchor(
11994        &self,
11995        breakpoint_position: Anchor,
11996        snapshot: &EditorSnapshot,
11997        cx: &mut Context<Self>,
11998    ) -> Option<(Anchor, Breakpoint)> {
11999        let (breakpoint_position, _) = snapshot
12000            .buffer_snapshot()
12001            .anchor_to_buffer_anchor(breakpoint_position)?;
12002        let buffer = self.buffer.read(cx).buffer(breakpoint_position.buffer_id)?;
12003
12004        let buffer_snapshot = buffer.read(cx).snapshot();
12005
12006        let row = buffer_snapshot
12007            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position)
12008            .row;
12009
12010        let line_len = buffer_snapshot.line_len(row);
12011        let anchor_end = buffer_snapshot.anchor_after(Point::new(row, line_len));
12012
12013        self.breakpoint_store
12014            .as_ref()?
12015            .read_with(cx, |breakpoint_store, cx| {
12016                breakpoint_store
12017                    .breakpoints(
12018                        &buffer,
12019                        Some(breakpoint_position..anchor_end),
12020                        &buffer_snapshot,
12021                        cx,
12022                    )
12023                    .next()
12024                    .and_then(|(bp, _)| {
12025                        let breakpoint_row = buffer_snapshot
12026                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
12027                            .row;
12028
12029                        if breakpoint_row == row {
12030                            snapshot
12031                                .buffer_snapshot()
12032                                .anchor_in_excerpt(bp.position)
12033                                .map(|position| (position, bp.bp.clone()))
12034                        } else {
12035                            None
12036                        }
12037                    })
12038            })
12039    }
12040
12041    pub fn edit_log_breakpoint(
12042        &mut self,
12043        _: &EditLogBreakpoint,
12044        window: &mut Window,
12045        cx: &mut Context<Self>,
12046    ) {
12047        if self.breakpoint_store.is_none() {
12048            return;
12049        }
12050
12051        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12052            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
12053                message: None,
12054                state: BreakpointState::Enabled,
12055                condition: None,
12056                hit_condition: None,
12057            });
12058
12059            self.add_edit_breakpoint_block(
12060                anchor,
12061                &breakpoint,
12062                BreakpointPromptEditAction::Log,
12063                window,
12064                cx,
12065            );
12066        }
12067    }
12068
12069    fn breakpoints_at_cursors(
12070        &self,
12071        window: &mut Window,
12072        cx: &mut Context<Self>,
12073    ) -> Vec<(Anchor, Option<Breakpoint>)> {
12074        let snapshot = self.snapshot(window, cx);
12075        let cursors = self
12076            .selections
12077            .disjoint_anchors_arc()
12078            .iter()
12079            .map(|selection| {
12080                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12081
12082                let breakpoint_position = self
12083                    .breakpoint_at_row(cursor_position.row, window, cx)
12084                    .map(|bp| bp.0)
12085                    .unwrap_or_else(|| {
12086                        snapshot
12087                            .display_snapshot
12088                            .buffer_snapshot()
12089                            .anchor_after(Point::new(cursor_position.row, 0))
12090                    });
12091
12092                let breakpoint = self
12093                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12094                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12095
12096                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12097            })
12098            // 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.
12099            .collect::<HashMap<Anchor, _>>();
12100
12101        cursors.into_iter().collect()
12102    }
12103
12104    pub fn enable_breakpoint(
12105        &mut self,
12106        _: &crate::actions::EnableBreakpoint,
12107        window: &mut Window,
12108        cx: &mut Context<Self>,
12109    ) {
12110        if self.breakpoint_store.is_none() {
12111            return;
12112        }
12113
12114        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12115            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12116                continue;
12117            };
12118            self.edit_breakpoint_at_anchor(
12119                anchor,
12120                breakpoint,
12121                BreakpointEditAction::InvertState,
12122                cx,
12123            );
12124        }
12125    }
12126
12127    pub fn align_selections(
12128        &mut self,
12129        _: &crate::actions::AlignSelections,
12130        window: &mut Window,
12131        cx: &mut Context<Self>,
12132    ) {
12133        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12134
12135        let display_snapshot = self.display_snapshot(cx);
12136
12137        struct CursorData {
12138            anchor: Anchor,
12139            point: Point,
12140        }
12141        let cursor_data: Vec<CursorData> = self
12142            .selections
12143            .disjoint_anchors()
12144            .iter()
12145            .map(|selection| {
12146                let anchor = if selection.reversed {
12147                    selection.head()
12148                } else {
12149                    selection.tail()
12150                };
12151                CursorData {
12152                    anchor: anchor,
12153                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12154                }
12155            })
12156            .collect();
12157
12158        let rows_anchors_count: Vec<usize> = cursor_data
12159            .iter()
12160            .map(|cursor| cursor.point.row)
12161            .chunk_by(|&row| row)
12162            .into_iter()
12163            .map(|(_, group)| group.count())
12164            .collect();
12165        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12166        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12167        let mut edits = Vec::new();
12168
12169        for column_idx in 0..max_columns {
12170            let mut cursor_index = 0;
12171
12172            // Calculate target_column => position that the selections will go
12173            let mut target_column = 0;
12174            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12175                // Skip rows that don't have this column
12176                if column_idx >= *cursor_count {
12177                    cursor_index += cursor_count;
12178                    continue;
12179                }
12180
12181                let point = &cursor_data[cursor_index + column_idx].point;
12182                let adjusted_column = point.column + rows_column_offset[row_idx];
12183                if adjusted_column > target_column {
12184                    target_column = adjusted_column;
12185                }
12186                cursor_index += cursor_count;
12187            }
12188
12189            // Collect edits for this column
12190            cursor_index = 0;
12191            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12192                // Skip rows that don't have this column
12193                if column_idx >= *cursor_count {
12194                    cursor_index += *cursor_count;
12195                    continue;
12196                }
12197
12198                let point = &cursor_data[cursor_index + column_idx].point;
12199                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12200                if spaces_needed > 0 {
12201                    let anchor = cursor_data[cursor_index + column_idx]
12202                        .anchor
12203                        .bias_left(&display_snapshot);
12204                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12205                }
12206                rows_column_offset[row_idx] += spaces_needed;
12207
12208                cursor_index += *cursor_count;
12209            }
12210        }
12211
12212        if !edits.is_empty() {
12213            self.transact(window, cx, |editor, _window, cx| {
12214                editor.edit(edits, cx);
12215            });
12216        }
12217    }
12218
12219    pub fn disable_breakpoint(
12220        &mut self,
12221        _: &crate::actions::DisableBreakpoint,
12222        window: &mut Window,
12223        cx: &mut Context<Self>,
12224    ) {
12225        if self.breakpoint_store.is_none() {
12226            return;
12227        }
12228
12229        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12230            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12231                continue;
12232            };
12233            self.edit_breakpoint_at_anchor(
12234                anchor,
12235                breakpoint,
12236                BreakpointEditAction::InvertState,
12237                cx,
12238            );
12239        }
12240    }
12241
12242    pub fn toggle_breakpoint(
12243        &mut self,
12244        _: &crate::actions::ToggleBreakpoint,
12245        window: &mut Window,
12246        cx: &mut Context<Self>,
12247    ) {
12248        if self.breakpoint_store.is_none() {
12249            return;
12250        }
12251
12252        let snapshot = self.snapshot(window, cx);
12253        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12254            if self.gutter_breakpoint_indicator.0.is_some() {
12255                let display_row = anchor
12256                    .to_point(snapshot.buffer_snapshot())
12257                    .to_display_point(&snapshot.display_snapshot)
12258                    .row();
12259                self.update_breakpoint_collision_on_toggle(
12260                    display_row,
12261                    &BreakpointEditAction::Toggle,
12262                );
12263            }
12264
12265            if let Some(breakpoint) = breakpoint {
12266                self.edit_breakpoint_at_anchor(
12267                    anchor,
12268                    breakpoint,
12269                    BreakpointEditAction::Toggle,
12270                    cx,
12271                );
12272            } else {
12273                self.edit_breakpoint_at_anchor(
12274                    anchor,
12275                    Breakpoint::new_standard(),
12276                    BreakpointEditAction::Toggle,
12277                    cx,
12278                );
12279            }
12280        }
12281    }
12282
12283    fn update_breakpoint_collision_on_toggle(
12284        &mut self,
12285        display_row: DisplayRow,
12286        edit_action: &BreakpointEditAction,
12287    ) {
12288        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12289            if breakpoint_indicator.display_row == display_row
12290                && matches!(edit_action, BreakpointEditAction::Toggle)
12291            {
12292                breakpoint_indicator.collides_with_existing_breakpoint =
12293                    !breakpoint_indicator.collides_with_existing_breakpoint;
12294            }
12295        }
12296    }
12297
12298    pub fn edit_breakpoint_at_anchor(
12299        &mut self,
12300        breakpoint_position: Anchor,
12301        breakpoint: Breakpoint,
12302        edit_action: BreakpointEditAction,
12303        cx: &mut Context<Self>,
12304    ) {
12305        let Some(breakpoint_store) = &self.breakpoint_store else {
12306            return;
12307        };
12308        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12309        let Some((position, _)) = buffer_snapshot.anchor_to_buffer_anchor(breakpoint_position)
12310        else {
12311            return;
12312        };
12313        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
12314            return;
12315        };
12316
12317        breakpoint_store.update(cx, |breakpoint_store, cx| {
12318            breakpoint_store.toggle_breakpoint(
12319                buffer,
12320                BreakpointWithPosition {
12321                    position,
12322                    bp: breakpoint,
12323                },
12324                edit_action,
12325                cx,
12326            );
12327        });
12328
12329        cx.notify();
12330    }
12331
12332    #[cfg(any(test, feature = "test-support"))]
12333    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12334        self.breakpoint_store.clone()
12335    }
12336
12337    pub fn prepare_restore_change(
12338        &self,
12339        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12340        hunk: &MultiBufferDiffHunk,
12341        cx: &mut App,
12342    ) -> Option<()> {
12343        if hunk.is_created_file() {
12344            return None;
12345        }
12346        let multi_buffer = self.buffer.read(cx);
12347        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
12348        let diff_snapshot = multi_buffer_snapshot.diff_for_buffer_id(hunk.buffer_id)?;
12349        let original_text = diff_snapshot
12350            .base_text()
12351            .as_rope()
12352            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12353        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
12354        let buffer = buffer.read(cx);
12355        let buffer_snapshot = buffer.snapshot();
12356        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12357        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12358            probe
12359                .0
12360                .start
12361                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12362                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12363        }) {
12364            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12365            Some(())
12366        } else {
12367            None
12368        }
12369    }
12370
12371    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12372        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12373    }
12374
12375    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12376        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12377    }
12378
12379    pub fn rotate_selections_forward(
12380        &mut self,
12381        _: &RotateSelectionsForward,
12382        window: &mut Window,
12383        cx: &mut Context<Self>,
12384    ) {
12385        self.rotate_selections(window, cx, false)
12386    }
12387
12388    pub fn rotate_selections_backward(
12389        &mut self,
12390        _: &RotateSelectionsBackward,
12391        window: &mut Window,
12392        cx: &mut Context<Self>,
12393    ) {
12394        self.rotate_selections(window, cx, true)
12395    }
12396
12397    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12398        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12399        let display_snapshot = self.display_snapshot(cx);
12400        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12401
12402        if selections.len() < 2 {
12403            return;
12404        }
12405
12406        let (edits, new_selections) = {
12407            let buffer = self.buffer.read(cx).read(cx);
12408            let has_selections = selections.iter().any(|s| !s.is_empty());
12409            if has_selections {
12410                let mut selected_texts: Vec<String> = selections
12411                    .iter()
12412                    .map(|selection| {
12413                        buffer
12414                            .text_for_range(selection.start..selection.end)
12415                            .collect()
12416                    })
12417                    .collect();
12418
12419                if reverse {
12420                    selected_texts.rotate_left(1);
12421                } else {
12422                    selected_texts.rotate_right(1);
12423                }
12424
12425                let mut offset_delta: i64 = 0;
12426                let mut new_selections = Vec::new();
12427                let edits: Vec<_> = selections
12428                    .iter()
12429                    .zip(selected_texts.iter())
12430                    .map(|(selection, new_text)| {
12431                        let old_len = (selection.end.0 - selection.start.0) as i64;
12432                        let new_len = new_text.len() as i64;
12433                        let adjusted_start =
12434                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12435                        let adjusted_end =
12436                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12437
12438                        new_selections.push(Selection {
12439                            id: selection.id,
12440                            start: adjusted_start,
12441                            end: adjusted_end,
12442                            reversed: selection.reversed,
12443                            goal: selection.goal,
12444                        });
12445
12446                        offset_delta += new_len - old_len;
12447                        (selection.start..selection.end, new_text.clone())
12448                    })
12449                    .collect();
12450                (edits, new_selections)
12451            } else {
12452                let mut all_rows: Vec<u32> = selections
12453                    .iter()
12454                    .map(|selection| buffer.offset_to_point(selection.start).row)
12455                    .collect();
12456                all_rows.sort_unstable();
12457                all_rows.dedup();
12458
12459                if all_rows.len() < 2 {
12460                    return;
12461                }
12462
12463                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12464                    .iter()
12465                    .map(|&row| {
12466                        let start = Point::new(row, 0);
12467                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12468                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12469                    })
12470                    .collect();
12471
12472                let mut line_texts: Vec<String> = line_ranges
12473                    .iter()
12474                    .map(|range| buffer.text_for_range(range.clone()).collect())
12475                    .collect();
12476
12477                if reverse {
12478                    line_texts.rotate_left(1);
12479                } else {
12480                    line_texts.rotate_right(1);
12481                }
12482
12483                let edits = line_ranges
12484                    .iter()
12485                    .zip(line_texts.iter())
12486                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12487                    .collect();
12488
12489                let num_rows = all_rows.len();
12490                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12491                    .iter()
12492                    .enumerate()
12493                    .map(|(i, &row)| (row, i))
12494                    .collect();
12495
12496                // Compute new line start offsets after rotation (handles CRLF)
12497                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12498                let first_line_start = line_ranges[0].start.0;
12499                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12500                for text in line_texts.iter().take(num_rows - 1) {
12501                    let prev_start = *new_line_starts.last().unwrap();
12502                    new_line_starts.push(prev_start + text.len() + newline_len);
12503                }
12504
12505                let new_selections = selections
12506                    .iter()
12507                    .map(|selection| {
12508                        let point = buffer.offset_to_point(selection.start);
12509                        let old_index = row_to_index[&point.row];
12510                        let new_index = if reverse {
12511                            (old_index + num_rows - 1) % num_rows
12512                        } else {
12513                            (old_index + 1) % num_rows
12514                        };
12515                        let new_offset =
12516                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12517                        Selection {
12518                            id: selection.id,
12519                            start: new_offset,
12520                            end: new_offset,
12521                            reversed: selection.reversed,
12522                            goal: selection.goal,
12523                        }
12524                    })
12525                    .collect();
12526
12527                (edits, new_selections)
12528            }
12529        };
12530
12531        self.transact(window, cx, |this, window, cx| {
12532            this.buffer.update(cx, |buffer, cx| {
12533                buffer.edit(edits, None, cx);
12534            });
12535            this.change_selections(Default::default(), window, cx, |s| {
12536                s.select(new_selections);
12537            });
12538        });
12539    }
12540
12541    fn manipulate_lines<M>(
12542        &mut self,
12543        window: &mut Window,
12544        cx: &mut Context<Self>,
12545        mut manipulate: M,
12546    ) where
12547        M: FnMut(&str) -> LineManipulationResult,
12548    {
12549        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12550
12551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12552        let buffer = self.buffer.read(cx).snapshot(cx);
12553
12554        let mut edits = Vec::new();
12555
12556        let selections = self.selections.all::<Point>(&display_map);
12557        let mut selections = selections.iter().peekable();
12558        let mut contiguous_row_selections = Vec::new();
12559        let mut new_selections = Vec::new();
12560        let mut added_lines = 0;
12561        let mut removed_lines = 0;
12562
12563        while let Some(selection) = selections.next() {
12564            let (start_row, end_row) = consume_contiguous_rows(
12565                &mut contiguous_row_selections,
12566                selection,
12567                &display_map,
12568                &mut selections,
12569            );
12570
12571            let start_point = Point::new(start_row.0, 0);
12572            let end_point = Point::new(
12573                end_row.previous_row().0,
12574                buffer.line_len(end_row.previous_row()),
12575            );
12576            let text = buffer
12577                .text_for_range(start_point..end_point)
12578                .collect::<String>();
12579
12580            let LineManipulationResult {
12581                new_text,
12582                line_count_before,
12583                line_count_after,
12584            } = manipulate(&text);
12585
12586            edits.push((start_point..end_point, new_text));
12587
12588            // Selections must change based on added and removed line count
12589            let start_row =
12590                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12591            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12592            new_selections.push(Selection {
12593                id: selection.id,
12594                start: start_row,
12595                end: end_row,
12596                goal: SelectionGoal::None,
12597                reversed: selection.reversed,
12598            });
12599
12600            if line_count_after > line_count_before {
12601                added_lines += line_count_after - line_count_before;
12602            } else if line_count_before > line_count_after {
12603                removed_lines += line_count_before - line_count_after;
12604            }
12605        }
12606
12607        self.transact(window, cx, |this, window, cx| {
12608            let buffer = this.buffer.update(cx, |buffer, cx| {
12609                buffer.edit(edits, None, cx);
12610                buffer.snapshot(cx)
12611            });
12612
12613            // Recalculate offsets on newly edited buffer
12614            let new_selections = new_selections
12615                .iter()
12616                .map(|s| {
12617                    let start_point = Point::new(s.start.0, 0);
12618                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12619                    Selection {
12620                        id: s.id,
12621                        start: buffer.point_to_offset(start_point),
12622                        end: buffer.point_to_offset(end_point),
12623                        goal: s.goal,
12624                        reversed: s.reversed,
12625                    }
12626                })
12627                .collect();
12628
12629            this.change_selections(Default::default(), window, cx, |s| {
12630                s.select(new_selections);
12631            });
12632
12633            this.request_autoscroll(Autoscroll::fit(), cx);
12634        });
12635    }
12636
12637    fn manipulate_immutable_lines<Fn>(
12638        &mut self,
12639        window: &mut Window,
12640        cx: &mut Context<Self>,
12641        mut callback: Fn,
12642    ) where
12643        Fn: FnMut(&mut Vec<&str>),
12644    {
12645        self.manipulate_lines(window, cx, |text| {
12646            let mut lines: Vec<&str> = text.split('\n').collect();
12647            let line_count_before = lines.len();
12648
12649            callback(&mut lines);
12650
12651            LineManipulationResult {
12652                new_text: lines.join("\n"),
12653                line_count_before,
12654                line_count_after: lines.len(),
12655            }
12656        });
12657    }
12658
12659    fn manipulate_mutable_lines<Fn>(
12660        &mut self,
12661        window: &mut Window,
12662        cx: &mut Context<Self>,
12663        mut callback: Fn,
12664    ) where
12665        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12666    {
12667        self.manipulate_lines(window, cx, |text| {
12668            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12669            let line_count_before = lines.len();
12670
12671            callback(&mut lines);
12672
12673            LineManipulationResult {
12674                new_text: lines.join("\n"),
12675                line_count_before,
12676                line_count_after: lines.len(),
12677            }
12678        });
12679    }
12680
12681    pub fn convert_indentation_to_spaces(
12682        &mut self,
12683        _: &ConvertIndentationToSpaces,
12684        window: &mut Window,
12685        cx: &mut Context<Self>,
12686    ) {
12687        let settings = self.buffer.read(cx).language_settings(cx);
12688        let tab_size = settings.tab_size.get() as usize;
12689
12690        self.manipulate_mutable_lines(window, cx, |lines| {
12691            // Allocates a reasonably sized scratch buffer once for the whole loop
12692            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12693            // Avoids recomputing spaces that could be inserted many times
12694            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12695                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12696                .collect();
12697
12698            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12699                let mut chars = line.as_ref().chars();
12700                let mut col = 0;
12701                let mut changed = false;
12702
12703                for ch in chars.by_ref() {
12704                    match ch {
12705                        ' ' => {
12706                            reindented_line.push(' ');
12707                            col += 1;
12708                        }
12709                        '\t' => {
12710                            // \t are converted to spaces depending on the current column
12711                            let spaces_len = tab_size - (col % tab_size);
12712                            reindented_line.extend(&space_cache[spaces_len - 1]);
12713                            col += spaces_len;
12714                            changed = true;
12715                        }
12716                        _ => {
12717                            // If we dont append before break, the character is consumed
12718                            reindented_line.push(ch);
12719                            break;
12720                        }
12721                    }
12722                }
12723
12724                if !changed {
12725                    reindented_line.clear();
12726                    continue;
12727                }
12728                // Append the rest of the line and replace old reference with new one
12729                reindented_line.extend(chars);
12730                *line = Cow::Owned(reindented_line.clone());
12731                reindented_line.clear();
12732            }
12733        });
12734    }
12735
12736    pub fn convert_indentation_to_tabs(
12737        &mut self,
12738        _: &ConvertIndentationToTabs,
12739        window: &mut Window,
12740        cx: &mut Context<Self>,
12741    ) {
12742        let settings = self.buffer.read(cx).language_settings(cx);
12743        let tab_size = settings.tab_size.get() as usize;
12744
12745        self.manipulate_mutable_lines(window, cx, |lines| {
12746            // Allocates a reasonably sized buffer once for the whole loop
12747            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12748            // Avoids recomputing spaces that could be inserted many times
12749            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12750                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12751                .collect();
12752
12753            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12754                let mut chars = line.chars();
12755                let mut spaces_count = 0;
12756                let mut first_non_indent_char = None;
12757                let mut changed = false;
12758
12759                for ch in chars.by_ref() {
12760                    match ch {
12761                        ' ' => {
12762                            // Keep track of spaces. Append \t when we reach tab_size
12763                            spaces_count += 1;
12764                            changed = true;
12765                            if spaces_count == tab_size {
12766                                reindented_line.push('\t');
12767                                spaces_count = 0;
12768                            }
12769                        }
12770                        '\t' => {
12771                            reindented_line.push('\t');
12772                            spaces_count = 0;
12773                        }
12774                        _ => {
12775                            // Dont append it yet, we might have remaining spaces
12776                            first_non_indent_char = Some(ch);
12777                            break;
12778                        }
12779                    }
12780                }
12781
12782                if !changed {
12783                    reindented_line.clear();
12784                    continue;
12785                }
12786                // Remaining spaces that didn't make a full tab stop
12787                if spaces_count > 0 {
12788                    reindented_line.extend(&space_cache[spaces_count - 1]);
12789                }
12790                // If we consume an extra character that was not indentation, add it back
12791                if let Some(extra_char) = first_non_indent_char {
12792                    reindented_line.push(extra_char);
12793                }
12794                // Append the rest of the line and replace old reference with new one
12795                reindented_line.extend(chars);
12796                *line = Cow::Owned(reindented_line.clone());
12797                reindented_line.clear();
12798            }
12799        });
12800    }
12801
12802    pub fn convert_to_upper_case(
12803        &mut self,
12804        _: &ConvertToUpperCase,
12805        window: &mut Window,
12806        cx: &mut Context<Self>,
12807    ) {
12808        self.manipulate_text(window, cx, |text| text.to_uppercase())
12809    }
12810
12811    pub fn convert_to_lower_case(
12812        &mut self,
12813        _: &ConvertToLowerCase,
12814        window: &mut Window,
12815        cx: &mut Context<Self>,
12816    ) {
12817        self.manipulate_text(window, cx, |text| text.to_lowercase())
12818    }
12819
12820    pub fn convert_to_title_case(
12821        &mut self,
12822        _: &ConvertToTitleCase,
12823        window: &mut Window,
12824        cx: &mut Context<Self>,
12825    ) {
12826        self.manipulate_text(window, cx, |text| {
12827            Self::convert_text_case(text, Case::Title)
12828        })
12829    }
12830
12831    pub fn convert_to_snake_case(
12832        &mut self,
12833        _: &ConvertToSnakeCase,
12834        window: &mut Window,
12835        cx: &mut Context<Self>,
12836    ) {
12837        self.manipulate_text(window, cx, |text| {
12838            Self::convert_text_case(text, Case::Snake)
12839        })
12840    }
12841
12842    pub fn convert_to_kebab_case(
12843        &mut self,
12844        _: &ConvertToKebabCase,
12845        window: &mut Window,
12846        cx: &mut Context<Self>,
12847    ) {
12848        self.manipulate_text(window, cx, |text| {
12849            Self::convert_text_case(text, Case::Kebab)
12850        })
12851    }
12852
12853    pub fn convert_to_upper_camel_case(
12854        &mut self,
12855        _: &ConvertToUpperCamelCase,
12856        window: &mut Window,
12857        cx: &mut Context<Self>,
12858    ) {
12859        self.manipulate_text(window, cx, |text| {
12860            Self::convert_text_case(text, Case::UpperCamel)
12861        })
12862    }
12863
12864    pub fn convert_to_lower_camel_case(
12865        &mut self,
12866        _: &ConvertToLowerCamelCase,
12867        window: &mut Window,
12868        cx: &mut Context<Self>,
12869    ) {
12870        self.manipulate_text(window, cx, |text| {
12871            Self::convert_text_case(text, Case::Camel)
12872        })
12873    }
12874
12875    pub fn convert_to_opposite_case(
12876        &mut self,
12877        _: &ConvertToOppositeCase,
12878        window: &mut Window,
12879        cx: &mut Context<Self>,
12880    ) {
12881        self.manipulate_text(window, cx, |text| {
12882            text.chars()
12883                .fold(String::with_capacity(text.len()), |mut t, c| {
12884                    if c.is_uppercase() {
12885                        t.extend(c.to_lowercase());
12886                    } else {
12887                        t.extend(c.to_uppercase());
12888                    }
12889                    t
12890                })
12891        })
12892    }
12893
12894    pub fn convert_to_sentence_case(
12895        &mut self,
12896        _: &ConvertToSentenceCase,
12897        window: &mut Window,
12898        cx: &mut Context<Self>,
12899    ) {
12900        self.manipulate_text(window, cx, |text| {
12901            Self::convert_text_case(text, Case::Sentence)
12902        })
12903    }
12904
12905    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12906        self.manipulate_text(window, cx, |text| {
12907            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12908            if has_upper_case_characters {
12909                text.to_lowercase()
12910            } else {
12911                text.to_uppercase()
12912            }
12913        })
12914    }
12915
12916    pub fn convert_to_rot13(
12917        &mut self,
12918        _: &ConvertToRot13,
12919        window: &mut Window,
12920        cx: &mut Context<Self>,
12921    ) {
12922        self.manipulate_text(window, cx, |text| {
12923            text.chars()
12924                .map(|c| match c {
12925                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12926                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12927                    _ => c,
12928                })
12929                .collect()
12930        })
12931    }
12932
12933    fn convert_text_case(text: &str, case: Case) -> String {
12934        text.lines()
12935            .map(|line| {
12936                let trimmed_start = line.trim_start();
12937                let leading = &line[..line.len() - trimmed_start.len()];
12938                let trimmed = trimmed_start.trim_end();
12939                let trailing = &trimmed_start[trimmed.len()..];
12940                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12941            })
12942            .join("\n")
12943    }
12944
12945    pub fn convert_to_rot47(
12946        &mut self,
12947        _: &ConvertToRot47,
12948        window: &mut Window,
12949        cx: &mut Context<Self>,
12950    ) {
12951        self.manipulate_text(window, cx, |text| {
12952            text.chars()
12953                .map(|c| {
12954                    let code_point = c as u32;
12955                    if code_point >= 33 && code_point <= 126 {
12956                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12957                    }
12958                    c
12959                })
12960                .collect()
12961        })
12962    }
12963
12964    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12965    where
12966        Fn: FnMut(&str) -> String,
12967    {
12968        let buffer = self.buffer.read(cx).snapshot(cx);
12969
12970        let mut new_selections = Vec::new();
12971        let mut edits = Vec::new();
12972        let mut selection_adjustment = 0isize;
12973
12974        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12975            let selection_is_empty = selection.is_empty();
12976
12977            let (start, end) = if selection_is_empty {
12978                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12979                (word_range.start, word_range.end)
12980            } else {
12981                (
12982                    buffer.point_to_offset(selection.start),
12983                    buffer.point_to_offset(selection.end),
12984                )
12985            };
12986
12987            let text = buffer.text_for_range(start..end).collect::<String>();
12988            let old_length = text.len() as isize;
12989            let text = callback(&text);
12990
12991            new_selections.push(Selection {
12992                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12993                end: MultiBufferOffset(
12994                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12995                ),
12996                goal: SelectionGoal::None,
12997                id: selection.id,
12998                reversed: selection.reversed,
12999            });
13000
13001            selection_adjustment += old_length - text.len() as isize;
13002
13003            edits.push((start..end, text));
13004        }
13005
13006        self.transact(window, cx, |this, window, cx| {
13007            this.buffer.update(cx, |buffer, cx| {
13008                buffer.edit(edits, None, cx);
13009            });
13010
13011            this.change_selections(Default::default(), window, cx, |s| {
13012                s.select(new_selections);
13013            });
13014
13015            this.request_autoscroll(Autoscroll::fit(), cx);
13016        });
13017    }
13018
13019    pub fn move_selection_on_drop(
13020        &mut self,
13021        selection: &Selection<Anchor>,
13022        target: DisplayPoint,
13023        is_cut: bool,
13024        window: &mut Window,
13025        cx: &mut Context<Self>,
13026    ) {
13027        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13028        let buffer = display_map.buffer_snapshot();
13029        let mut edits = Vec::new();
13030        let insert_point = display_map
13031            .clip_point(target, Bias::Left)
13032            .to_point(&display_map);
13033        let text = buffer
13034            .text_for_range(selection.start..selection.end)
13035            .collect::<String>();
13036        if is_cut {
13037            edits.push(((selection.start..selection.end), String::new()));
13038        }
13039        let insert_anchor = buffer.anchor_before(insert_point);
13040        edits.push(((insert_anchor..insert_anchor), text));
13041        let last_edit_start = insert_anchor.bias_left(buffer);
13042        let last_edit_end = insert_anchor.bias_right(buffer);
13043        self.transact(window, cx, |this, window, cx| {
13044            this.buffer.update(cx, |buffer, cx| {
13045                buffer.edit(edits, None, cx);
13046            });
13047            this.change_selections(Default::default(), window, cx, |s| {
13048                s.select_anchor_ranges([last_edit_start..last_edit_end]);
13049            });
13050        });
13051    }
13052
13053    pub fn clear_selection_drag_state(&mut self) {
13054        self.selection_drag_state = SelectionDragState::None;
13055    }
13056
13057    pub fn duplicate(
13058        &mut self,
13059        upwards: bool,
13060        whole_lines: bool,
13061        window: &mut Window,
13062        cx: &mut Context<Self>,
13063    ) {
13064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13065
13066        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13067        let buffer = display_map.buffer_snapshot();
13068        let selections = self.selections.all::<Point>(&display_map);
13069
13070        let mut edits = Vec::new();
13071        let mut selections_iter = selections.iter().peekable();
13072        while let Some(selection) = selections_iter.next() {
13073            let mut rows = selection.spanned_rows(false, &display_map);
13074            // duplicate line-wise
13075            if whole_lines || selection.start == selection.end {
13076                // Avoid duplicating the same lines twice.
13077                while let Some(next_selection) = selections_iter.peek() {
13078                    let next_rows = next_selection.spanned_rows(false, &display_map);
13079                    if next_rows.start < rows.end {
13080                        rows.end = next_rows.end;
13081                        selections_iter.next().unwrap();
13082                    } else {
13083                        break;
13084                    }
13085                }
13086
13087                // Copy the text from the selected row region and splice it either at the start
13088                // or end of the region.
13089                let start = Point::new(rows.start.0, 0);
13090                let end = Point::new(
13091                    rows.end.previous_row().0,
13092                    buffer.line_len(rows.end.previous_row()),
13093                );
13094
13095                let mut text = buffer.text_for_range(start..end).collect::<String>();
13096
13097                let insert_location = if upwards {
13098                    // When duplicating upward, we need to insert before the current line.
13099                    // If we're on the last line and it doesn't end with a newline,
13100                    // we need to add a newline before the duplicated content.
13101                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13102                        && buffer.max_point().column > 0
13103                        && !text.ends_with('\n');
13104
13105                    if needs_leading_newline {
13106                        text.insert(0, '\n');
13107                        end
13108                    } else {
13109                        text.push('\n');
13110                        Point::new(rows.start.0, 0)
13111                    }
13112                } else {
13113                    text.push('\n');
13114                    start
13115                };
13116                edits.push((insert_location..insert_location, text));
13117            } else {
13118                // duplicate character-wise
13119                let start = selection.start;
13120                let end = selection.end;
13121                let text = buffer.text_for_range(start..end).collect::<String>();
13122                edits.push((selection.end..selection.end, text));
13123            }
13124        }
13125
13126        self.transact(window, cx, |this, window, cx| {
13127            this.buffer.update(cx, |buffer, cx| {
13128                buffer.edit(edits, None, cx);
13129            });
13130
13131            // When duplicating upward with whole lines, move the cursor to the duplicated line
13132            if upwards && whole_lines {
13133                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13134
13135                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13136                    let mut new_ranges = Vec::new();
13137                    let selections = s.all::<Point>(&display_map);
13138                    let mut selections_iter = selections.iter().peekable();
13139
13140                    while let Some(first_selection) = selections_iter.next() {
13141                        // Group contiguous selections together to find the total row span
13142                        let mut group_selections = vec![first_selection];
13143                        let mut rows = first_selection.spanned_rows(false, &display_map);
13144
13145                        while let Some(next_selection) = selections_iter.peek() {
13146                            let next_rows = next_selection.spanned_rows(false, &display_map);
13147                            if next_rows.start < rows.end {
13148                                rows.end = next_rows.end;
13149                                group_selections.push(selections_iter.next().unwrap());
13150                            } else {
13151                                break;
13152                            }
13153                        }
13154
13155                        let row_count = rows.end.0 - rows.start.0;
13156
13157                        // Move all selections in this group up by the total number of duplicated rows
13158                        for selection in group_selections {
13159                            let new_start = Point::new(
13160                                selection.start.row.saturating_sub(row_count),
13161                                selection.start.column,
13162                            );
13163
13164                            let new_end = Point::new(
13165                                selection.end.row.saturating_sub(row_count),
13166                                selection.end.column,
13167                            );
13168
13169                            new_ranges.push(new_start..new_end);
13170                        }
13171                    }
13172
13173                    s.select_ranges(new_ranges);
13174                });
13175            }
13176
13177            this.request_autoscroll(Autoscroll::fit(), cx);
13178        });
13179    }
13180
13181    pub fn duplicate_line_up(
13182        &mut self,
13183        _: &DuplicateLineUp,
13184        window: &mut Window,
13185        cx: &mut Context<Self>,
13186    ) {
13187        self.duplicate(true, true, window, cx);
13188    }
13189
13190    pub fn duplicate_line_down(
13191        &mut self,
13192        _: &DuplicateLineDown,
13193        window: &mut Window,
13194        cx: &mut Context<Self>,
13195    ) {
13196        self.duplicate(false, true, window, cx);
13197    }
13198
13199    pub fn duplicate_selection(
13200        &mut self,
13201        _: &DuplicateSelection,
13202        window: &mut Window,
13203        cx: &mut Context<Self>,
13204    ) {
13205        self.duplicate(false, false, window, cx);
13206    }
13207
13208    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13209        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13210        if self.mode.is_single_line() {
13211            cx.propagate();
13212            return;
13213        }
13214
13215        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13216        let buffer = self.buffer.read(cx).snapshot(cx);
13217
13218        let mut edits = Vec::new();
13219        let mut unfold_ranges = Vec::new();
13220        let mut refold_creases = Vec::new();
13221
13222        let selections = self.selections.all::<Point>(&display_map);
13223        let mut selections = selections.iter().peekable();
13224        let mut contiguous_row_selections = Vec::new();
13225        let mut new_selections = Vec::new();
13226
13227        while let Some(selection) = selections.next() {
13228            // Find all the selections that span a contiguous row range
13229            let (start_row, end_row) = consume_contiguous_rows(
13230                &mut contiguous_row_selections,
13231                selection,
13232                &display_map,
13233                &mut selections,
13234            );
13235
13236            // Move the text spanned by the row range to be before the line preceding the row range
13237            if start_row.0 > 0 {
13238                let range_to_move = Point::new(
13239                    start_row.previous_row().0,
13240                    buffer.line_len(start_row.previous_row()),
13241                )
13242                    ..Point::new(
13243                        end_row.previous_row().0,
13244                        buffer.line_len(end_row.previous_row()),
13245                    );
13246                let insertion_point = display_map
13247                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13248                    .0;
13249
13250                // Don't move lines across excerpts
13251                if buffer
13252                    .excerpt_containing(insertion_point..range_to_move.end)
13253                    .is_some()
13254                {
13255                    let text = buffer
13256                        .text_for_range(range_to_move.clone())
13257                        .flat_map(|s| s.chars())
13258                        .skip(1)
13259                        .chain(['\n'])
13260                        .collect::<String>();
13261
13262                    edits.push((
13263                        buffer.anchor_after(range_to_move.start)
13264                            ..buffer.anchor_before(range_to_move.end),
13265                        String::new(),
13266                    ));
13267                    let insertion_anchor = buffer.anchor_after(insertion_point);
13268                    edits.push((insertion_anchor..insertion_anchor, text));
13269
13270                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13271
13272                    // Move selections up
13273                    new_selections.extend(contiguous_row_selections.drain(..).map(
13274                        |mut selection| {
13275                            selection.start.row -= row_delta;
13276                            selection.end.row -= row_delta;
13277                            selection
13278                        },
13279                    ));
13280
13281                    // Move folds up
13282                    unfold_ranges.push(range_to_move.clone());
13283                    for fold in display_map.folds_in_range(
13284                        buffer.anchor_before(range_to_move.start)
13285                            ..buffer.anchor_after(range_to_move.end),
13286                    ) {
13287                        let mut start = fold.range.start.to_point(&buffer);
13288                        let mut end = fold.range.end.to_point(&buffer);
13289                        start.row -= row_delta;
13290                        end.row -= row_delta;
13291                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13292                    }
13293                }
13294            }
13295
13296            // If we didn't move line(s), preserve the existing selections
13297            new_selections.append(&mut contiguous_row_selections);
13298        }
13299
13300        self.transact(window, cx, |this, window, cx| {
13301            this.unfold_ranges(&unfold_ranges, true, true, cx);
13302            this.buffer.update(cx, |buffer, cx| {
13303                for (range, text) in edits {
13304                    buffer.edit([(range, text)], None, cx);
13305                }
13306            });
13307            this.fold_creases(refold_creases, true, window, cx);
13308            this.change_selections(Default::default(), window, cx, |s| {
13309                s.select(new_selections);
13310            })
13311        });
13312    }
13313
13314    pub fn move_line_down(
13315        &mut self,
13316        _: &MoveLineDown,
13317        window: &mut Window,
13318        cx: &mut Context<Self>,
13319    ) {
13320        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13321        if self.mode.is_single_line() {
13322            cx.propagate();
13323            return;
13324        }
13325
13326        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13327        let buffer = self.buffer.read(cx).snapshot(cx);
13328
13329        let mut edits = Vec::new();
13330        let mut unfold_ranges = Vec::new();
13331        let mut refold_creases = Vec::new();
13332
13333        let selections = self.selections.all::<Point>(&display_map);
13334        let mut selections = selections.iter().peekable();
13335        let mut contiguous_row_selections = Vec::new();
13336        let mut new_selections = Vec::new();
13337
13338        while let Some(selection) = selections.next() {
13339            // Find all the selections that span a contiguous row range
13340            let (start_row, end_row) = consume_contiguous_rows(
13341                &mut contiguous_row_selections,
13342                selection,
13343                &display_map,
13344                &mut selections,
13345            );
13346
13347            // Move the text spanned by the row range to be after the last line of the row range
13348            if end_row.0 <= buffer.max_point().row {
13349                let range_to_move =
13350                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13351                let insertion_point = display_map
13352                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13353                    .0;
13354
13355                // Don't move lines across excerpt boundaries
13356                if buffer
13357                    .excerpt_containing(range_to_move.start..insertion_point)
13358                    .is_some()
13359                {
13360                    let mut text = String::from("\n");
13361                    text.extend(buffer.text_for_range(range_to_move.clone()));
13362                    text.pop(); // Drop trailing newline
13363                    edits.push((
13364                        buffer.anchor_after(range_to_move.start)
13365                            ..buffer.anchor_before(range_to_move.end),
13366                        String::new(),
13367                    ));
13368                    let insertion_anchor = buffer.anchor_after(insertion_point);
13369                    edits.push((insertion_anchor..insertion_anchor, text));
13370
13371                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13372
13373                    // Move selections down
13374                    new_selections.extend(contiguous_row_selections.drain(..).map(
13375                        |mut selection| {
13376                            selection.start.row += row_delta;
13377                            selection.end.row += row_delta;
13378                            selection
13379                        },
13380                    ));
13381
13382                    // Move folds down
13383                    unfold_ranges.push(range_to_move.clone());
13384                    for fold in display_map.folds_in_range(
13385                        buffer.anchor_before(range_to_move.start)
13386                            ..buffer.anchor_after(range_to_move.end),
13387                    ) {
13388                        let mut start = fold.range.start.to_point(&buffer);
13389                        let mut end = fold.range.end.to_point(&buffer);
13390                        start.row += row_delta;
13391                        end.row += row_delta;
13392                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13393                    }
13394                }
13395            }
13396
13397            // If we didn't move line(s), preserve the existing selections
13398            new_selections.append(&mut contiguous_row_selections);
13399        }
13400
13401        self.transact(window, cx, |this, window, cx| {
13402            this.unfold_ranges(&unfold_ranges, true, true, cx);
13403            this.buffer.update(cx, |buffer, cx| {
13404                for (range, text) in edits {
13405                    buffer.edit([(range, text)], None, cx);
13406                }
13407            });
13408            this.fold_creases(refold_creases, true, window, cx);
13409            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13410        });
13411    }
13412
13413    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13414        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13415        let text_layout_details = &self.text_layout_details(window, cx);
13416        self.transact(window, cx, |this, window, cx| {
13417            let edits = this.change_selections(Default::default(), window, cx, |s| {
13418                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13419                s.move_with(&mut |display_map, selection| {
13420                    if !selection.is_empty() {
13421                        return;
13422                    }
13423
13424                    let mut head = selection.head();
13425                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13426                    if head.column() == display_map.line_len(head.row()) {
13427                        transpose_offset = display_map
13428                            .buffer_snapshot()
13429                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13430                    }
13431
13432                    if transpose_offset == MultiBufferOffset(0) {
13433                        return;
13434                    }
13435
13436                    *head.column_mut() += 1;
13437                    head = display_map.clip_point(head, Bias::Right);
13438                    let goal = SelectionGoal::HorizontalPosition(
13439                        display_map
13440                            .x_for_display_point(head, text_layout_details)
13441                            .into(),
13442                    );
13443                    selection.collapse_to(head, goal);
13444
13445                    let transpose_start = display_map
13446                        .buffer_snapshot()
13447                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13448                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13449                        let transpose_end = display_map
13450                            .buffer_snapshot()
13451                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13452                        if let Some(ch) = display_map
13453                            .buffer_snapshot()
13454                            .chars_at(transpose_start)
13455                            .next()
13456                        {
13457                            edits.push((transpose_start..transpose_offset, String::new()));
13458                            edits.push((transpose_end..transpose_end, ch.to_string()));
13459                        }
13460                    }
13461                });
13462                edits
13463            });
13464            this.buffer
13465                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13466            let selections = this
13467                .selections
13468                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13469            this.change_selections(Default::default(), window, cx, |s| {
13470                s.select(selections);
13471            });
13472        });
13473    }
13474
13475    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13477        if self.mode.is_single_line() {
13478            cx.propagate();
13479            return;
13480        }
13481
13482        self.rewrap_impl(RewrapOptions::default(), cx)
13483    }
13484
13485    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13486        let buffer = self.buffer.read(cx).snapshot(cx);
13487        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13488
13489        #[derive(Clone, Debug, PartialEq)]
13490        enum CommentFormat {
13491            /// single line comment, with prefix for line
13492            Line(String),
13493            /// single line within a block comment, with prefix for line
13494            BlockLine(String),
13495            /// a single line of a block comment that includes the initial delimiter
13496            BlockCommentWithStart(BlockCommentConfig),
13497            /// a single line of a block comment that includes the ending delimiter
13498            BlockCommentWithEnd(BlockCommentConfig),
13499        }
13500
13501        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13502        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13503            let language_settings = buffer.language_settings_at(selection.head(), cx);
13504            let language_scope = buffer.language_scope_at(selection.head());
13505
13506            let indent_and_prefix_for_row =
13507                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13508                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13509                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13510                        &language_scope
13511                    {
13512                        let indent_end = Point::new(row, indent.len);
13513                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13514                        let line_text_after_indent = buffer
13515                            .text_for_range(indent_end..line_end)
13516                            .collect::<String>();
13517
13518                        let is_within_comment_override = buffer
13519                            .language_scope_at(indent_end)
13520                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13521                        let comment_delimiters = if is_within_comment_override {
13522                            // we are within a comment syntax node, but we don't
13523                            // yet know what kind of comment: block, doc or line
13524                            match (
13525                                language_scope.documentation_comment(),
13526                                language_scope.block_comment(),
13527                            ) {
13528                                (Some(config), _) | (_, Some(config))
13529                                    if buffer.contains_str_at(indent_end, &config.start) =>
13530                                {
13531                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13532                                }
13533                                (Some(config), _) | (_, Some(config))
13534                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13535                                {
13536                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13537                                }
13538                                (Some(config), _) | (_, Some(config))
13539                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13540                                {
13541                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13542                                }
13543                                (_, _) => language_scope
13544                                    .line_comment_prefixes()
13545                                    .iter()
13546                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13547                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13548                            }
13549                        } else {
13550                            // we not in an overridden comment node, but we may
13551                            // be within a non-overridden line comment node
13552                            language_scope
13553                                .line_comment_prefixes()
13554                                .iter()
13555                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13556                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13557                        };
13558
13559                        let rewrap_prefix = language_scope
13560                            .rewrap_prefixes()
13561                            .iter()
13562                            .find_map(|prefix_regex| {
13563                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13564                                    if mat.start() == 0 {
13565                                        Some(mat.as_str().to_string())
13566                                    } else {
13567                                        None
13568                                    }
13569                                })
13570                            })
13571                            .flatten();
13572                        (comment_delimiters, rewrap_prefix)
13573                    } else {
13574                        (None, None)
13575                    };
13576                    (indent, comment_prefix, rewrap_prefix)
13577                };
13578
13579            let mut start_row = selection.start.row;
13580            let mut end_row = selection.end.row;
13581
13582            if selection.is_empty() {
13583                let cursor_row = selection.start.row;
13584
13585                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13586                let line_prefix = match &comment_prefix {
13587                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13588                        Some(prefix.as_str())
13589                    }
13590                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13591                        prefix, ..
13592                    })) => Some(prefix.as_ref()),
13593                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13594                        start: _,
13595                        end: _,
13596                        prefix,
13597                        tab_size,
13598                    })) => {
13599                        indent_size.len += tab_size;
13600                        Some(prefix.as_ref())
13601                    }
13602                    None => None,
13603                };
13604                let indent_prefix = indent_size.chars().collect::<String>();
13605                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13606
13607                'expand_upwards: while start_row > 0 {
13608                    let prev_row = start_row - 1;
13609                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13610                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13611                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13612                    {
13613                        start_row = prev_row;
13614                    } else {
13615                        break 'expand_upwards;
13616                    }
13617                }
13618
13619                'expand_downwards: while end_row < buffer.max_point().row {
13620                    let next_row = end_row + 1;
13621                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13622                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13623                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13624                    {
13625                        end_row = next_row;
13626                    } else {
13627                        break 'expand_downwards;
13628                    }
13629                }
13630            }
13631
13632            let mut non_blank_rows_iter = (start_row..=end_row)
13633                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13634                .peekable();
13635
13636            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13637                row
13638            } else {
13639                return Vec::new();
13640            };
13641
13642            let mut ranges = Vec::new();
13643
13644            let mut current_range_start = first_row;
13645            let mut prev_row = first_row;
13646            let (
13647                mut current_range_indent,
13648                mut current_range_comment_delimiters,
13649                mut current_range_rewrap_prefix,
13650            ) = indent_and_prefix_for_row(first_row);
13651
13652            for row in non_blank_rows_iter.skip(1) {
13653                let has_paragraph_break = row > prev_row + 1;
13654
13655                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13656                    indent_and_prefix_for_row(row);
13657
13658                let has_indent_change = row_indent != current_range_indent;
13659                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13660
13661                let has_boundary_change = has_comment_change
13662                    || row_rewrap_prefix.is_some()
13663                    || (has_indent_change && current_range_comment_delimiters.is_some());
13664
13665                if has_paragraph_break || has_boundary_change {
13666                    ranges.push((
13667                        language_settings.clone(),
13668                        Point::new(current_range_start, 0)
13669                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13670                        current_range_indent,
13671                        current_range_comment_delimiters.clone(),
13672                        current_range_rewrap_prefix.clone(),
13673                    ));
13674                    current_range_start = row;
13675                    current_range_indent = row_indent;
13676                    current_range_comment_delimiters = row_comment_delimiters;
13677                    current_range_rewrap_prefix = row_rewrap_prefix;
13678                }
13679                prev_row = row;
13680            }
13681
13682            ranges.push((
13683                language_settings.clone(),
13684                Point::new(current_range_start, 0)
13685                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13686                current_range_indent,
13687                current_range_comment_delimiters,
13688                current_range_rewrap_prefix,
13689            ));
13690
13691            ranges
13692        });
13693
13694        let mut edits = Vec::new();
13695        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13696
13697        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13698            wrap_ranges
13699        {
13700            let start_row = wrap_range.start.row;
13701            let end_row = wrap_range.end.row;
13702
13703            // Skip selections that overlap with a range that has already been rewrapped.
13704            let selection_range = start_row..end_row;
13705            if rewrapped_row_ranges
13706                .iter()
13707                .any(|range| range.overlaps(&selection_range))
13708            {
13709                continue;
13710            }
13711
13712            let tab_size = language_settings.tab_size;
13713
13714            let (line_prefix, inside_comment) = match &comment_prefix {
13715                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13716                    (Some(prefix.as_str()), true)
13717                }
13718                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13719                    (Some(prefix.as_ref()), true)
13720                }
13721                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13722                    start: _,
13723                    end: _,
13724                    prefix,
13725                    tab_size,
13726                })) => {
13727                    indent_size.len += tab_size;
13728                    (Some(prefix.as_ref()), true)
13729                }
13730                None => (None, false),
13731            };
13732            let indent_prefix = indent_size.chars().collect::<String>();
13733            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13734
13735            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13736                RewrapBehavior::InComments => inside_comment,
13737                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13738                RewrapBehavior::Anywhere => true,
13739            };
13740
13741            let should_rewrap = options.override_language_settings
13742                || allow_rewrap_based_on_language
13743                || self.hard_wrap.is_some();
13744            if !should_rewrap {
13745                continue;
13746            }
13747
13748            let start = Point::new(start_row, 0);
13749            let start_offset = ToOffset::to_offset(&start, &buffer);
13750            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13751            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13752            let mut first_line_delimiter = None;
13753            let mut last_line_delimiter = None;
13754            let Some(lines_without_prefixes) = selection_text
13755                .lines()
13756                .enumerate()
13757                .map(|(ix, line)| {
13758                    let line_trimmed = line.trim_start();
13759                    if rewrap_prefix.is_some() && ix > 0 {
13760                        Ok(line_trimmed)
13761                    } else if let Some(
13762                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13763                            start,
13764                            prefix,
13765                            end,
13766                            tab_size,
13767                        })
13768                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13769                            start,
13770                            prefix,
13771                            end,
13772                            tab_size,
13773                        }),
13774                    ) = &comment_prefix
13775                    {
13776                        let line_trimmed = line_trimmed
13777                            .strip_prefix(start.as_ref())
13778                            .map(|s| {
13779                                let mut indent_size = indent_size;
13780                                indent_size.len -= tab_size;
13781                                let indent_prefix: String = indent_size.chars().collect();
13782                                first_line_delimiter = Some((indent_prefix, start));
13783                                s.trim_start()
13784                            })
13785                            .unwrap_or(line_trimmed);
13786                        let line_trimmed = line_trimmed
13787                            .strip_suffix(end.as_ref())
13788                            .map(|s| {
13789                                last_line_delimiter = Some(end);
13790                                s.trim_end()
13791                            })
13792                            .unwrap_or(line_trimmed);
13793                        let line_trimmed = line_trimmed
13794                            .strip_prefix(prefix.as_ref())
13795                            .unwrap_or(line_trimmed);
13796                        Ok(line_trimmed)
13797                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13798                        line_trimmed.strip_prefix(prefix).with_context(|| {
13799                            format!("line did not start with prefix {prefix:?}: {line:?}")
13800                        })
13801                    } else {
13802                        line_trimmed
13803                            .strip_prefix(&line_prefix.trim_start())
13804                            .with_context(|| {
13805                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13806                            })
13807                    }
13808                })
13809                .collect::<Result<Vec<_>, _>>()
13810                .log_err()
13811            else {
13812                continue;
13813            };
13814
13815            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13816                buffer
13817                    .language_settings_at(Point::new(start_row, 0), cx)
13818                    .preferred_line_length as usize
13819            });
13820
13821            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13822                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13823            } else {
13824                line_prefix.clone()
13825            };
13826
13827            let wrapped_text = {
13828                let mut wrapped_text = wrap_with_prefix(
13829                    line_prefix,
13830                    subsequent_lines_prefix,
13831                    lines_without_prefixes.join("\n"),
13832                    wrap_column,
13833                    tab_size,
13834                    options.preserve_existing_whitespace,
13835                );
13836
13837                if let Some((indent, delimiter)) = first_line_delimiter {
13838                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13839                }
13840                if let Some(last_line) = last_line_delimiter {
13841                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13842                }
13843
13844                wrapped_text
13845            };
13846
13847            // TODO: should always use char-based diff while still supporting cursor behavior that
13848            // matches vim.
13849            let mut diff_options = DiffOptions::default();
13850            if options.override_language_settings {
13851                diff_options.max_word_diff_len = 0;
13852                diff_options.max_word_diff_line_count = 0;
13853            } else {
13854                diff_options.max_word_diff_len = usize::MAX;
13855                diff_options.max_word_diff_line_count = usize::MAX;
13856            }
13857
13858            for (old_range, new_text) in
13859                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13860            {
13861                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13862                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13863                edits.push((edit_start..edit_end, new_text));
13864            }
13865
13866            rewrapped_row_ranges.push(start_row..=end_row);
13867        }
13868
13869        self.buffer
13870            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13871    }
13872
13873    pub fn cut_common(
13874        &mut self,
13875        cut_no_selection_line: bool,
13876        window: &mut Window,
13877        cx: &mut Context<Self>,
13878    ) -> ClipboardItem {
13879        let mut text = String::new();
13880        let buffer = self.buffer.read(cx).snapshot(cx);
13881        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13882        let mut clipboard_selections = Vec::with_capacity(selections.len());
13883        {
13884            let max_point = buffer.max_point();
13885            let mut is_first = true;
13886            let mut prev_selection_was_entire_line = false;
13887            for selection in &mut selections {
13888                let is_entire_line =
13889                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13890                if is_entire_line {
13891                    selection.start = Point::new(selection.start.row, 0);
13892                    if !selection.is_empty() && selection.end.column == 0 {
13893                        selection.end = cmp::min(max_point, selection.end);
13894                    } else {
13895                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13896                    }
13897                    selection.goal = SelectionGoal::None;
13898                }
13899                if is_first {
13900                    is_first = false;
13901                } else if !prev_selection_was_entire_line {
13902                    text += "\n";
13903                }
13904                prev_selection_was_entire_line = is_entire_line;
13905                let mut len = 0;
13906                for chunk in buffer.text_for_range(selection.start..selection.end) {
13907                    text.push_str(chunk);
13908                    len += chunk.len();
13909                }
13910
13911                clipboard_selections.push(ClipboardSelection::for_buffer(
13912                    len,
13913                    is_entire_line,
13914                    selection.range(),
13915                    &buffer,
13916                    self.project.as_ref(),
13917                    cx,
13918                ));
13919            }
13920        }
13921
13922        self.transact(window, cx, |this, window, cx| {
13923            this.change_selections(Default::default(), window, cx, |s| {
13924                s.select(selections);
13925            });
13926            this.insert("", window, cx);
13927        });
13928        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13929    }
13930
13931    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13932        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13933        let item = self.cut_common(true, window, cx);
13934        cx.write_to_clipboard(item);
13935    }
13936
13937    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13938        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13939        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13940            s.move_with(&mut |snapshot, sel| {
13941                if sel.is_empty() {
13942                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13943                }
13944                if sel.is_empty() {
13945                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13946                }
13947            });
13948        });
13949        let item = self.cut_common(false, window, cx);
13950        cx.set_global(KillRing(item))
13951    }
13952
13953    pub fn kill_ring_yank(
13954        &mut self,
13955        _: &KillRingYank,
13956        window: &mut Window,
13957        cx: &mut Context<Self>,
13958    ) {
13959        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13960        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13961            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13962                (kill_ring.text().to_string(), kill_ring.metadata_json())
13963            } else {
13964                return;
13965            }
13966        } else {
13967            return;
13968        };
13969        self.do_paste(&text, metadata, false, window, cx);
13970    }
13971
13972    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13973        self.do_copy(true, cx);
13974    }
13975
13976    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13977        self.do_copy(false, cx);
13978    }
13979
13980    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13981        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13982        let buffer = self.buffer.read(cx).read(cx);
13983        let mut text = String::new();
13984        let mut clipboard_selections = Vec::with_capacity(selections.len());
13985
13986        let max_point = buffer.max_point();
13987        let mut is_first = true;
13988        for selection in &selections {
13989            let mut start = selection.start;
13990            let mut end = selection.end;
13991            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13992            let mut add_trailing_newline = false;
13993            if is_entire_line {
13994                start = Point::new(start.row, 0);
13995                let next_line_start = Point::new(end.row + 1, 0);
13996                if next_line_start <= max_point {
13997                    end = next_line_start;
13998                } else {
13999                    // We're on the last line without a trailing newline.
14000                    // Copy to the end of the line and add a newline afterwards.
14001                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
14002                    add_trailing_newline = true;
14003                }
14004            }
14005
14006            let mut trimmed_selections = Vec::new();
14007            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
14008                let row = MultiBufferRow(start.row);
14009                let first_indent = buffer.indent_size_for_line(row);
14010                if first_indent.len == 0 || start.column > first_indent.len {
14011                    trimmed_selections.push(start..end);
14012                } else {
14013                    trimmed_selections.push(
14014                        Point::new(row.0, first_indent.len)
14015                            ..Point::new(row.0, buffer.line_len(row)),
14016                    );
14017                    for row in start.row + 1..=end.row {
14018                        let mut line_len = buffer.line_len(MultiBufferRow(row));
14019                        if row == end.row {
14020                            line_len = end.column;
14021                        }
14022                        if line_len == 0 {
14023                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
14024                            continue;
14025                        }
14026                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
14027                        if row_indent_size.len >= first_indent.len {
14028                            trimmed_selections
14029                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
14030                        } else {
14031                            trimmed_selections.clear();
14032                            trimmed_selections.push(start..end);
14033                            break;
14034                        }
14035                    }
14036                }
14037            } else {
14038                trimmed_selections.push(start..end);
14039            }
14040
14041            let is_multiline_trim = trimmed_selections.len() > 1;
14042            let mut selection_len: usize = 0;
14043            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
14044
14045            for trimmed_range in trimmed_selections {
14046                if is_first {
14047                    is_first = false;
14048                } else if is_multiline_trim || !prev_selection_was_entire_line {
14049                    text.push('\n');
14050                    if is_multiline_trim {
14051                        selection_len += 1;
14052                    }
14053                }
14054                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
14055                    text.push_str(chunk);
14056                    selection_len += chunk.len();
14057                }
14058                if add_trailing_newline {
14059                    text.push('\n');
14060                    selection_len += 1;
14061                }
14062            }
14063
14064            clipboard_selections.push(ClipboardSelection::for_buffer(
14065                selection_len,
14066                is_entire_line,
14067                start..end,
14068                &buffer,
14069                self.project.as_ref(),
14070                cx,
14071            ));
14072        }
14073
14074        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
14075            text,
14076            clipboard_selections,
14077        ));
14078    }
14079
14080    pub fn do_paste(
14081        &mut self,
14082        text: &String,
14083        clipboard_selections: Option<Vec<ClipboardSelection>>,
14084        handle_entire_lines: bool,
14085        window: &mut Window,
14086        cx: &mut Context<Self>,
14087    ) {
14088        if self.read_only(cx) {
14089            return;
14090        }
14091
14092        self.finalize_last_transaction(cx);
14093
14094        let clipboard_text = Cow::Borrowed(text.as_str());
14095
14096        self.transact(window, cx, |this, window, cx| {
14097            let had_active_edit_prediction = this.has_active_edit_prediction();
14098            let display_map = this.display_snapshot(cx);
14099            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14100            let cursor_offset = this
14101                .selections
14102                .last::<MultiBufferOffset>(&display_map)
14103                .head();
14104
14105            if let Some(mut clipboard_selections) = clipboard_selections {
14106                let all_selections_were_entire_line =
14107                    clipboard_selections.iter().all(|s| s.is_entire_line);
14108                let first_selection_indent_column =
14109                    clipboard_selections.first().map(|s| s.first_line_indent);
14110                if clipboard_selections.len() != old_selections.len() {
14111                    clipboard_selections.drain(..);
14112                }
14113                let mut auto_indent_on_paste = true;
14114
14115                this.buffer.update(cx, |buffer, cx| {
14116                    let snapshot = buffer.read(cx);
14117                    auto_indent_on_paste = snapshot
14118                        .language_settings_at(cursor_offset, cx)
14119                        .auto_indent_on_paste;
14120
14121                    let mut start_offset = 0;
14122                    let mut edits = Vec::new();
14123                    let mut original_indent_columns = Vec::new();
14124                    for (ix, selection) in old_selections.iter().enumerate() {
14125                        let to_insert;
14126                        let entire_line;
14127                        let original_indent_column;
14128                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14129                            let end_offset = start_offset + clipboard_selection.len;
14130                            to_insert = &clipboard_text[start_offset..end_offset];
14131                            entire_line = clipboard_selection.is_entire_line;
14132                            start_offset = if entire_line {
14133                                end_offset
14134                            } else {
14135                                end_offset + 1
14136                            };
14137                            original_indent_column = Some(clipboard_selection.first_line_indent);
14138                        } else {
14139                            to_insert = &*clipboard_text;
14140                            entire_line = all_selections_were_entire_line;
14141                            original_indent_column = first_selection_indent_column
14142                        }
14143
14144                        let (range, to_insert) =
14145                            if selection.is_empty() && handle_entire_lines && entire_line {
14146                                // If the corresponding selection was empty when this slice of the
14147                                // clipboard text was written, then the entire line containing the
14148                                // selection was copied. If this selection is also currently empty,
14149                                // then paste the line before the current line of the buffer.
14150                                let column = selection.start.to_point(&snapshot).column as usize;
14151                                let line_start = selection.start - column;
14152                                (line_start..line_start, Cow::Borrowed(to_insert))
14153                            } else {
14154                                let language = snapshot.language_at(selection.head());
14155                                let range = selection.range();
14156                                if let Some(language) = language
14157                                    && language.name() == "Markdown"
14158                                {
14159                                    edit_for_markdown_paste(
14160                                        &snapshot,
14161                                        range,
14162                                        to_insert,
14163                                        url::Url::parse(to_insert).ok(),
14164                                    )
14165                                } else {
14166                                    (range, Cow::Borrowed(to_insert))
14167                                }
14168                            };
14169
14170                        edits.push((range, to_insert));
14171                        original_indent_columns.push(original_indent_column);
14172                    }
14173                    drop(snapshot);
14174
14175                    buffer.edit(
14176                        edits,
14177                        if auto_indent_on_paste {
14178                            Some(AutoindentMode::Block {
14179                                original_indent_columns,
14180                            })
14181                        } else {
14182                            None
14183                        },
14184                        cx,
14185                    );
14186                });
14187
14188                let selections = this
14189                    .selections
14190                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14191                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14192            } else {
14193                let url = url::Url::parse(&clipboard_text).ok();
14194
14195                let auto_indent_mode = if !clipboard_text.is_empty() {
14196                    Some(AutoindentMode::Block {
14197                        original_indent_columns: Vec::new(),
14198                    })
14199                } else {
14200                    None
14201                };
14202
14203                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14204                    let snapshot = buffer.snapshot(cx);
14205
14206                    let anchors = old_selections
14207                        .iter()
14208                        .map(|s| {
14209                            let anchor = snapshot.anchor_after(s.head());
14210                            s.map(|_| anchor)
14211                        })
14212                        .collect::<Vec<_>>();
14213
14214                    let mut edits = Vec::new();
14215
14216                    // When pasting text without metadata (e.g. copied from an
14217                    // external editor using multiple cursors) and the number of
14218                    // lines matches the number of selections, distribute one
14219                    // line per cursor instead of pasting the whole text at each.
14220                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14221                    let distribute_lines =
14222                        old_selections.len() > 1 && lines.len() == old_selections.len();
14223
14224                    for (ix, selection) in old_selections.iter().enumerate() {
14225                        let language = snapshot.language_at(selection.head());
14226                        let range = selection.range();
14227
14228                        let text_for_cursor: &str = if distribute_lines {
14229                            lines[ix]
14230                        } else {
14231                            &clipboard_text
14232                        };
14233
14234                        let (edit_range, edit_text) = if let Some(language) = language
14235                            && language.name() == "Markdown"
14236                        {
14237                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14238                        } else {
14239                            (range, Cow::Borrowed(text_for_cursor))
14240                        };
14241
14242                        edits.push((edit_range, edit_text));
14243                    }
14244
14245                    drop(snapshot);
14246                    buffer.edit(edits, auto_indent_mode, cx);
14247
14248                    anchors
14249                });
14250
14251                this.change_selections(Default::default(), window, cx, |s| {
14252                    s.select_anchors(selection_anchors);
14253                });
14254            }
14255
14256            //   🤔                 |    ..     | show_in_menu |
14257            // | ..                  |   true        true
14258            // | had_edit_prediction |   false       true
14259
14260            let trigger_in_words =
14261                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14262
14263            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14264        });
14265    }
14266
14267    pub fn diff_clipboard_with_selection(
14268        &mut self,
14269        _: &DiffClipboardWithSelection,
14270        window: &mut Window,
14271        cx: &mut Context<Self>,
14272    ) {
14273        let selections = self
14274            .selections
14275            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14276
14277        if selections.is_empty() {
14278            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14279            return;
14280        };
14281
14282        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14283            item.entries().iter().find_map(|entry| match entry {
14284                ClipboardEntry::String(text) => Some(text.text().to_string()),
14285                _ => None,
14286            })
14287        });
14288
14289        let Some(clipboard_text) = clipboard_text else {
14290            log::warn!("Clipboard doesn't contain text.");
14291            return;
14292        };
14293
14294        window.dispatch_action(
14295            Box::new(DiffClipboardWithSelectionData {
14296                clipboard_text,
14297                editor: cx.entity(),
14298            }),
14299            cx,
14300        );
14301    }
14302
14303    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14304        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14305        if let Some(item) = cx.read_from_clipboard() {
14306            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14307                ClipboardEntry::String(s) => Some(s),
14308                _ => None,
14309            });
14310            match clipboard_string {
14311                Some(clipboard_string) => self.do_paste(
14312                    clipboard_string.text(),
14313                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14314                    true,
14315                    window,
14316                    cx,
14317                ),
14318                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14319            }
14320        }
14321    }
14322
14323    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14324        if self.read_only(cx) {
14325            return;
14326        }
14327
14328        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14329
14330        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14331            if let Some((selections, _)) =
14332                self.selection_history.transaction(transaction_id).cloned()
14333            {
14334                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14335                    s.select_anchors(selections.to_vec());
14336                });
14337            } else {
14338                log::error!(
14339                    "No entry in selection_history found for undo. \
14340                     This may correspond to a bug where undo does not update the selection. \
14341                     If this is occurring, please add details to \
14342                     https://github.com/zed-industries/zed/issues/22692"
14343                );
14344            }
14345            self.request_autoscroll(Autoscroll::fit(), cx);
14346            self.unmark_text(window, cx);
14347            self.refresh_edit_prediction(true, false, window, cx);
14348            cx.emit(EditorEvent::Edited { transaction_id });
14349            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14350        }
14351    }
14352
14353    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14354        if self.read_only(cx) {
14355            return;
14356        }
14357
14358        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14359
14360        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14361            if let Some((_, Some(selections))) =
14362                self.selection_history.transaction(transaction_id).cloned()
14363            {
14364                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14365                    s.select_anchors(selections.to_vec());
14366                });
14367            } else {
14368                log::error!(
14369                    "No entry in selection_history found for redo. \
14370                     This may correspond to a bug where undo does not update the selection. \
14371                     If this is occurring, please add details to \
14372                     https://github.com/zed-industries/zed/issues/22692"
14373                );
14374            }
14375            self.request_autoscroll(Autoscroll::fit(), cx);
14376            self.unmark_text(window, cx);
14377            self.refresh_edit_prediction(true, false, window, cx);
14378            cx.emit(EditorEvent::Edited { transaction_id });
14379        }
14380    }
14381
14382    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14383        self.buffer
14384            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14385    }
14386
14387    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14388        self.buffer
14389            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14390    }
14391
14392    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14393        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14394        self.change_selections(Default::default(), window, cx, |s| {
14395            s.move_with(&mut |map, selection| {
14396                let cursor = if selection.is_empty() {
14397                    movement::left(map, selection.start)
14398                } else {
14399                    selection.start
14400                };
14401                selection.collapse_to(cursor, SelectionGoal::None);
14402            });
14403        })
14404    }
14405
14406    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14407        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14408        self.change_selections(Default::default(), window, cx, |s| {
14409            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14410        })
14411    }
14412
14413    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14414        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14415        self.change_selections(Default::default(), window, cx, |s| {
14416            s.move_with(&mut |map, selection| {
14417                let cursor = if selection.is_empty() {
14418                    movement::right(map, selection.end)
14419                } else {
14420                    selection.end
14421                };
14422                selection.collapse_to(cursor, SelectionGoal::None)
14423            });
14424        })
14425    }
14426
14427    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14428        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14429        self.change_selections(Default::default(), window, cx, |s| {
14430            s.move_heads_with(&mut |map, head, _| {
14431                (movement::right(map, head), SelectionGoal::None)
14432            });
14433        });
14434    }
14435
14436    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14437        if self.take_rename(true, window, cx).is_some() {
14438            return;
14439        }
14440
14441        if self.mode.is_single_line() {
14442            cx.propagate();
14443            return;
14444        }
14445
14446        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14447
14448        let text_layout_details = &self.text_layout_details(window, cx);
14449        let selection_count = self.selections.count();
14450        let first_selection = self.selections.first_anchor();
14451
14452        self.change_selections(Default::default(), window, cx, |s| {
14453            s.move_with(&mut |map, selection| {
14454                if !selection.is_empty() {
14455                    selection.goal = SelectionGoal::None;
14456                }
14457                let (cursor, goal) = movement::up(
14458                    map,
14459                    selection.start,
14460                    selection.goal,
14461                    false,
14462                    text_layout_details,
14463                );
14464                selection.collapse_to(cursor, goal);
14465            });
14466        });
14467
14468        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14469        {
14470            cx.propagate();
14471        }
14472    }
14473
14474    pub fn move_up_by_lines(
14475        &mut self,
14476        action: &MoveUpByLines,
14477        window: &mut Window,
14478        cx: &mut Context<Self>,
14479    ) {
14480        if self.take_rename(true, window, cx).is_some() {
14481            return;
14482        }
14483
14484        if self.mode.is_single_line() {
14485            cx.propagate();
14486            return;
14487        }
14488
14489        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14490
14491        let text_layout_details = &self.text_layout_details(window, cx);
14492
14493        self.change_selections(Default::default(), window, cx, |s| {
14494            s.move_with(&mut |map, selection| {
14495                if !selection.is_empty() {
14496                    selection.goal = SelectionGoal::None;
14497                }
14498                let (cursor, goal) = movement::up_by_rows(
14499                    map,
14500                    selection.start,
14501                    action.lines,
14502                    selection.goal,
14503                    false,
14504                    text_layout_details,
14505                );
14506                selection.collapse_to(cursor, goal);
14507            });
14508        })
14509    }
14510
14511    pub fn move_down_by_lines(
14512        &mut self,
14513        action: &MoveDownByLines,
14514        window: &mut Window,
14515        cx: &mut Context<Self>,
14516    ) {
14517        if self.take_rename(true, window, cx).is_some() {
14518            return;
14519        }
14520
14521        if self.mode.is_single_line() {
14522            cx.propagate();
14523            return;
14524        }
14525
14526        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14527
14528        let text_layout_details = &self.text_layout_details(window, cx);
14529
14530        self.change_selections(Default::default(), window, cx, |s| {
14531            s.move_with(&mut |map, selection| {
14532                if !selection.is_empty() {
14533                    selection.goal = SelectionGoal::None;
14534                }
14535                let (cursor, goal) = movement::down_by_rows(
14536                    map,
14537                    selection.start,
14538                    action.lines,
14539                    selection.goal,
14540                    false,
14541                    text_layout_details,
14542                );
14543                selection.collapse_to(cursor, goal);
14544            });
14545        })
14546    }
14547
14548    pub fn select_down_by_lines(
14549        &mut self,
14550        action: &SelectDownByLines,
14551        window: &mut Window,
14552        cx: &mut Context<Self>,
14553    ) {
14554        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14555        let text_layout_details = &self.text_layout_details(window, cx);
14556        self.change_selections(Default::default(), window, cx, |s| {
14557            s.move_heads_with(&mut |map, head, goal| {
14558                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14559            })
14560        })
14561    }
14562
14563    pub fn select_up_by_lines(
14564        &mut self,
14565        action: &SelectUpByLines,
14566        window: &mut Window,
14567        cx: &mut Context<Self>,
14568    ) {
14569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14570        let text_layout_details = &self.text_layout_details(window, cx);
14571        self.change_selections(Default::default(), window, cx, |s| {
14572            s.move_heads_with(&mut |map, head, goal| {
14573                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14574            })
14575        })
14576    }
14577
14578    pub fn select_page_up(
14579        &mut self,
14580        _: &SelectPageUp,
14581        window: &mut Window,
14582        cx: &mut Context<Self>,
14583    ) {
14584        let Some(row_count) = self.visible_row_count() else {
14585            return;
14586        };
14587
14588        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14589
14590        let text_layout_details = &self.text_layout_details(window, cx);
14591
14592        self.change_selections(Default::default(), window, cx, |s| {
14593            s.move_heads_with(&mut |map, head, goal| {
14594                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14595            })
14596        })
14597    }
14598
14599    pub fn move_page_up(
14600        &mut self,
14601        action: &MovePageUp,
14602        window: &mut Window,
14603        cx: &mut Context<Self>,
14604    ) {
14605        if self.take_rename(true, window, cx).is_some() {
14606            return;
14607        }
14608
14609        if self
14610            .context_menu
14611            .borrow_mut()
14612            .as_mut()
14613            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14614            .unwrap_or(false)
14615        {
14616            return;
14617        }
14618
14619        if matches!(self.mode, EditorMode::SingleLine) {
14620            cx.propagate();
14621            return;
14622        }
14623
14624        let Some(row_count) = self.visible_row_count() else {
14625            return;
14626        };
14627
14628        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14629
14630        let effects = if action.center_cursor {
14631            SelectionEffects::scroll(Autoscroll::center())
14632        } else {
14633            SelectionEffects::default()
14634        };
14635
14636        let text_layout_details = &self.text_layout_details(window, cx);
14637
14638        self.change_selections(effects, window, cx, |s| {
14639            s.move_with(&mut |map, selection| {
14640                if !selection.is_empty() {
14641                    selection.goal = SelectionGoal::None;
14642                }
14643                let (cursor, goal) = movement::up_by_rows(
14644                    map,
14645                    selection.end,
14646                    row_count,
14647                    selection.goal,
14648                    false,
14649                    text_layout_details,
14650                );
14651                selection.collapse_to(cursor, goal);
14652            });
14653        });
14654    }
14655
14656    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14657        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14658        let text_layout_details = &self.text_layout_details(window, cx);
14659        self.change_selections(Default::default(), window, cx, |s| {
14660            s.move_heads_with(&mut |map, head, goal| {
14661                movement::up(map, head, goal, false, text_layout_details)
14662            })
14663        })
14664    }
14665
14666    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14667        self.take_rename(true, window, cx);
14668
14669        if self.mode.is_single_line() {
14670            cx.propagate();
14671            return;
14672        }
14673
14674        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14675
14676        let text_layout_details = &self.text_layout_details(window, cx);
14677        let selection_count = self.selections.count();
14678        let first_selection = self.selections.first_anchor();
14679
14680        self.change_selections(Default::default(), window, cx, |s| {
14681            s.move_with(&mut |map, selection| {
14682                if !selection.is_empty() {
14683                    selection.goal = SelectionGoal::None;
14684                }
14685                let (cursor, goal) = movement::down(
14686                    map,
14687                    selection.end,
14688                    selection.goal,
14689                    false,
14690                    text_layout_details,
14691                );
14692                selection.collapse_to(cursor, goal);
14693            });
14694        });
14695
14696        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14697        {
14698            cx.propagate();
14699        }
14700    }
14701
14702    pub fn select_page_down(
14703        &mut self,
14704        _: &SelectPageDown,
14705        window: &mut Window,
14706        cx: &mut Context<Self>,
14707    ) {
14708        let Some(row_count) = self.visible_row_count() else {
14709            return;
14710        };
14711
14712        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14713
14714        let text_layout_details = &self.text_layout_details(window, cx);
14715
14716        self.change_selections(Default::default(), window, cx, |s| {
14717            s.move_heads_with(&mut |map, head, goal| {
14718                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14719            })
14720        })
14721    }
14722
14723    pub fn move_page_down(
14724        &mut self,
14725        action: &MovePageDown,
14726        window: &mut Window,
14727        cx: &mut Context<Self>,
14728    ) {
14729        if self.take_rename(true, window, cx).is_some() {
14730            return;
14731        }
14732
14733        if self
14734            .context_menu
14735            .borrow_mut()
14736            .as_mut()
14737            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14738            .unwrap_or(false)
14739        {
14740            return;
14741        }
14742
14743        if matches!(self.mode, EditorMode::SingleLine) {
14744            cx.propagate();
14745            return;
14746        }
14747
14748        let Some(row_count) = self.visible_row_count() else {
14749            return;
14750        };
14751
14752        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14753
14754        let effects = if action.center_cursor {
14755            SelectionEffects::scroll(Autoscroll::center())
14756        } else {
14757            SelectionEffects::default()
14758        };
14759
14760        let text_layout_details = &self.text_layout_details(window, cx);
14761        self.change_selections(effects, window, cx, |s| {
14762            s.move_with(&mut |map, selection| {
14763                if !selection.is_empty() {
14764                    selection.goal = SelectionGoal::None;
14765                }
14766                let (cursor, goal) = movement::down_by_rows(
14767                    map,
14768                    selection.end,
14769                    row_count,
14770                    selection.goal,
14771                    false,
14772                    text_layout_details,
14773                );
14774                selection.collapse_to(cursor, goal);
14775            });
14776        });
14777    }
14778
14779    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14780        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14781        let text_layout_details = &self.text_layout_details(window, cx);
14782        self.change_selections(Default::default(), window, cx, |s| {
14783            s.move_heads_with(&mut |map, head, goal| {
14784                movement::down(map, head, goal, false, text_layout_details)
14785            })
14786        });
14787    }
14788
14789    pub fn context_menu_first(
14790        &mut self,
14791        _: &ContextMenuFirst,
14792        window: &mut Window,
14793        cx: &mut Context<Self>,
14794    ) {
14795        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14796            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14797        }
14798    }
14799
14800    pub fn context_menu_prev(
14801        &mut self,
14802        _: &ContextMenuPrevious,
14803        window: &mut Window,
14804        cx: &mut Context<Self>,
14805    ) {
14806        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14807            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14808        }
14809    }
14810
14811    pub fn context_menu_next(
14812        &mut self,
14813        _: &ContextMenuNext,
14814        window: &mut Window,
14815        cx: &mut Context<Self>,
14816    ) {
14817        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14818            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14819        }
14820    }
14821
14822    pub fn context_menu_last(
14823        &mut self,
14824        _: &ContextMenuLast,
14825        window: &mut Window,
14826        cx: &mut Context<Self>,
14827    ) {
14828        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14829            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14830        }
14831    }
14832
14833    pub fn signature_help_prev(
14834        &mut self,
14835        _: &SignatureHelpPrevious,
14836        _: &mut Window,
14837        cx: &mut Context<Self>,
14838    ) {
14839        if let Some(popover) = self.signature_help_state.popover_mut() {
14840            if popover.current_signature == 0 {
14841                popover.current_signature = popover.signatures.len() - 1;
14842            } else {
14843                popover.current_signature -= 1;
14844            }
14845            cx.notify();
14846        }
14847    }
14848
14849    pub fn signature_help_next(
14850        &mut self,
14851        _: &SignatureHelpNext,
14852        _: &mut Window,
14853        cx: &mut Context<Self>,
14854    ) {
14855        if let Some(popover) = self.signature_help_state.popover_mut() {
14856            if popover.current_signature + 1 == popover.signatures.len() {
14857                popover.current_signature = 0;
14858            } else {
14859                popover.current_signature += 1;
14860            }
14861            cx.notify();
14862        }
14863    }
14864
14865    pub fn move_to_previous_word_start(
14866        &mut self,
14867        _: &MoveToPreviousWordStart,
14868        window: &mut Window,
14869        cx: &mut Context<Self>,
14870    ) {
14871        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14872        self.change_selections(Default::default(), window, cx, |s| {
14873            s.move_cursors_with(&mut |map, head, _| {
14874                (
14875                    movement::previous_word_start(map, head),
14876                    SelectionGoal::None,
14877                )
14878            });
14879        })
14880    }
14881
14882    pub fn move_to_previous_subword_start(
14883        &mut self,
14884        _: &MoveToPreviousSubwordStart,
14885        window: &mut Window,
14886        cx: &mut Context<Self>,
14887    ) {
14888        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14889        self.change_selections(Default::default(), window, cx, |s| {
14890            s.move_cursors_with(&mut |map, head, _| {
14891                (
14892                    movement::previous_subword_start(map, head),
14893                    SelectionGoal::None,
14894                )
14895            });
14896        })
14897    }
14898
14899    pub fn select_to_previous_word_start(
14900        &mut self,
14901        _: &SelectToPreviousWordStart,
14902        window: &mut Window,
14903        cx: &mut Context<Self>,
14904    ) {
14905        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14906        self.change_selections(Default::default(), window, cx, |s| {
14907            s.move_heads_with(&mut |map, head, _| {
14908                (
14909                    movement::previous_word_start(map, head),
14910                    SelectionGoal::None,
14911                )
14912            });
14913        })
14914    }
14915
14916    pub fn select_to_previous_subword_start(
14917        &mut self,
14918        _: &SelectToPreviousSubwordStart,
14919        window: &mut Window,
14920        cx: &mut Context<Self>,
14921    ) {
14922        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14923        self.change_selections(Default::default(), window, cx, |s| {
14924            s.move_heads_with(&mut |map, head, _| {
14925                (
14926                    movement::previous_subword_start(map, head),
14927                    SelectionGoal::None,
14928                )
14929            });
14930        })
14931    }
14932
14933    pub fn delete_to_previous_word_start(
14934        &mut self,
14935        action: &DeleteToPreviousWordStart,
14936        window: &mut Window,
14937        cx: &mut Context<Self>,
14938    ) {
14939        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14940        self.transact(window, cx, |this, window, cx| {
14941            this.select_autoclose_pair(window, cx);
14942            this.change_selections(Default::default(), window, cx, |s| {
14943                s.move_with(&mut |map, selection| {
14944                    if selection.is_empty() {
14945                        let mut cursor = if action.ignore_newlines {
14946                            movement::previous_word_start(map, selection.head())
14947                        } else {
14948                            movement::previous_word_start_or_newline(map, selection.head())
14949                        };
14950                        cursor = movement::adjust_greedy_deletion(
14951                            map,
14952                            selection.head(),
14953                            cursor,
14954                            action.ignore_brackets,
14955                        );
14956                        selection.set_head(cursor, SelectionGoal::None);
14957                    }
14958                });
14959            });
14960            this.insert("", window, cx);
14961        });
14962    }
14963
14964    pub fn delete_to_previous_subword_start(
14965        &mut self,
14966        action: &DeleteToPreviousSubwordStart,
14967        window: &mut Window,
14968        cx: &mut Context<Self>,
14969    ) {
14970        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14971        self.transact(window, cx, |this, window, cx| {
14972            this.select_autoclose_pair(window, cx);
14973            this.change_selections(Default::default(), window, cx, |s| {
14974                s.move_with(&mut |map, selection| {
14975                    if selection.is_empty() {
14976                        let mut cursor = if action.ignore_newlines {
14977                            movement::previous_subword_start(map, selection.head())
14978                        } else {
14979                            movement::previous_subword_start_or_newline(map, selection.head())
14980                        };
14981                        cursor = movement::adjust_greedy_deletion(
14982                            map,
14983                            selection.head(),
14984                            cursor,
14985                            action.ignore_brackets,
14986                        );
14987                        selection.set_head(cursor, SelectionGoal::None);
14988                    }
14989                });
14990            });
14991            this.insert("", window, cx);
14992        });
14993    }
14994
14995    pub fn move_to_next_word_end(
14996        &mut self,
14997        _: &MoveToNextWordEnd,
14998        window: &mut Window,
14999        cx: &mut Context<Self>,
15000    ) {
15001        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15002        self.change_selections(Default::default(), window, cx, |s| {
15003            s.move_cursors_with(&mut |map, head, _| {
15004                (movement::next_word_end(map, head), SelectionGoal::None)
15005            });
15006        })
15007    }
15008
15009    pub fn move_to_next_subword_end(
15010        &mut self,
15011        _: &MoveToNextSubwordEnd,
15012        window: &mut Window,
15013        cx: &mut Context<Self>,
15014    ) {
15015        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15016        self.change_selections(Default::default(), window, cx, |s| {
15017            s.move_cursors_with(&mut |map, head, _| {
15018                (movement::next_subword_end(map, head), SelectionGoal::None)
15019            });
15020        })
15021    }
15022
15023    pub fn select_to_next_word_end(
15024        &mut self,
15025        _: &SelectToNextWordEnd,
15026        window: &mut Window,
15027        cx: &mut Context<Self>,
15028    ) {
15029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15030        self.change_selections(Default::default(), window, cx, |s| {
15031            s.move_heads_with(&mut |map, head, _| {
15032                (movement::next_word_end(map, head), SelectionGoal::None)
15033            });
15034        })
15035    }
15036
15037    pub fn select_to_next_subword_end(
15038        &mut self,
15039        _: &SelectToNextSubwordEnd,
15040        window: &mut Window,
15041        cx: &mut Context<Self>,
15042    ) {
15043        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15044        self.change_selections(Default::default(), window, cx, |s| {
15045            s.move_heads_with(&mut |map, head, _| {
15046                (movement::next_subword_end(map, head), SelectionGoal::None)
15047            });
15048        })
15049    }
15050
15051    pub fn delete_to_next_word_end(
15052        &mut self,
15053        action: &DeleteToNextWordEnd,
15054        window: &mut Window,
15055        cx: &mut Context<Self>,
15056    ) {
15057        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15058        self.transact(window, cx, |this, window, cx| {
15059            this.change_selections(Default::default(), window, cx, |s| {
15060                s.move_with(&mut |map, selection| {
15061                    if selection.is_empty() {
15062                        let mut cursor = if action.ignore_newlines {
15063                            movement::next_word_end(map, selection.head())
15064                        } else {
15065                            movement::next_word_end_or_newline(map, selection.head())
15066                        };
15067                        cursor = movement::adjust_greedy_deletion(
15068                            map,
15069                            selection.head(),
15070                            cursor,
15071                            action.ignore_brackets,
15072                        );
15073                        selection.set_head(cursor, SelectionGoal::None);
15074                    }
15075                });
15076            });
15077            this.insert("", window, cx);
15078        });
15079    }
15080
15081    pub fn delete_to_next_subword_end(
15082        &mut self,
15083        action: &DeleteToNextSubwordEnd,
15084        window: &mut Window,
15085        cx: &mut Context<Self>,
15086    ) {
15087        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15088        self.transact(window, cx, |this, window, cx| {
15089            this.change_selections(Default::default(), window, cx, |s| {
15090                s.move_with(&mut |map, selection| {
15091                    if selection.is_empty() {
15092                        let mut cursor = if action.ignore_newlines {
15093                            movement::next_subword_end(map, selection.head())
15094                        } else {
15095                            movement::next_subword_end_or_newline(map, selection.head())
15096                        };
15097                        cursor = movement::adjust_greedy_deletion(
15098                            map,
15099                            selection.head(),
15100                            cursor,
15101                            action.ignore_brackets,
15102                        );
15103                        selection.set_head(cursor, SelectionGoal::None);
15104                    }
15105                });
15106            });
15107            this.insert("", window, cx);
15108        });
15109    }
15110
15111    pub fn move_to_beginning_of_line(
15112        &mut self,
15113        action: &MoveToBeginningOfLine,
15114        window: &mut Window,
15115        cx: &mut Context<Self>,
15116    ) {
15117        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15119        self.change_selections(Default::default(), window, cx, |s| {
15120            s.move_cursors_with(&mut |map, head, _| {
15121                (
15122                    movement::indented_line_beginning(
15123                        map,
15124                        head,
15125                        action.stop_at_soft_wraps,
15126                        stop_at_indent,
15127                    ),
15128                    SelectionGoal::None,
15129                )
15130            });
15131        })
15132    }
15133
15134    pub fn select_to_beginning_of_line(
15135        &mut self,
15136        action: &SelectToBeginningOfLine,
15137        window: &mut Window,
15138        cx: &mut Context<Self>,
15139    ) {
15140        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15141        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15142        self.change_selections(Default::default(), window, cx, |s| {
15143            s.move_heads_with(&mut |map, head, _| {
15144                (
15145                    movement::indented_line_beginning(
15146                        map,
15147                        head,
15148                        action.stop_at_soft_wraps,
15149                        stop_at_indent,
15150                    ),
15151                    SelectionGoal::None,
15152                )
15153            });
15154        });
15155    }
15156
15157    pub fn delete_to_beginning_of_line(
15158        &mut self,
15159        action: &DeleteToBeginningOfLine,
15160        window: &mut Window,
15161        cx: &mut Context<Self>,
15162    ) {
15163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15164        self.transact(window, cx, |this, window, cx| {
15165            this.change_selections(Default::default(), window, cx, |s| {
15166                s.move_with(&mut |_, selection| {
15167                    selection.reversed = true;
15168                });
15169            });
15170
15171            this.select_to_beginning_of_line(
15172                &SelectToBeginningOfLine {
15173                    stop_at_soft_wraps: false,
15174                    stop_at_indent: action.stop_at_indent,
15175                },
15176                window,
15177                cx,
15178            );
15179            this.backspace(&Backspace, window, cx);
15180        });
15181    }
15182
15183    pub fn move_to_end_of_line(
15184        &mut self,
15185        action: &MoveToEndOfLine,
15186        window: &mut Window,
15187        cx: &mut Context<Self>,
15188    ) {
15189        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15190        self.change_selections(Default::default(), window, cx, |s| {
15191            s.move_cursors_with(&mut |map, head, _| {
15192                (
15193                    movement::line_end(map, head, action.stop_at_soft_wraps),
15194                    SelectionGoal::None,
15195                )
15196            });
15197        })
15198    }
15199
15200    pub fn select_to_end_of_line(
15201        &mut self,
15202        action: &SelectToEndOfLine,
15203        window: &mut Window,
15204        cx: &mut Context<Self>,
15205    ) {
15206        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15207        self.change_selections(Default::default(), window, cx, |s| {
15208            s.move_heads_with(&mut |map, head, _| {
15209                (
15210                    movement::line_end(map, head, action.stop_at_soft_wraps),
15211                    SelectionGoal::None,
15212                )
15213            });
15214        })
15215    }
15216
15217    pub fn delete_to_end_of_line(
15218        &mut self,
15219        _: &DeleteToEndOfLine,
15220        window: &mut Window,
15221        cx: &mut Context<Self>,
15222    ) {
15223        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15224        self.transact(window, cx, |this, window, cx| {
15225            this.select_to_end_of_line(
15226                &SelectToEndOfLine {
15227                    stop_at_soft_wraps: false,
15228                },
15229                window,
15230                cx,
15231            );
15232            this.delete(&Delete, window, cx);
15233        });
15234    }
15235
15236    pub fn cut_to_end_of_line(
15237        &mut self,
15238        action: &CutToEndOfLine,
15239        window: &mut Window,
15240        cx: &mut Context<Self>,
15241    ) {
15242        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15243        self.transact(window, cx, |this, window, cx| {
15244            this.select_to_end_of_line(
15245                &SelectToEndOfLine {
15246                    stop_at_soft_wraps: false,
15247                },
15248                window,
15249                cx,
15250            );
15251            if !action.stop_at_newlines {
15252                this.change_selections(Default::default(), window, cx, |s| {
15253                    s.move_with(&mut |_, sel| {
15254                        if sel.is_empty() {
15255                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15256                        }
15257                    });
15258                });
15259            }
15260            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15261            let item = this.cut_common(false, window, cx);
15262            cx.write_to_clipboard(item);
15263        });
15264    }
15265
15266    pub fn move_to_start_of_paragraph(
15267        &mut self,
15268        _: &MoveToStartOfParagraph,
15269        window: &mut Window,
15270        cx: &mut Context<Self>,
15271    ) {
15272        if matches!(self.mode, EditorMode::SingleLine) {
15273            cx.propagate();
15274            return;
15275        }
15276        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15277        self.change_selections(Default::default(), window, cx, |s| {
15278            s.move_with(&mut |map, selection| {
15279                selection.collapse_to(
15280                    movement::start_of_paragraph(map, selection.head(), 1),
15281                    SelectionGoal::None,
15282                )
15283            });
15284        })
15285    }
15286
15287    pub fn move_to_end_of_paragraph(
15288        &mut self,
15289        _: &MoveToEndOfParagraph,
15290        window: &mut Window,
15291        cx: &mut Context<Self>,
15292    ) {
15293        if matches!(self.mode, EditorMode::SingleLine) {
15294            cx.propagate();
15295            return;
15296        }
15297        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15298        self.change_selections(Default::default(), window, cx, |s| {
15299            s.move_with(&mut |map, selection| {
15300                selection.collapse_to(
15301                    movement::end_of_paragraph(map, selection.head(), 1),
15302                    SelectionGoal::None,
15303                )
15304            });
15305        })
15306    }
15307
15308    pub fn select_to_start_of_paragraph(
15309        &mut self,
15310        _: &SelectToStartOfParagraph,
15311        window: &mut Window,
15312        cx: &mut Context<Self>,
15313    ) {
15314        if matches!(self.mode, EditorMode::SingleLine) {
15315            cx.propagate();
15316            return;
15317        }
15318        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15319        self.change_selections(Default::default(), window, cx, |s| {
15320            s.move_heads_with(&mut |map, head, _| {
15321                (
15322                    movement::start_of_paragraph(map, head, 1),
15323                    SelectionGoal::None,
15324                )
15325            });
15326        })
15327    }
15328
15329    pub fn select_to_end_of_paragraph(
15330        &mut self,
15331        _: &SelectToEndOfParagraph,
15332        window: &mut Window,
15333        cx: &mut Context<Self>,
15334    ) {
15335        if matches!(self.mode, EditorMode::SingleLine) {
15336            cx.propagate();
15337            return;
15338        }
15339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15340        self.change_selections(Default::default(), window, cx, |s| {
15341            s.move_heads_with(&mut |map, head, _| {
15342                (
15343                    movement::end_of_paragraph(map, head, 1),
15344                    SelectionGoal::None,
15345                )
15346            });
15347        })
15348    }
15349
15350    pub fn move_to_start_of_excerpt(
15351        &mut self,
15352        _: &MoveToStartOfExcerpt,
15353        window: &mut Window,
15354        cx: &mut Context<Self>,
15355    ) {
15356        if matches!(self.mode, EditorMode::SingleLine) {
15357            cx.propagate();
15358            return;
15359        }
15360        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15361        self.change_selections(Default::default(), window, cx, |s| {
15362            s.move_with(&mut |map, selection| {
15363                selection.collapse_to(
15364                    movement::start_of_excerpt(
15365                        map,
15366                        selection.head(),
15367                        workspace::searchable::Direction::Prev,
15368                    ),
15369                    SelectionGoal::None,
15370                )
15371            });
15372        })
15373    }
15374
15375    pub fn move_to_start_of_next_excerpt(
15376        &mut self,
15377        _: &MoveToStartOfNextExcerpt,
15378        window: &mut Window,
15379        cx: &mut Context<Self>,
15380    ) {
15381        if matches!(self.mode, EditorMode::SingleLine) {
15382            cx.propagate();
15383            return;
15384        }
15385
15386        self.change_selections(Default::default(), window, cx, |s| {
15387            s.move_with(&mut |map, selection| {
15388                selection.collapse_to(
15389                    movement::start_of_excerpt(
15390                        map,
15391                        selection.head(),
15392                        workspace::searchable::Direction::Next,
15393                    ),
15394                    SelectionGoal::None,
15395                )
15396            });
15397        })
15398    }
15399
15400    pub fn move_to_end_of_excerpt(
15401        &mut self,
15402        _: &MoveToEndOfExcerpt,
15403        window: &mut Window,
15404        cx: &mut Context<Self>,
15405    ) {
15406        if matches!(self.mode, EditorMode::SingleLine) {
15407            cx.propagate();
15408            return;
15409        }
15410        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15411        self.change_selections(Default::default(), window, cx, |s| {
15412            s.move_with(&mut |map, selection| {
15413                selection.collapse_to(
15414                    movement::end_of_excerpt(
15415                        map,
15416                        selection.head(),
15417                        workspace::searchable::Direction::Next,
15418                    ),
15419                    SelectionGoal::None,
15420                )
15421            });
15422        })
15423    }
15424
15425    pub fn move_to_end_of_previous_excerpt(
15426        &mut self,
15427        _: &MoveToEndOfPreviousExcerpt,
15428        window: &mut Window,
15429        cx: &mut Context<Self>,
15430    ) {
15431        if matches!(self.mode, EditorMode::SingleLine) {
15432            cx.propagate();
15433            return;
15434        }
15435        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15436        self.change_selections(Default::default(), window, cx, |s| {
15437            s.move_with(&mut |map, selection| {
15438                selection.collapse_to(
15439                    movement::end_of_excerpt(
15440                        map,
15441                        selection.head(),
15442                        workspace::searchable::Direction::Prev,
15443                    ),
15444                    SelectionGoal::None,
15445                )
15446            });
15447        })
15448    }
15449
15450    pub fn select_to_start_of_excerpt(
15451        &mut self,
15452        _: &SelectToStartOfExcerpt,
15453        window: &mut Window,
15454        cx: &mut Context<Self>,
15455    ) {
15456        if matches!(self.mode, EditorMode::SingleLine) {
15457            cx.propagate();
15458            return;
15459        }
15460        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15461        self.change_selections(Default::default(), window, cx, |s| {
15462            s.move_heads_with(&mut |map, head, _| {
15463                (
15464                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15465                    SelectionGoal::None,
15466                )
15467            });
15468        })
15469    }
15470
15471    pub fn select_to_start_of_next_excerpt(
15472        &mut self,
15473        _: &SelectToStartOfNextExcerpt,
15474        window: &mut Window,
15475        cx: &mut Context<Self>,
15476    ) {
15477        if matches!(self.mode, EditorMode::SingleLine) {
15478            cx.propagate();
15479            return;
15480        }
15481        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15482        self.change_selections(Default::default(), window, cx, |s| {
15483            s.move_heads_with(&mut |map, head, _| {
15484                (
15485                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15486                    SelectionGoal::None,
15487                )
15488            });
15489        })
15490    }
15491
15492    pub fn select_to_end_of_excerpt(
15493        &mut self,
15494        _: &SelectToEndOfExcerpt,
15495        window: &mut Window,
15496        cx: &mut Context<Self>,
15497    ) {
15498        if matches!(self.mode, EditorMode::SingleLine) {
15499            cx.propagate();
15500            return;
15501        }
15502        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15503        self.change_selections(Default::default(), window, cx, |s| {
15504            s.move_heads_with(&mut |map, head, _| {
15505                (
15506                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15507                    SelectionGoal::None,
15508                )
15509            });
15510        })
15511    }
15512
15513    pub fn select_to_end_of_previous_excerpt(
15514        &mut self,
15515        _: &SelectToEndOfPreviousExcerpt,
15516        window: &mut Window,
15517        cx: &mut Context<Self>,
15518    ) {
15519        if matches!(self.mode, EditorMode::SingleLine) {
15520            cx.propagate();
15521            return;
15522        }
15523        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15524        self.change_selections(Default::default(), window, cx, |s| {
15525            s.move_heads_with(&mut |map, head, _| {
15526                (
15527                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15528                    SelectionGoal::None,
15529                )
15530            });
15531        })
15532    }
15533
15534    pub fn move_to_beginning(
15535        &mut self,
15536        _: &MoveToBeginning,
15537        window: &mut Window,
15538        cx: &mut Context<Self>,
15539    ) {
15540        if matches!(self.mode, EditorMode::SingleLine) {
15541            cx.propagate();
15542            return;
15543        }
15544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15545        self.change_selections(Default::default(), window, cx, |s| {
15546            s.select_ranges(vec![Anchor::Min..Anchor::Min]);
15547        });
15548    }
15549
15550    pub fn select_to_beginning(
15551        &mut self,
15552        _: &SelectToBeginning,
15553        window: &mut Window,
15554        cx: &mut Context<Self>,
15555    ) {
15556        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15557        selection.set_head(Point::zero(), SelectionGoal::None);
15558        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15559        self.change_selections(Default::default(), window, cx, |s| {
15560            s.select(vec![selection]);
15561        });
15562    }
15563
15564    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15565        if matches!(self.mode, EditorMode::SingleLine) {
15566            cx.propagate();
15567            return;
15568        }
15569        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15570        let cursor = self.buffer.read(cx).read(cx).len();
15571        self.change_selections(Default::default(), window, cx, |s| {
15572            s.select_ranges(vec![cursor..cursor])
15573        });
15574    }
15575
15576    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15577        self.nav_history = nav_history;
15578    }
15579
15580    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15581        self.nav_history.as_ref()
15582    }
15583
15584    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15585        self.push_to_nav_history(
15586            self.selections.newest_anchor().head(),
15587            None,
15588            false,
15589            true,
15590            cx,
15591        );
15592    }
15593
15594    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15595        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15596        let buffer = self.buffer.read(cx).read(cx);
15597        let cursor_position = cursor_anchor.to_point(&buffer);
15598        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15599        let scroll_top_row = scroll_anchor.top_row(&buffer);
15600        drop(buffer);
15601
15602        NavigationData {
15603            cursor_anchor,
15604            cursor_position,
15605            scroll_anchor,
15606            scroll_top_row,
15607        }
15608    }
15609
15610    fn navigation_entry(
15611        &self,
15612        cursor_anchor: Anchor,
15613        cx: &mut Context<Self>,
15614    ) -> Option<NavigationEntry> {
15615        let Some(history) = self.nav_history.clone() else {
15616            return None;
15617        };
15618        let data = self.navigation_data(cursor_anchor, cx);
15619        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15620    }
15621
15622    fn push_to_nav_history(
15623        &mut self,
15624        cursor_anchor: Anchor,
15625        new_position: Option<Point>,
15626        is_deactivate: bool,
15627        always: bool,
15628        cx: &mut Context<Self>,
15629    ) {
15630        let data = self.navigation_data(cursor_anchor, cx);
15631        if let Some(nav_history) = self.nav_history.as_mut() {
15632            if let Some(new_position) = new_position {
15633                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15634                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15635                    return;
15636                }
15637            }
15638
15639            let cursor_row = data.cursor_position.row;
15640            nav_history.push(Some(data), Some(cursor_row), cx);
15641            cx.emit(EditorEvent::PushedToNavHistory {
15642                anchor: cursor_anchor,
15643                is_deactivate,
15644            })
15645        }
15646    }
15647
15648    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15649        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15650        let buffer = self.buffer.read(cx).snapshot(cx);
15651        let mut selection = self
15652            .selections
15653            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15654        selection.set_head(buffer.len(), SelectionGoal::None);
15655        self.change_selections(Default::default(), window, cx, |s| {
15656            s.select(vec![selection]);
15657        });
15658    }
15659
15660    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15661        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15662        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15663            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
15664        });
15665    }
15666
15667    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15668        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15669        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15670        let mut selections = self.selections.all::<Point>(&display_map);
15671        let max_point = display_map.buffer_snapshot().max_point();
15672        for selection in &mut selections {
15673            let rows = selection.spanned_rows(true, &display_map);
15674            selection.start = Point::new(rows.start.0, 0);
15675            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15676            selection.reversed = false;
15677        }
15678        self.change_selections(Default::default(), window, cx, |s| {
15679            s.select(selections);
15680        });
15681    }
15682
15683    pub fn split_selection_into_lines(
15684        &mut self,
15685        action: &SplitSelectionIntoLines,
15686        window: &mut Window,
15687        cx: &mut Context<Self>,
15688    ) {
15689        let selections = self
15690            .selections
15691            .all::<Point>(&self.display_snapshot(cx))
15692            .into_iter()
15693            .map(|selection| selection.start..selection.end)
15694            .collect::<Vec<_>>();
15695        self.unfold_ranges(&selections, true, false, cx);
15696
15697        let mut new_selection_ranges = Vec::new();
15698        {
15699            let buffer = self.buffer.read(cx).read(cx);
15700            for selection in selections {
15701                for row in selection.start.row..selection.end.row {
15702                    let line_start = Point::new(row, 0);
15703                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15704
15705                    if action.keep_selections {
15706                        // Keep the selection range for each line
15707                        let selection_start = if row == selection.start.row {
15708                            selection.start
15709                        } else {
15710                            line_start
15711                        };
15712                        new_selection_ranges.push(selection_start..line_end);
15713                    } else {
15714                        // Collapse to cursor at end of line
15715                        new_selection_ranges.push(line_end..line_end);
15716                    }
15717                }
15718
15719                let is_multiline_selection = selection.start.row != selection.end.row;
15720                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15721                // so this action feels more ergonomic when paired with other selection operations
15722                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15723                if !should_skip_last {
15724                    if action.keep_selections {
15725                        if is_multiline_selection {
15726                            let line_start = Point::new(selection.end.row, 0);
15727                            new_selection_ranges.push(line_start..selection.end);
15728                        } else {
15729                            new_selection_ranges.push(selection.start..selection.end);
15730                        }
15731                    } else {
15732                        new_selection_ranges.push(selection.end..selection.end);
15733                    }
15734                }
15735            }
15736        }
15737        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15738            s.select_ranges(new_selection_ranges);
15739        });
15740    }
15741
15742    pub fn add_selection_above(
15743        &mut self,
15744        action: &AddSelectionAbove,
15745        window: &mut Window,
15746        cx: &mut Context<Self>,
15747    ) {
15748        self.add_selection(true, action.skip_soft_wrap, window, cx);
15749    }
15750
15751    pub fn add_selection_below(
15752        &mut self,
15753        action: &AddSelectionBelow,
15754        window: &mut Window,
15755        cx: &mut Context<Self>,
15756    ) {
15757        self.add_selection(false, action.skip_soft_wrap, window, cx);
15758    }
15759
15760    fn add_selection(
15761        &mut self,
15762        above: bool,
15763        skip_soft_wrap: bool,
15764        window: &mut Window,
15765        cx: &mut Context<Self>,
15766    ) {
15767        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15768
15769        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15770        let all_selections = self.selections.all::<Point>(&display_map);
15771        let text_layout_details = self.text_layout_details(window, cx);
15772
15773        let (mut columnar_selections, new_selections_to_columnarize) = {
15774            if let Some(state) = self.add_selections_state.as_ref() {
15775                let columnar_selection_ids: HashSet<_> = state
15776                    .groups
15777                    .iter()
15778                    .flat_map(|group| group.stack.iter())
15779                    .copied()
15780                    .collect();
15781
15782                all_selections
15783                    .into_iter()
15784                    .partition(|s| columnar_selection_ids.contains(&s.id))
15785            } else {
15786                (Vec::new(), all_selections)
15787            }
15788        };
15789
15790        let mut state = self
15791            .add_selections_state
15792            .take()
15793            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15794
15795        for selection in new_selections_to_columnarize {
15796            let range = selection.display_range(&display_map).sorted();
15797            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15798            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15799            let positions = start_x.min(end_x)..start_x.max(end_x);
15800            let mut stack = Vec::new();
15801            for row in range.start.row().0..=range.end.row().0 {
15802                if let Some(selection) = self.selections.build_columnar_selection(
15803                    &display_map,
15804                    DisplayRow(row),
15805                    &positions,
15806                    selection.reversed,
15807                    &text_layout_details,
15808                ) {
15809                    stack.push(selection.id);
15810                    columnar_selections.push(selection);
15811                }
15812            }
15813            if !stack.is_empty() {
15814                if above {
15815                    stack.reverse();
15816                }
15817                state.groups.push(AddSelectionsGroup { above, stack });
15818            }
15819        }
15820
15821        let mut final_selections = Vec::new();
15822        let end_row = if above {
15823            DisplayRow(0)
15824        } else {
15825            display_map.max_point().row()
15826        };
15827
15828        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15829        // positions to place new selections, so we need to keep track of the
15830        // column range of the oldest selection in each group, because
15831        // intermediate selections may have been clamped to shorter lines.
15832        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15833            let mut map = HashMap::default();
15834            for group in state.groups.iter() {
15835                if let Some(oldest_id) = group.stack.first() {
15836                    if let Some(oldest_selection) =
15837                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15838                    {
15839                        let snapshot = display_map.buffer_snapshot();
15840                        let start_col =
15841                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15842                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15843                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15844                        for id in &group.stack {
15845                            map.insert(*id, goal_columns.clone());
15846                        }
15847                    }
15848                }
15849            }
15850            map
15851        } else {
15852            HashMap::default()
15853        };
15854
15855        let mut last_added_item_per_group = HashMap::default();
15856        for group in state.groups.iter_mut() {
15857            if let Some(last_id) = group.stack.last() {
15858                last_added_item_per_group.insert(*last_id, group);
15859            }
15860        }
15861
15862        for selection in columnar_selections {
15863            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15864                if above == group.above {
15865                    let range = selection.display_range(&display_map).sorted();
15866                    debug_assert_eq!(range.start.row(), range.end.row());
15867                    let row = range.start.row();
15868                    let positions =
15869                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15870                            Pixels::from(start)..Pixels::from(end)
15871                        } else {
15872                            let start_x =
15873                                display_map.x_for_display_point(range.start, &text_layout_details);
15874                            let end_x =
15875                                display_map.x_for_display_point(range.end, &text_layout_details);
15876                            start_x.min(end_x)..start_x.max(end_x)
15877                        };
15878
15879                    let maybe_new_selection = if skip_soft_wrap {
15880                        let goal_columns = goal_columns_by_selection_id
15881                            .remove(&selection.id)
15882                            .unwrap_or_else(|| {
15883                                let snapshot = display_map.buffer_snapshot();
15884                                let start_col =
15885                                    snapshot.point_to_point_utf16(selection.start).column;
15886                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15887                                start_col.min(end_col)..start_col.max(end_col)
15888                            });
15889                        self.selections.find_next_columnar_selection_by_buffer_row(
15890                            &display_map,
15891                            row,
15892                            end_row,
15893                            above,
15894                            &goal_columns,
15895                            selection.reversed,
15896                            &text_layout_details,
15897                        )
15898                    } else {
15899                        self.selections.find_next_columnar_selection_by_display_row(
15900                            &display_map,
15901                            row,
15902                            end_row,
15903                            above,
15904                            &positions,
15905                            selection.reversed,
15906                            &text_layout_details,
15907                        )
15908                    };
15909
15910                    if let Some(new_selection) = maybe_new_selection {
15911                        group.stack.push(new_selection.id);
15912                        if above {
15913                            final_selections.push(new_selection);
15914                            final_selections.push(selection);
15915                        } else {
15916                            final_selections.push(selection);
15917                            final_selections.push(new_selection);
15918                        }
15919                    } else {
15920                        final_selections.push(selection);
15921                    }
15922                } else {
15923                    group.stack.pop();
15924                }
15925            } else {
15926                final_selections.push(selection);
15927            }
15928        }
15929
15930        self.change_selections(Default::default(), window, cx, |s| {
15931            s.select(final_selections);
15932        });
15933
15934        let final_selection_ids: HashSet<_> = self
15935            .selections
15936            .all::<Point>(&display_map)
15937            .iter()
15938            .map(|s| s.id)
15939            .collect();
15940        state.groups.retain_mut(|group| {
15941            // selections might get merged above so we remove invalid items from stacks
15942            group.stack.retain(|id| final_selection_ids.contains(id));
15943
15944            // single selection in stack can be treated as initial state
15945            group.stack.len() > 1
15946        });
15947
15948        if !state.groups.is_empty() {
15949            self.add_selections_state = Some(state);
15950        }
15951    }
15952
15953    pub fn insert_snippet_at_selections(
15954        &mut self,
15955        action: &InsertSnippet,
15956        window: &mut Window,
15957        cx: &mut Context<Self>,
15958    ) {
15959        self.try_insert_snippet_at_selections(action, window, cx)
15960            .log_err();
15961    }
15962
15963    fn try_insert_snippet_at_selections(
15964        &mut self,
15965        action: &InsertSnippet,
15966        window: &mut Window,
15967        cx: &mut Context<Self>,
15968    ) -> Result<()> {
15969        let insertion_ranges = self
15970            .selections
15971            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15972            .into_iter()
15973            .map(|selection| selection.range())
15974            .collect_vec();
15975
15976        let snippet = if let Some(snippet_body) = &action.snippet {
15977            if action.language.is_none() && action.name.is_none() {
15978                Snippet::parse(snippet_body)?
15979            } else {
15980                bail!("`snippet` is mutually exclusive with `language` and `name`")
15981            }
15982        } else if let Some(name) = &action.name {
15983            let project = self.project().context("no project")?;
15984            let snippet_store = project.read(cx).snippets().read(cx);
15985            let snippet = snippet_store
15986                .snippets_for(action.language.clone(), cx)
15987                .into_iter()
15988                .find(|snippet| snippet.name == *name)
15989                .context("snippet not found")?;
15990            Snippet::parse(&snippet.body)?
15991        } else {
15992            // todo(andrew): open modal to select snippet
15993            bail!("`name` or `snippet` is required")
15994        };
15995
15996        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15997    }
15998
15999    fn select_match_ranges(
16000        &mut self,
16001        range: Range<MultiBufferOffset>,
16002        reversed: bool,
16003        replace_newest: bool,
16004        auto_scroll: Option<Autoscroll>,
16005        window: &mut Window,
16006        cx: &mut Context<Editor>,
16007    ) {
16008        self.unfold_ranges(
16009            std::slice::from_ref(&range),
16010            false,
16011            auto_scroll.is_some(),
16012            cx,
16013        );
16014        let effects = if let Some(scroll) = auto_scroll {
16015            SelectionEffects::scroll(scroll)
16016        } else {
16017            SelectionEffects::no_scroll()
16018        };
16019        self.change_selections(effects, window, cx, |s| {
16020            if replace_newest {
16021                s.delete(s.newest_anchor().id);
16022            }
16023            if reversed {
16024                s.insert_range(range.end..range.start);
16025            } else {
16026                s.insert_range(range);
16027            }
16028        });
16029    }
16030
16031    pub fn select_next_match_internal(
16032        &mut self,
16033        display_map: &DisplaySnapshot,
16034        replace_newest: bool,
16035        autoscroll: Option<Autoscroll>,
16036        window: &mut Window,
16037        cx: &mut Context<Self>,
16038    ) -> Result<()> {
16039        let buffer = display_map.buffer_snapshot();
16040        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16041        if let Some(mut select_next_state) = self.select_next_state.take() {
16042            let query = &select_next_state.query;
16043            if !select_next_state.done {
16044                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16045                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16046                let mut next_selected_range = None;
16047
16048                let bytes_after_last_selection =
16049                    buffer.bytes_in_range(last_selection.end..buffer.len());
16050                let bytes_before_first_selection =
16051                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
16052                let query_matches = query
16053                    .stream_find_iter(bytes_after_last_selection)
16054                    .map(|result| (last_selection.end, result))
16055                    .chain(
16056                        query
16057                            .stream_find_iter(bytes_before_first_selection)
16058                            .map(|result| (MultiBufferOffset(0), result)),
16059                    );
16060
16061                for (start_offset, query_match) in query_matches {
16062                    let query_match = query_match.unwrap(); // can only fail due to I/O
16063                    let offset_range =
16064                        start_offset + query_match.start()..start_offset + query_match.end();
16065
16066                    if !select_next_state.wordwise
16067                        || (!buffer.is_inside_word(offset_range.start, None)
16068                            && !buffer.is_inside_word(offset_range.end, None))
16069                    {
16070                        let idx = selections
16071                            .partition_point(|selection| selection.end <= offset_range.start);
16072                        let overlaps = selections
16073                            .get(idx)
16074                            .map_or(false, |selection| selection.start < offset_range.end);
16075
16076                        if !overlaps {
16077                            next_selected_range = Some(offset_range);
16078                            break;
16079                        }
16080                    }
16081                }
16082
16083                if let Some(next_selected_range) = next_selected_range {
16084                    self.select_match_ranges(
16085                        next_selected_range,
16086                        last_selection.reversed,
16087                        replace_newest,
16088                        autoscroll,
16089                        window,
16090                        cx,
16091                    );
16092                } else {
16093                    select_next_state.done = true;
16094                }
16095            }
16096
16097            self.select_next_state = Some(select_next_state);
16098        } else {
16099            let mut only_carets = true;
16100            let mut same_text_selected = true;
16101            let mut selected_text = None;
16102
16103            let mut selections_iter = selections.iter().peekable();
16104            while let Some(selection) = selections_iter.next() {
16105                if selection.start != selection.end {
16106                    only_carets = false;
16107                }
16108
16109                if same_text_selected {
16110                    if selected_text.is_none() {
16111                        selected_text =
16112                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16113                    }
16114
16115                    if let Some(next_selection) = selections_iter.peek() {
16116                        if next_selection.len() == selection.len() {
16117                            let next_selected_text = buffer
16118                                .text_for_range(next_selection.range())
16119                                .collect::<String>();
16120                            if Some(next_selected_text) != selected_text {
16121                                same_text_selected = false;
16122                                selected_text = None;
16123                            }
16124                        } else {
16125                            same_text_selected = false;
16126                            selected_text = None;
16127                        }
16128                    }
16129                }
16130            }
16131
16132            if only_carets {
16133                for selection in &mut selections {
16134                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16135                    selection.start = word_range.start;
16136                    selection.end = word_range.end;
16137                    selection.goal = SelectionGoal::None;
16138                    selection.reversed = false;
16139                    self.select_match_ranges(
16140                        selection.start..selection.end,
16141                        selection.reversed,
16142                        replace_newest,
16143                        autoscroll,
16144                        window,
16145                        cx,
16146                    );
16147                }
16148
16149                if selections.len() == 1 {
16150                    let selection = selections
16151                        .last()
16152                        .expect("ensured that there's only one selection");
16153                    let query = buffer
16154                        .text_for_range(selection.start..selection.end)
16155                        .collect::<String>();
16156                    let is_empty = query.is_empty();
16157                    let select_state = SelectNextState {
16158                        query: self.build_query(&[query], cx)?,
16159                        wordwise: true,
16160                        done: is_empty,
16161                    };
16162                    self.select_next_state = Some(select_state);
16163                } else {
16164                    self.select_next_state = None;
16165                }
16166            } else if let Some(selected_text) = selected_text {
16167                self.select_next_state = Some(SelectNextState {
16168                    query: self.build_query(&[selected_text], cx)?,
16169                    wordwise: false,
16170                    done: false,
16171                });
16172                self.select_next_match_internal(
16173                    display_map,
16174                    replace_newest,
16175                    autoscroll,
16176                    window,
16177                    cx,
16178                )?;
16179            }
16180        }
16181        Ok(())
16182    }
16183
16184    pub fn select_all_matches(
16185        &mut self,
16186        _action: &SelectAllMatches,
16187        window: &mut Window,
16188        cx: &mut Context<Self>,
16189    ) -> Result<()> {
16190        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16191
16192        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16193
16194        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16195        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16196        else {
16197            return Ok(());
16198        };
16199
16200        let mut new_selections = Vec::new();
16201        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
16202        let reversed = initial_selection.reversed;
16203        let buffer = display_map.buffer_snapshot();
16204        let query_matches = select_next_state
16205            .query
16206            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16207
16208        for query_match in query_matches.into_iter() {
16209            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16210            let offset_range = if reversed {
16211                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16212            } else {
16213                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16214            };
16215
16216            let is_partial_word_match = select_next_state.wordwise
16217                && (buffer.is_inside_word(offset_range.start, None)
16218                    || buffer.is_inside_word(offset_range.end, None));
16219
16220            let is_initial_selection = MultiBufferOffset(query_match.start())
16221                == initial_selection.start
16222                && MultiBufferOffset(query_match.end()) == initial_selection.end;
16223
16224            if !is_partial_word_match && !is_initial_selection {
16225                new_selections.push(offset_range);
16226            }
16227        }
16228
16229        // Ensure that the initial range is the last selection, as
16230        // `MutableSelectionsCollection::select_ranges` makes the last selection
16231        // the newest selection, which the editor then relies on as the primary
16232        // cursor for scroll targeting. Without this, the last match would then
16233        // be automatically focused when the user started editing the selected
16234        // matches.
16235        let initial_directed_range = if reversed {
16236            initial_selection.end..initial_selection.start
16237        } else {
16238            initial_selection.start..initial_selection.end
16239        };
16240        new_selections.push(initial_directed_range);
16241
16242        select_next_state.done = true;
16243        self.unfold_ranges(&new_selections, false, false, cx);
16244        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16245            selections.select_ranges(new_selections)
16246        });
16247
16248        Ok(())
16249    }
16250
16251    pub fn select_next(
16252        &mut self,
16253        action: &SelectNext,
16254        window: &mut Window,
16255        cx: &mut Context<Self>,
16256    ) -> Result<()> {
16257        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16258        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16259        self.select_next_match_internal(
16260            &display_map,
16261            action.replace_newest,
16262            Some(Autoscroll::newest()),
16263            window,
16264            cx,
16265        )
16266    }
16267
16268    pub fn select_previous(
16269        &mut self,
16270        action: &SelectPrevious,
16271        window: &mut Window,
16272        cx: &mut Context<Self>,
16273    ) -> Result<()> {
16274        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16275        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16276        let buffer = display_map.buffer_snapshot();
16277        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16278        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16279            let query = &select_prev_state.query;
16280            if !select_prev_state.done {
16281                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16282                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16283                let mut next_selected_range = None;
16284                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16285                let bytes_before_last_selection =
16286                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16287                let bytes_after_first_selection =
16288                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16289                let query_matches = query
16290                    .stream_find_iter(bytes_before_last_selection)
16291                    .map(|result| (last_selection.start, result))
16292                    .chain(
16293                        query
16294                            .stream_find_iter(bytes_after_first_selection)
16295                            .map(|result| (buffer.len(), result)),
16296                    );
16297                for (end_offset, query_match) in query_matches {
16298                    let query_match = query_match.unwrap(); // can only fail due to I/O
16299                    let offset_range =
16300                        end_offset - query_match.end()..end_offset - query_match.start();
16301
16302                    if !select_prev_state.wordwise
16303                        || (!buffer.is_inside_word(offset_range.start, None)
16304                            && !buffer.is_inside_word(offset_range.end, None))
16305                    {
16306                        next_selected_range = Some(offset_range);
16307                        break;
16308                    }
16309                }
16310
16311                if let Some(next_selected_range) = next_selected_range {
16312                    self.select_match_ranges(
16313                        next_selected_range,
16314                        last_selection.reversed,
16315                        action.replace_newest,
16316                        Some(Autoscroll::newest()),
16317                        window,
16318                        cx,
16319                    );
16320                } else {
16321                    select_prev_state.done = true;
16322                }
16323            }
16324
16325            self.select_prev_state = Some(select_prev_state);
16326        } else {
16327            let mut only_carets = true;
16328            let mut same_text_selected = true;
16329            let mut selected_text = None;
16330
16331            let mut selections_iter = selections.iter().peekable();
16332            while let Some(selection) = selections_iter.next() {
16333                if selection.start != selection.end {
16334                    only_carets = false;
16335                }
16336
16337                if same_text_selected {
16338                    if selected_text.is_none() {
16339                        selected_text =
16340                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16341                    }
16342
16343                    if let Some(next_selection) = selections_iter.peek() {
16344                        if next_selection.len() == selection.len() {
16345                            let next_selected_text = buffer
16346                                .text_for_range(next_selection.range())
16347                                .collect::<String>();
16348                            if Some(next_selected_text) != selected_text {
16349                                same_text_selected = false;
16350                                selected_text = None;
16351                            }
16352                        } else {
16353                            same_text_selected = false;
16354                            selected_text = None;
16355                        }
16356                    }
16357                }
16358            }
16359
16360            if only_carets {
16361                for selection in &mut selections {
16362                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16363                    selection.start = word_range.start;
16364                    selection.end = word_range.end;
16365                    selection.goal = SelectionGoal::None;
16366                    selection.reversed = false;
16367                    self.select_match_ranges(
16368                        selection.start..selection.end,
16369                        selection.reversed,
16370                        action.replace_newest,
16371                        Some(Autoscroll::newest()),
16372                        window,
16373                        cx,
16374                    );
16375                }
16376                if selections.len() == 1 {
16377                    let selection = selections
16378                        .last()
16379                        .expect("ensured that there's only one selection");
16380                    let query = buffer
16381                        .text_for_range(selection.start..selection.end)
16382                        .collect::<String>();
16383                    let is_empty = query.is_empty();
16384                    let select_state = SelectNextState {
16385                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16386                        wordwise: true,
16387                        done: is_empty,
16388                    };
16389                    self.select_prev_state = Some(select_state);
16390                } else {
16391                    self.select_prev_state = None;
16392                }
16393            } else if let Some(selected_text) = selected_text {
16394                self.select_prev_state = Some(SelectNextState {
16395                    query: self
16396                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16397                    wordwise: false,
16398                    done: false,
16399                });
16400                self.select_previous(action, window, cx)?;
16401            }
16402        }
16403        Ok(())
16404    }
16405
16406    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16407    /// setting the case sensitivity based on the global
16408    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16409    /// editor's settings.
16410    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16411    where
16412        I: IntoIterator<Item = P>,
16413        P: AsRef<[u8]>,
16414    {
16415        let case_sensitive = self
16416            .select_next_is_case_sensitive
16417            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16418
16419        let mut builder = AhoCorasickBuilder::new();
16420        builder.ascii_case_insensitive(!case_sensitive);
16421        builder.build(patterns)
16422    }
16423
16424    pub fn find_next_match(
16425        &mut self,
16426        _: &FindNextMatch,
16427        window: &mut Window,
16428        cx: &mut Context<Self>,
16429    ) -> Result<()> {
16430        let selections = self.selections.disjoint_anchors_arc();
16431        match selections.first() {
16432            Some(first) if selections.len() >= 2 => {
16433                self.change_selections(Default::default(), window, cx, |s| {
16434                    s.select_ranges([first.range()]);
16435                });
16436            }
16437            _ => self.select_next(
16438                &SelectNext {
16439                    replace_newest: true,
16440                },
16441                window,
16442                cx,
16443            )?,
16444        }
16445        Ok(())
16446    }
16447
16448    pub fn find_previous_match(
16449        &mut self,
16450        _: &FindPreviousMatch,
16451        window: &mut Window,
16452        cx: &mut Context<Self>,
16453    ) -> Result<()> {
16454        let selections = self.selections.disjoint_anchors_arc();
16455        match selections.last() {
16456            Some(last) if selections.len() >= 2 => {
16457                self.change_selections(Default::default(), window, cx, |s| {
16458                    s.select_ranges([last.range()]);
16459                });
16460            }
16461            _ => self.select_previous(
16462                &SelectPrevious {
16463                    replace_newest: true,
16464                },
16465                window,
16466                cx,
16467            )?,
16468        }
16469        Ok(())
16470    }
16471
16472    pub fn toggle_block_comments(
16473        &mut self,
16474        _: &ToggleBlockComments,
16475        window: &mut Window,
16476        cx: &mut Context<Self>,
16477    ) {
16478        if self.read_only(cx) {
16479            return;
16480        }
16481        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16482        self.transact(window, cx, |this, _window, cx| {
16483            let mut selections = this
16484                .selections
16485                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16486            let mut edits = Vec::new();
16487            let snapshot = this.buffer.read(cx).read(cx);
16488            let empty_str: Arc<str> = Arc::default();
16489            let mut markers_inserted = Vec::new();
16490
16491            for selection in &mut selections {
16492                let start_point = selection.start;
16493                let end_point = selection.end;
16494
16495                let Some(language) =
16496                    snapshot.language_scope_at(Point::new(start_point.row, start_point.column))
16497                else {
16498                    continue;
16499                };
16500
16501                let Some(BlockCommentConfig {
16502                    start: comment_start,
16503                    end: comment_end,
16504                    ..
16505                }) = language.block_comment()
16506                else {
16507                    continue;
16508                };
16509
16510                let prefix_needle = comment_start.trim_end().as_bytes();
16511                let suffix_needle = comment_end.trim_start().as_bytes();
16512
16513                // Collect full lines spanning the selection as the search region
16514                let region_start = Point::new(start_point.row, 0);
16515                let region_end = Point::new(
16516                    end_point.row,
16517                    snapshot.line_len(MultiBufferRow(end_point.row)),
16518                );
16519                let region_bytes: Vec<u8> = snapshot
16520                    .bytes_in_range(region_start..region_end)
16521                    .flatten()
16522                    .copied()
16523                    .collect();
16524
16525                let region_start_offset = snapshot.point_to_offset(region_start);
16526                let start_byte = snapshot.point_to_offset(start_point) - region_start_offset;
16527                let end_byte = snapshot.point_to_offset(end_point) - region_start_offset;
16528
16529                let mut is_commented = false;
16530                let mut prefix_range = start_point..start_point;
16531                let mut suffix_range = end_point..end_point;
16532
16533                // Find rightmost /* at or before the selection end
16534                if let Some(prefix_pos) = region_bytes[..end_byte.min(region_bytes.len())]
16535                    .windows(prefix_needle.len())
16536                    .rposition(|w| w == prefix_needle)
16537                {
16538                    let after_prefix = prefix_pos + prefix_needle.len();
16539
16540                    // Find the first */ after that /*
16541                    if let Some(suffix_pos) = region_bytes[after_prefix..]
16542                        .windows(suffix_needle.len())
16543                        .position(|w| w == suffix_needle)
16544                        .map(|p| p + after_prefix)
16545                    {
16546                        let suffix_end = suffix_pos + suffix_needle.len();
16547
16548                        // Case 1: /* ... */ surrounds the selection
16549                        let markers_surround = prefix_pos <= start_byte
16550                            && suffix_end >= end_byte
16551                            && start_byte < suffix_end;
16552
16553                        // Case 2: selection contains /* ... */ (only whitespace padding)
16554                        let selection_contains = start_byte <= prefix_pos
16555                            && suffix_end <= end_byte
16556                            && region_bytes[start_byte..prefix_pos]
16557                                .iter()
16558                                .all(|&b| b.is_ascii_whitespace())
16559                            && region_bytes[suffix_end..end_byte]
16560                                .iter()
16561                                .all(|&b| b.is_ascii_whitespace());
16562
16563                        if markers_surround || selection_contains {
16564                            is_commented = true;
16565                            let prefix_pt =
16566                                snapshot.offset_to_point(region_start_offset + prefix_pos);
16567                            let suffix_pt =
16568                                snapshot.offset_to_point(region_start_offset + suffix_pos);
16569                            prefix_range = prefix_pt
16570                                ..Point::new(
16571                                    prefix_pt.row,
16572                                    prefix_pt.column + prefix_needle.len() as u32,
16573                                );
16574                            suffix_range = suffix_pt
16575                                ..Point::new(
16576                                    suffix_pt.row,
16577                                    suffix_pt.column + suffix_needle.len() as u32,
16578                                );
16579                        }
16580                    }
16581                }
16582
16583                if is_commented {
16584                    // Also remove the space after /* and before */
16585                    if snapshot
16586                        .bytes_in_range(prefix_range.end..snapshot.max_point())
16587                        .flatten()
16588                        .next()
16589                        == Some(&b' ')
16590                    {
16591                        prefix_range.end.column += 1;
16592                    }
16593                    if suffix_range.start.column > 0 {
16594                        let before =
16595                            Point::new(suffix_range.start.row, suffix_range.start.column - 1);
16596                        if snapshot
16597                            .bytes_in_range(before..suffix_range.start)
16598                            .flatten()
16599                            .next()
16600                            == Some(&b' ')
16601                        {
16602                            suffix_range.start.column -= 1;
16603                        }
16604                    }
16605
16606                    edits.push((prefix_range, empty_str.clone()));
16607                    edits.push((suffix_range, empty_str.clone()));
16608                } else {
16609                    let prefix: Arc<str> = if comment_start.ends_with(' ') {
16610                        comment_start.clone()
16611                    } else {
16612                        format!("{} ", comment_start).into()
16613                    };
16614                    let suffix: Arc<str> = if comment_end.starts_with(' ') {
16615                        comment_end.clone()
16616                    } else {
16617                        format!(" {}", comment_end).into()
16618                    };
16619
16620                    edits.push((start_point..start_point, prefix.clone()));
16621                    edits.push((end_point..end_point, suffix.clone()));
16622                    markers_inserted.push((
16623                        selection.id,
16624                        prefix.len(),
16625                        suffix.len(),
16626                        selection.is_empty(),
16627                        end_point.row,
16628                    ));
16629                }
16630            }
16631
16632            drop(snapshot);
16633            this.buffer.update(cx, |buffer, cx| {
16634                buffer.edit(edits, None, cx);
16635            });
16636
16637            let mut selections = this
16638                .selections
16639                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16640            for selection in &mut selections {
16641                if let Some((_, prefix_len, suffix_len, was_empty, suffix_row)) = markers_inserted
16642                    .iter()
16643                    .find(|(id, _, _, _, _)| *id == selection.id)
16644                {
16645                    if *was_empty {
16646                        selection.start.column = selection
16647                            .start
16648                            .column
16649                            .saturating_sub((*prefix_len + *suffix_len) as u32);
16650                    } else {
16651                        selection.start.column =
16652                            selection.start.column.saturating_sub(*prefix_len as u32);
16653                        if selection.end.row == *suffix_row {
16654                            selection.end.column += *suffix_len as u32;
16655                        }
16656                    }
16657                }
16658            }
16659            this.change_selections(Default::default(), _window, cx, |s| s.select(selections));
16660        });
16661    }
16662
16663    pub fn toggle_comments(
16664        &mut self,
16665        action: &ToggleComments,
16666        window: &mut Window,
16667        cx: &mut Context<Self>,
16668    ) {
16669        if self.read_only(cx) {
16670            return;
16671        }
16672        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16673        let text_layout_details = &self.text_layout_details(window, cx);
16674        self.transact(window, cx, |this, window, cx| {
16675            let mut selections = this
16676                .selections
16677                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16678            let mut edits = Vec::new();
16679            let mut selection_edit_ranges = Vec::new();
16680            let mut last_toggled_row = None;
16681            let snapshot = this.buffer.read(cx).read(cx);
16682            let empty_str: Arc<str> = Arc::default();
16683            let mut suffixes_inserted = Vec::new();
16684            let ignore_indent = action.ignore_indent;
16685
16686            fn comment_prefix_range(
16687                snapshot: &MultiBufferSnapshot,
16688                row: MultiBufferRow,
16689                comment_prefix: &str,
16690                comment_prefix_whitespace: &str,
16691                ignore_indent: bool,
16692            ) -> Range<Point> {
16693                let indent_size = if ignore_indent {
16694                    0
16695                } else {
16696                    snapshot.indent_size_for_line(row).len
16697                };
16698
16699                let start = Point::new(row.0, indent_size);
16700
16701                let mut line_bytes = snapshot
16702                    .bytes_in_range(start..snapshot.max_point())
16703                    .flatten()
16704                    .copied();
16705
16706                // If this line currently begins with the line comment prefix, then record
16707                // the range containing the prefix.
16708                if line_bytes
16709                    .by_ref()
16710                    .take(comment_prefix.len())
16711                    .eq(comment_prefix.bytes())
16712                {
16713                    // Include any whitespace that matches the comment prefix.
16714                    let matching_whitespace_len = line_bytes
16715                        .zip(comment_prefix_whitespace.bytes())
16716                        .take_while(|(a, b)| a == b)
16717                        .count() as u32;
16718                    let end = Point::new(
16719                        start.row,
16720                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16721                    );
16722                    start..end
16723                } else {
16724                    start..start
16725                }
16726            }
16727
16728            fn comment_suffix_range(
16729                snapshot: &MultiBufferSnapshot,
16730                row: MultiBufferRow,
16731                comment_suffix: &str,
16732                comment_suffix_has_leading_space: bool,
16733            ) -> Range<Point> {
16734                let end = Point::new(row.0, snapshot.line_len(row));
16735                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16736
16737                let mut line_end_bytes = snapshot
16738                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16739                    .flatten()
16740                    .copied();
16741
16742                let leading_space_len = if suffix_start_column > 0
16743                    && line_end_bytes.next() == Some(b' ')
16744                    && comment_suffix_has_leading_space
16745                {
16746                    1
16747                } else {
16748                    0
16749                };
16750
16751                // If this line currently begins with the line comment prefix, then record
16752                // the range containing the prefix.
16753                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16754                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16755                    start..end
16756                } else {
16757                    end..end
16758                }
16759            }
16760
16761            // TODO: Handle selections that cross excerpts
16762            for selection in &mut selections {
16763                let start_column = snapshot
16764                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16765                    .len;
16766                let language = if let Some(language) =
16767                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16768                {
16769                    language
16770                } else {
16771                    continue;
16772                };
16773
16774                selection_edit_ranges.clear();
16775
16776                // If multiple selections contain a given row, avoid processing that
16777                // row more than once.
16778                let mut start_row = MultiBufferRow(selection.start.row);
16779                if last_toggled_row == Some(start_row) {
16780                    start_row = start_row.next_row();
16781                }
16782                let end_row =
16783                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16784                        MultiBufferRow(selection.end.row - 1)
16785                    } else {
16786                        MultiBufferRow(selection.end.row)
16787                    };
16788                last_toggled_row = Some(end_row);
16789
16790                if start_row > end_row {
16791                    continue;
16792                }
16793
16794                // If the language has line comments, toggle those.
16795                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16796
16797                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16798                if ignore_indent {
16799                    full_comment_prefixes = full_comment_prefixes
16800                        .into_iter()
16801                        .map(|s| Arc::from(s.trim_end()))
16802                        .collect();
16803                }
16804
16805                if !full_comment_prefixes.is_empty() {
16806                    let first_prefix = full_comment_prefixes
16807                        .first()
16808                        .expect("prefixes is non-empty");
16809                    let prefix_trimmed_lengths = full_comment_prefixes
16810                        .iter()
16811                        .map(|p| p.trim_end_matches(' ').len())
16812                        .collect::<SmallVec<[usize; 4]>>();
16813
16814                    let mut all_selection_lines_are_comments = true;
16815
16816                    for row in start_row.0..=end_row.0 {
16817                        let row = MultiBufferRow(row);
16818                        if start_row < end_row && snapshot.is_line_blank(row) {
16819                            continue;
16820                        }
16821
16822                        let prefix_range = full_comment_prefixes
16823                            .iter()
16824                            .zip(prefix_trimmed_lengths.iter().copied())
16825                            .map(|(prefix, trimmed_prefix_len)| {
16826                                comment_prefix_range(
16827                                    snapshot.deref(),
16828                                    row,
16829                                    &prefix[..trimmed_prefix_len],
16830                                    &prefix[trimmed_prefix_len..],
16831                                    ignore_indent,
16832                                )
16833                            })
16834                            .max_by_key(|range| range.end.column - range.start.column)
16835                            .expect("prefixes is non-empty");
16836
16837                        if prefix_range.is_empty() {
16838                            all_selection_lines_are_comments = false;
16839                        }
16840
16841                        selection_edit_ranges.push(prefix_range);
16842                    }
16843
16844                    if all_selection_lines_are_comments {
16845                        edits.extend(
16846                            selection_edit_ranges
16847                                .iter()
16848                                .cloned()
16849                                .map(|range| (range, empty_str.clone())),
16850                        );
16851                    } else {
16852                        let min_column = selection_edit_ranges
16853                            .iter()
16854                            .map(|range| range.start.column)
16855                            .min()
16856                            .unwrap_or(0);
16857                        edits.extend(selection_edit_ranges.iter().map(|range| {
16858                            let position = Point::new(range.start.row, min_column);
16859                            (position..position, first_prefix.clone())
16860                        }));
16861                    }
16862                } else if let Some(BlockCommentConfig {
16863                    start: full_comment_prefix,
16864                    end: comment_suffix,
16865                    ..
16866                }) = language.block_comment()
16867                {
16868                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16869                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16870                    let prefix_range = comment_prefix_range(
16871                        snapshot.deref(),
16872                        start_row,
16873                        comment_prefix,
16874                        comment_prefix_whitespace,
16875                        ignore_indent,
16876                    );
16877                    let suffix_range = comment_suffix_range(
16878                        snapshot.deref(),
16879                        end_row,
16880                        comment_suffix.trim_start_matches(' '),
16881                        comment_suffix.starts_with(' '),
16882                    );
16883
16884                    if prefix_range.is_empty() || suffix_range.is_empty() {
16885                        edits.push((
16886                            prefix_range.start..prefix_range.start,
16887                            full_comment_prefix.clone(),
16888                        ));
16889                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16890                        suffixes_inserted.push((end_row, comment_suffix.len()));
16891                    } else {
16892                        edits.push((prefix_range, empty_str.clone()));
16893                        edits.push((suffix_range, empty_str.clone()));
16894                    }
16895                } else {
16896                    continue;
16897                }
16898            }
16899
16900            drop(snapshot);
16901            this.buffer.update(cx, |buffer, cx| {
16902                buffer.edit(edits, None, cx);
16903            });
16904
16905            // Adjust selections so that they end before any comment suffixes that
16906            // were inserted.
16907            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16908            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16909            let snapshot = this.buffer.read(cx).read(cx);
16910            for selection in &mut selections {
16911                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16912                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16913                        Ordering::Less => {
16914                            suffixes_inserted.next();
16915                            continue;
16916                        }
16917                        Ordering::Greater => break,
16918                        Ordering::Equal => {
16919                            if selection.end.column == snapshot.line_len(row) {
16920                                if selection.is_empty() {
16921                                    selection.start.column -= suffix_len as u32;
16922                                }
16923                                selection.end.column -= suffix_len as u32;
16924                            }
16925                            break;
16926                        }
16927                    }
16928                }
16929            }
16930
16931            drop(snapshot);
16932            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16933
16934            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16935            let selections_on_single_row = selections.windows(2).all(|selections| {
16936                selections[0].start.row == selections[1].start.row
16937                    && selections[0].end.row == selections[1].end.row
16938                    && selections[0].start.row == selections[0].end.row
16939            });
16940            let selections_selecting = selections
16941                .iter()
16942                .any(|selection| selection.start != selection.end);
16943            let advance_downwards = action.advance_downwards
16944                && selections_on_single_row
16945                && !selections_selecting
16946                && !matches!(this.mode, EditorMode::SingleLine);
16947
16948            if advance_downwards {
16949                let snapshot = this.buffer.read(cx).snapshot(cx);
16950
16951                this.change_selections(Default::default(), window, cx, |s| {
16952                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16953                        let mut point = display_point.to_point(display_snapshot);
16954                        point.row += 1;
16955                        point = snapshot.clip_point(point, Bias::Left);
16956                        let display_point = point.to_display_point(display_snapshot);
16957                        let goal = SelectionGoal::HorizontalPosition(
16958                            display_snapshot
16959                                .x_for_display_point(display_point, text_layout_details)
16960                                .into(),
16961                        );
16962                        (display_point, goal)
16963                    })
16964                });
16965            }
16966        });
16967    }
16968
16969    pub fn select_enclosing_symbol(
16970        &mut self,
16971        _: &SelectEnclosingSymbol,
16972        window: &mut Window,
16973        cx: &mut Context<Self>,
16974    ) {
16975        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16976
16977        let buffer = self.buffer.read(cx).snapshot(cx);
16978        let old_selections = self
16979            .selections
16980            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16981            .into_boxed_slice();
16982
16983        fn update_selection(
16984            selection: &Selection<MultiBufferOffset>,
16985            buffer_snap: &MultiBufferSnapshot,
16986        ) -> Option<Selection<MultiBufferOffset>> {
16987            let cursor = selection.head();
16988            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16989            for symbol in symbols.iter().rev() {
16990                let start = symbol.range.start.to_offset(buffer_snap);
16991                let end = symbol.range.end.to_offset(buffer_snap);
16992                let new_range = start..end;
16993                if start < selection.start || end > selection.end {
16994                    return Some(Selection {
16995                        id: selection.id,
16996                        start: new_range.start,
16997                        end: new_range.end,
16998                        goal: SelectionGoal::None,
16999                        reversed: selection.reversed,
17000                    });
17001                }
17002            }
17003            None
17004        }
17005
17006        let mut selected_larger_symbol = false;
17007        let new_selections = old_selections
17008            .iter()
17009            .map(|selection| match update_selection(selection, &buffer) {
17010                Some(new_selection) => {
17011                    if new_selection.range() != selection.range() {
17012                        selected_larger_symbol = true;
17013                    }
17014                    new_selection
17015                }
17016                None => selection.clone(),
17017            })
17018            .collect::<Vec<_>>();
17019
17020        if selected_larger_symbol {
17021            self.change_selections(Default::default(), window, cx, |s| {
17022                s.select(new_selections);
17023            });
17024        }
17025    }
17026
17027    pub fn select_larger_syntax_node(
17028        &mut self,
17029        _: &SelectLargerSyntaxNode,
17030        window: &mut Window,
17031        cx: &mut Context<Self>,
17032    ) {
17033        let Some(visible_row_count) = self.visible_row_count() else {
17034            return;
17035        };
17036        let old_selections: Box<[_]> = self
17037            .selections
17038            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17039            .into();
17040        if old_selections.is_empty() {
17041            return;
17042        }
17043
17044        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17045
17046        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17047        let buffer = self.buffer.read(cx).snapshot(cx);
17048
17049        let mut selected_larger_node = false;
17050        let mut new_selections = old_selections
17051            .iter()
17052            .map(|selection| {
17053                let old_range = selection.start..selection.end;
17054
17055                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
17056                    // manually select word at selection
17057                    if ["string_content", "inline"].contains(&node.kind()) {
17058                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
17059                        // ignore if word is already selected
17060                        if !word_range.is_empty() && old_range != word_range {
17061                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
17062                            // only select word if start and end point belongs to same word
17063                            if word_range == last_word_range {
17064                                selected_larger_node = true;
17065                                return Selection {
17066                                    id: selection.id,
17067                                    start: word_range.start,
17068                                    end: word_range.end,
17069                                    goal: SelectionGoal::None,
17070                                    reversed: selection.reversed,
17071                                };
17072                            }
17073                        }
17074                    }
17075                }
17076
17077                let mut new_range = old_range.clone();
17078                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
17079                    new_range = range;
17080                    if !node.is_named() {
17081                        continue;
17082                    }
17083                    if !display_map.intersects_fold(new_range.start)
17084                        && !display_map.intersects_fold(new_range.end)
17085                    {
17086                        break;
17087                    }
17088                }
17089
17090                selected_larger_node |= new_range != old_range;
17091                Selection {
17092                    id: selection.id,
17093                    start: new_range.start,
17094                    end: new_range.end,
17095                    goal: SelectionGoal::None,
17096                    reversed: selection.reversed,
17097                }
17098            })
17099            .collect::<Vec<_>>();
17100
17101        if !selected_larger_node {
17102            return; // don't put this call in the history
17103        }
17104
17105        // scroll based on transformation done to the last selection created by the user
17106        let (last_old, last_new) = old_selections
17107            .last()
17108            .zip(new_selections.last().cloned())
17109            .expect("old_selections isn't empty");
17110
17111        let is_selection_reversed = if new_selections.len() == 1 {
17112            let should_be_reversed = last_old.start != last_new.start;
17113            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
17114            should_be_reversed
17115        } else {
17116            last_new.reversed
17117        };
17118
17119        if selected_larger_node {
17120            self.select_syntax_node_history.disable_clearing = true;
17121            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17122                s.select(new_selections.clone());
17123            });
17124            self.select_syntax_node_history.disable_clearing = false;
17125        }
17126
17127        let start_row = last_new.start.to_display_point(&display_map).row().0;
17128        let end_row = last_new.end.to_display_point(&display_map).row().0;
17129        let selection_height = end_row - start_row + 1;
17130        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
17131
17132        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
17133        let scroll_behavior = if fits_on_the_screen {
17134            self.request_autoscroll(Autoscroll::fit(), cx);
17135            SelectSyntaxNodeScrollBehavior::FitSelection
17136        } else if is_selection_reversed {
17137            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
17138            SelectSyntaxNodeScrollBehavior::CursorTop
17139        } else {
17140            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
17141            SelectSyntaxNodeScrollBehavior::CursorBottom
17142        };
17143
17144        let old_selections: Box<[Selection<Anchor>]> = old_selections
17145            .iter()
17146            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
17147            .collect();
17148        self.select_syntax_node_history.push((
17149            old_selections,
17150            scroll_behavior,
17151            is_selection_reversed,
17152        ));
17153    }
17154
17155    pub fn select_smaller_syntax_node(
17156        &mut self,
17157        _: &SelectSmallerSyntaxNode,
17158        window: &mut Window,
17159        cx: &mut Context<Self>,
17160    ) {
17161        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17162
17163        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
17164            self.select_syntax_node_history.pop()
17165        {
17166            if let Some(selection) = selections.last_mut() {
17167                selection.reversed = is_selection_reversed;
17168            }
17169
17170            let snapshot = self.buffer.read(cx).snapshot(cx);
17171            let selections: Vec<Selection<MultiBufferOffset>> = selections
17172                .iter()
17173                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
17174                .collect();
17175
17176            self.select_syntax_node_history.disable_clearing = true;
17177            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17178                s.select(selections);
17179            });
17180            self.select_syntax_node_history.disable_clearing = false;
17181
17182            match scroll_behavior {
17183                SelectSyntaxNodeScrollBehavior::CursorTop => {
17184                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
17185                }
17186                SelectSyntaxNodeScrollBehavior::FitSelection => {
17187                    self.request_autoscroll(Autoscroll::fit(), cx);
17188                }
17189                SelectSyntaxNodeScrollBehavior::CursorBottom => {
17190                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
17191                }
17192            }
17193        }
17194    }
17195
17196    pub fn unwrap_syntax_node(
17197        &mut self,
17198        _: &UnwrapSyntaxNode,
17199        window: &mut Window,
17200        cx: &mut Context<Self>,
17201    ) {
17202        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17203
17204        let buffer = self.buffer.read(cx).snapshot(cx);
17205        let selections = self
17206            .selections
17207            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17208            .into_iter()
17209            // subtracting the offset requires sorting
17210            .sorted_by_key(|i| i.start);
17211
17212        let full_edits = selections
17213            .into_iter()
17214            .filter_map(|selection| {
17215                let child = if selection.is_empty()
17216                    && let Some((_, ancestor_range)) =
17217                        buffer.syntax_ancestor(selection.start..selection.end)
17218                {
17219                    ancestor_range
17220                } else {
17221                    selection.range()
17222                };
17223
17224                let mut parent = child.clone();
17225                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
17226                    parent = ancestor_range;
17227                    if parent.start < child.start || parent.end > child.end {
17228                        break;
17229                    }
17230                }
17231
17232                if parent == child {
17233                    return None;
17234                }
17235                let text = buffer.text_for_range(child).collect::<String>();
17236                Some((selection.id, parent, text))
17237            })
17238            .collect::<Vec<_>>();
17239        if full_edits.is_empty() {
17240            return;
17241        }
17242
17243        self.transact(window, cx, |this, window, cx| {
17244            this.buffer.update(cx, |buffer, cx| {
17245                buffer.edit(
17246                    full_edits
17247                        .iter()
17248                        .map(|(_, p, t)| (p.clone(), t.clone()))
17249                        .collect::<Vec<_>>(),
17250                    None,
17251                    cx,
17252                );
17253            });
17254            this.change_selections(Default::default(), window, cx, |s| {
17255                let mut offset = 0;
17256                let mut selections = vec![];
17257                for (id, parent, text) in full_edits {
17258                    let start = parent.start - offset;
17259                    offset += (parent.end - parent.start) - text.len();
17260                    selections.push(Selection {
17261                        id,
17262                        start,
17263                        end: start + text.len(),
17264                        reversed: false,
17265                        goal: Default::default(),
17266                    });
17267                }
17268                s.select(selections);
17269            });
17270        });
17271    }
17272
17273    pub fn select_next_syntax_node(
17274        &mut self,
17275        _: &SelectNextSyntaxNode,
17276        window: &mut Window,
17277        cx: &mut Context<Self>,
17278    ) {
17279        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
17280        if old_selections.is_empty() {
17281            return;
17282        }
17283
17284        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17285
17286        let buffer = self.buffer.read(cx).snapshot(cx);
17287        let mut selected_sibling = false;
17288
17289        let new_selections = old_selections
17290            .iter()
17291            .map(|selection| {
17292                let old_range =
17293                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
17294                if let Some(results) = buffer.map_excerpt_ranges(
17295                    old_range,
17296                    |buf, _excerpt_range, input_buffer_range| {
17297                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
17298                            return Vec::new();
17299                        };
17300                        vec![(
17301                            BufferOffset(node.byte_range().start)
17302                                ..BufferOffset(node.byte_range().end),
17303                            (),
17304                        )]
17305                    },
17306                ) && let [(new_range, _)] = results.as_slice()
17307                {
17308                    selected_sibling = true;
17309                    let new_range =
17310                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
17311                    Selection {
17312                        id: selection.id,
17313                        start: new_range.start,
17314                        end: new_range.end,
17315                        goal: SelectionGoal::None,
17316                        reversed: selection.reversed,
17317                    }
17318                } else {
17319                    selection.clone()
17320                }
17321            })
17322            .collect::<Vec<_>>();
17323
17324        if selected_sibling {
17325            self.change_selections(
17326                SelectionEffects::scroll(Autoscroll::fit()),
17327                window,
17328                cx,
17329                |s| {
17330                    s.select(new_selections);
17331                },
17332            );
17333        }
17334    }
17335
17336    pub fn select_prev_syntax_node(
17337        &mut self,
17338        _: &SelectPreviousSyntaxNode,
17339        window: &mut Window,
17340        cx: &mut Context<Self>,
17341    ) {
17342        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
17343
17344        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17345
17346        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
17347        let mut selected_sibling = false;
17348
17349        let new_selections = old_selections
17350            .iter()
17351            .map(|selection| {
17352                let old_range = selection.start.to_offset(&multibuffer_snapshot)
17353                    ..selection.end.to_offset(&multibuffer_snapshot);
17354                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
17355                    old_range,
17356                    |buf, _excerpt_range, input_buffer_range| {
17357                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
17358                            return Vec::new();
17359                        };
17360                        vec![(
17361                            BufferOffset(node.byte_range().start)
17362                                ..BufferOffset(node.byte_range().end),
17363                            (),
17364                        )]
17365                    },
17366                ) && let [(new_range, _)] = results.as_slice()
17367                {
17368                    selected_sibling = true;
17369                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
17370                        ..multibuffer_snapshot.anchor_before(new_range.end);
17371                    Selection {
17372                        id: selection.id,
17373                        start: new_range.start,
17374                        end: new_range.end,
17375                        goal: SelectionGoal::None,
17376                        reversed: selection.reversed,
17377                    }
17378                } else {
17379                    selection.clone()
17380                }
17381            })
17382            .collect::<Vec<_>>();
17383
17384        if selected_sibling {
17385            self.change_selections(
17386                SelectionEffects::scroll(Autoscroll::fit()),
17387                window,
17388                cx,
17389                |s| {
17390                    s.select(new_selections);
17391                },
17392            );
17393        }
17394    }
17395
17396    pub fn move_to_start_of_larger_syntax_node(
17397        &mut self,
17398        _: &MoveToStartOfLargerSyntaxNode,
17399        window: &mut Window,
17400        cx: &mut Context<Self>,
17401    ) {
17402        self.move_cursors_to_syntax_nodes(window, cx, false);
17403    }
17404
17405    pub fn move_to_end_of_larger_syntax_node(
17406        &mut self,
17407        _: &MoveToEndOfLargerSyntaxNode,
17408        window: &mut Window,
17409        cx: &mut Context<Self>,
17410    ) {
17411        self.move_cursors_to_syntax_nodes(window, cx, true);
17412    }
17413
17414    fn find_syntax_node_boundary(
17415        &self,
17416        selection_pos: MultiBufferOffset,
17417        move_to_end: bool,
17418        display_map: &DisplaySnapshot,
17419        buffer: &MultiBufferSnapshot,
17420    ) -> MultiBufferOffset {
17421        let old_range = selection_pos..selection_pos;
17422        let mut new_pos = selection_pos;
17423        let mut search_range = old_range;
17424        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17425            search_range = range.clone();
17426            if !node.is_named()
17427                || display_map.intersects_fold(range.start)
17428                || display_map.intersects_fold(range.end)
17429                // If cursor is already at the end of the syntax node, continue searching
17430                || (move_to_end && range.end == selection_pos)
17431                // If cursor is already at the start of the syntax node, continue searching
17432                || (!move_to_end && range.start == selection_pos)
17433            {
17434                continue;
17435            }
17436
17437            // If we found a string_content node, find the largest parent that is still string_content
17438            // Enables us to skip to the end of strings without taking multiple steps inside the string
17439            let (_, final_range) = if node.kind() == "string_content" {
17440                let mut current_node = node;
17441                let mut current_range = range;
17442                while let Some((parent, parent_range)) =
17443                    buffer.syntax_ancestor(current_range.clone())
17444                {
17445                    if parent.kind() == "string_content" {
17446                        current_node = parent;
17447                        current_range = parent_range;
17448                    } else {
17449                        break;
17450                    }
17451                }
17452
17453                (current_node, current_range)
17454            } else {
17455                (node, range)
17456            };
17457
17458            new_pos = if move_to_end {
17459                final_range.end
17460            } else {
17461                final_range.start
17462            };
17463
17464            break;
17465        }
17466
17467        new_pos
17468    }
17469
17470    fn move_cursors_to_syntax_nodes(
17471        &mut self,
17472        window: &mut Window,
17473        cx: &mut Context<Self>,
17474        move_to_end: bool,
17475    ) -> bool {
17476        let old_selections: Box<[_]> = self
17477            .selections
17478            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17479            .into();
17480        if old_selections.is_empty() {
17481            return false;
17482        }
17483
17484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17485
17486        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17487        let buffer = self.buffer.read(cx).snapshot(cx);
17488
17489        let mut any_cursor_moved = false;
17490        let new_selections = old_selections
17491            .iter()
17492            .map(|selection| {
17493                if !selection.is_empty() {
17494                    return selection.clone();
17495                }
17496
17497                let selection_pos = selection.head();
17498                let new_pos = self.find_syntax_node_boundary(
17499                    selection_pos,
17500                    move_to_end,
17501                    &display_map,
17502                    &buffer,
17503                );
17504
17505                any_cursor_moved |= new_pos != selection_pos;
17506
17507                Selection {
17508                    id: selection.id,
17509                    start: new_pos,
17510                    end: new_pos,
17511                    goal: SelectionGoal::None,
17512                    reversed: false,
17513                }
17514            })
17515            .collect::<Vec<_>>();
17516
17517        self.change_selections(Default::default(), window, cx, |s| {
17518            s.select(new_selections);
17519        });
17520        self.request_autoscroll(Autoscroll::newest(), cx);
17521
17522        any_cursor_moved
17523    }
17524
17525    pub fn select_to_start_of_larger_syntax_node(
17526        &mut self,
17527        _: &SelectToStartOfLargerSyntaxNode,
17528        window: &mut Window,
17529        cx: &mut Context<Self>,
17530    ) {
17531        self.select_to_syntax_nodes(window, cx, false);
17532    }
17533
17534    pub fn select_to_end_of_larger_syntax_node(
17535        &mut self,
17536        _: &SelectToEndOfLargerSyntaxNode,
17537        window: &mut Window,
17538        cx: &mut Context<Self>,
17539    ) {
17540        self.select_to_syntax_nodes(window, cx, true);
17541    }
17542
17543    fn select_to_syntax_nodes(
17544        &mut self,
17545        window: &mut Window,
17546        cx: &mut Context<Self>,
17547        move_to_end: bool,
17548    ) {
17549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17550
17551        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17552        let buffer = self.buffer.read(cx).snapshot(cx);
17553        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17554
17555        let new_selections = old_selections
17556            .iter()
17557            .map(|selection| {
17558                let new_pos = self.find_syntax_node_boundary(
17559                    selection.head(),
17560                    move_to_end,
17561                    &display_map,
17562                    &buffer,
17563                );
17564
17565                let mut new_selection = selection.clone();
17566                new_selection.set_head(new_pos, SelectionGoal::None);
17567                new_selection
17568            })
17569            .collect::<Vec<_>>();
17570
17571        self.change_selections(Default::default(), window, cx, |s| {
17572            s.select(new_selections);
17573        });
17574    }
17575
17576    pub fn move_to_enclosing_bracket(
17577        &mut self,
17578        _: &MoveToEnclosingBracket,
17579        window: &mut Window,
17580        cx: &mut Context<Self>,
17581    ) {
17582        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17583        self.change_selections(Default::default(), window, cx, |s| {
17584            s.move_offsets_with(&mut |snapshot, selection| {
17585                let Some(enclosing_bracket_ranges) =
17586                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17587                else {
17588                    return;
17589                };
17590
17591                let mut best_length = usize::MAX;
17592                let mut best_inside = false;
17593                let mut best_in_bracket_range = false;
17594                let mut best_destination = None;
17595                for (open, close) in enclosing_bracket_ranges {
17596                    let close = close.to_inclusive();
17597                    let length = *close.end() - open.start;
17598                    let inside = selection.start >= open.end && selection.end <= *close.start();
17599                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17600                        || close.contains(&selection.head());
17601
17602                    // If best is next to a bracket and current isn't, skip
17603                    if !in_bracket_range && best_in_bracket_range {
17604                        continue;
17605                    }
17606
17607                    // Prefer smaller lengths unless best is inside and current isn't
17608                    if length > best_length && (best_inside || !inside) {
17609                        continue;
17610                    }
17611
17612                    best_length = length;
17613                    best_inside = inside;
17614                    best_in_bracket_range = in_bracket_range;
17615                    best_destination = Some(
17616                        if close.contains(&selection.start) && close.contains(&selection.end) {
17617                            if inside { open.end } else { open.start }
17618                        } else if inside {
17619                            *close.start()
17620                        } else {
17621                            *close.end()
17622                        },
17623                    );
17624                }
17625
17626                if let Some(destination) = best_destination {
17627                    selection.collapse_to(destination, SelectionGoal::None);
17628                }
17629            })
17630        });
17631    }
17632
17633    pub fn undo_selection(
17634        &mut self,
17635        _: &UndoSelection,
17636        window: &mut Window,
17637        cx: &mut Context<Self>,
17638    ) {
17639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17640        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17641            self.selection_history.mode = SelectionHistoryMode::Undoing;
17642            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17643                this.end_selection(window, cx);
17644                this.change_selections(
17645                    SelectionEffects::scroll(Autoscroll::newest()),
17646                    window,
17647                    cx,
17648                    |s| s.select_anchors(entry.selections.to_vec()),
17649                );
17650            });
17651            self.selection_history.mode = SelectionHistoryMode::Normal;
17652
17653            self.select_next_state = entry.select_next_state;
17654            self.select_prev_state = entry.select_prev_state;
17655            self.add_selections_state = entry.add_selections_state;
17656        }
17657    }
17658
17659    pub fn redo_selection(
17660        &mut self,
17661        _: &RedoSelection,
17662        window: &mut Window,
17663        cx: &mut Context<Self>,
17664    ) {
17665        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17666        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17667            self.selection_history.mode = SelectionHistoryMode::Redoing;
17668            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17669                this.end_selection(window, cx);
17670                this.change_selections(
17671                    SelectionEffects::scroll(Autoscroll::newest()),
17672                    window,
17673                    cx,
17674                    |s| s.select_anchors(entry.selections.to_vec()),
17675                );
17676            });
17677            self.selection_history.mode = SelectionHistoryMode::Normal;
17678
17679            self.select_next_state = entry.select_next_state;
17680            self.select_prev_state = entry.select_prev_state;
17681            self.add_selections_state = entry.add_selections_state;
17682        }
17683    }
17684
17685    pub fn expand_excerpts(
17686        &mut self,
17687        action: &ExpandExcerpts,
17688        _: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) {
17691        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17692    }
17693
17694    pub fn expand_excerpts_down(
17695        &mut self,
17696        action: &ExpandExcerptsDown,
17697        _: &mut Window,
17698        cx: &mut Context<Self>,
17699    ) {
17700        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17701    }
17702
17703    pub fn expand_excerpts_up(
17704        &mut self,
17705        action: &ExpandExcerptsUp,
17706        _: &mut Window,
17707        cx: &mut Context<Self>,
17708    ) {
17709        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17710    }
17711
17712    pub fn expand_excerpts_for_direction(
17713        &mut self,
17714        lines: u32,
17715        direction: ExpandExcerptDirection,
17716        cx: &mut Context<Self>,
17717    ) {
17718        let selections = self.selections.disjoint_anchors_arc();
17719
17720        let lines = if lines == 0 {
17721            EditorSettings::get_global(cx).expand_excerpt_lines
17722        } else {
17723            lines
17724        };
17725
17726        let snapshot = self.buffer.read(cx).snapshot(cx);
17727        let excerpt_anchors = selections
17728            .iter()
17729            .flat_map(|selection| {
17730                snapshot
17731                    .range_to_buffer_ranges(selection.range())
17732                    .into_iter()
17733                    .filter_map(|(buffer_snapshot, range, _)| {
17734                        snapshot.anchor_in_excerpt(buffer_snapshot.anchor_after(range.start))
17735                    })
17736            })
17737            .collect::<Vec<_>>();
17738
17739        if self.delegate_expand_excerpts {
17740            cx.emit(EditorEvent::ExpandExcerptsRequested {
17741                excerpt_anchors,
17742                lines,
17743                direction,
17744            });
17745            return;
17746        }
17747
17748        self.buffer.update(cx, |buffer, cx| {
17749            buffer.expand_excerpts(excerpt_anchors, lines, direction, cx)
17750        })
17751    }
17752
17753    pub(crate) fn expand_excerpt(
17754        &mut self,
17755        excerpt_anchor: Anchor,
17756        direction: ExpandExcerptDirection,
17757        window: &mut Window,
17758        cx: &mut Context<Self>,
17759    ) {
17760        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17761
17762        if self.delegate_expand_excerpts {
17763            cx.emit(EditorEvent::ExpandExcerptsRequested {
17764                excerpt_anchors: vec![excerpt_anchor],
17765                lines: lines_to_expand,
17766                direction,
17767            });
17768            return;
17769        }
17770
17771        let current_scroll_position = self.scroll_position(cx);
17772        let mut scroll = None;
17773
17774        if direction == ExpandExcerptDirection::Down {
17775            let multi_buffer = self.buffer.read(cx);
17776            let snapshot = multi_buffer.snapshot(cx);
17777            if let Some((buffer_snapshot, excerpt_range)) =
17778                snapshot.excerpt_containing(excerpt_anchor..excerpt_anchor)
17779            {
17780                let excerpt_end_row =
17781                    Point::from_anchor(&excerpt_range.context.end, &buffer_snapshot).row;
17782                let last_row = buffer_snapshot.max_point().row;
17783                let lines_below = last_row.saturating_sub(excerpt_end_row);
17784                if lines_below >= lines_to_expand {
17785                    scroll = Some(
17786                        current_scroll_position
17787                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17788                    );
17789                }
17790            }
17791        }
17792        if direction == ExpandExcerptDirection::Up
17793            && self
17794                .buffer
17795                .read(cx)
17796                .snapshot(cx)
17797                .excerpt_before(excerpt_anchor)
17798                .is_none()
17799        {
17800            scroll = Some(current_scroll_position);
17801        }
17802
17803        self.buffer.update(cx, |buffer, cx| {
17804            buffer.expand_excerpts([excerpt_anchor], lines_to_expand, direction, cx)
17805        });
17806
17807        if let Some(new_scroll_position) = scroll {
17808            self.set_scroll_position(new_scroll_position, window, cx);
17809        }
17810    }
17811
17812    pub fn go_to_singleton_buffer_point(
17813        &mut self,
17814        point: Point,
17815        window: &mut Window,
17816        cx: &mut Context<Self>,
17817    ) {
17818        self.go_to_singleton_buffer_range(point..point, window, cx);
17819    }
17820
17821    pub fn go_to_singleton_buffer_range(
17822        &mut self,
17823        range: Range<Point>,
17824        window: &mut Window,
17825        cx: &mut Context<Self>,
17826    ) {
17827        let multibuffer = self.buffer().read(cx);
17828        if !multibuffer.is_singleton() {
17829            return;
17830        };
17831        let anchor_range = range.to_anchors(&multibuffer.snapshot(cx));
17832        self.change_selections(
17833            SelectionEffects::default().nav_history(true),
17834            window,
17835            cx,
17836            |s| s.select_anchor_ranges([anchor_range]),
17837        );
17838    }
17839
17840    pub fn go_to_diagnostic(
17841        &mut self,
17842        action: &GoToDiagnostic,
17843        window: &mut Window,
17844        cx: &mut Context<Self>,
17845    ) {
17846        if !self.diagnostics_enabled() {
17847            return;
17848        }
17849        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17850        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17851    }
17852
17853    pub fn go_to_prev_diagnostic(
17854        &mut self,
17855        action: &GoToPreviousDiagnostic,
17856        window: &mut Window,
17857        cx: &mut Context<Self>,
17858    ) {
17859        if !self.diagnostics_enabled() {
17860            return;
17861        }
17862        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17863        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17864    }
17865
17866    pub fn go_to_diagnostic_impl(
17867        &mut self,
17868        direction: Direction,
17869        severity: GoToDiagnosticSeverityFilter,
17870        window: &mut Window,
17871        cx: &mut Context<Self>,
17872    ) {
17873        let buffer = self.buffer.read(cx).snapshot(cx);
17874        let selection = self
17875            .selections
17876            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17877
17878        let mut active_group_id = None;
17879        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17880            && active_group.active_range.start.to_offset(&buffer) == selection.start
17881        {
17882            active_group_id = Some(active_group.group_id);
17883        }
17884
17885        fn filtered<'a>(
17886            severity: GoToDiagnosticSeverityFilter,
17887            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17888        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17889            diagnostics
17890                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17891                .filter(|entry| entry.range.start != entry.range.end)
17892                .filter(|entry| !entry.diagnostic.is_unnecessary)
17893        }
17894
17895        let before = filtered(
17896            severity,
17897            buffer
17898                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17899                .filter(|entry| entry.range.start <= selection.start),
17900        );
17901        let after = filtered(
17902            severity,
17903            buffer
17904                .diagnostics_in_range(selection.start..buffer.len())
17905                .filter(|entry| entry.range.start >= selection.start),
17906        );
17907
17908        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17909        if direction == Direction::Prev {
17910            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17911            {
17912                for diagnostic in prev_diagnostics.into_iter().rev() {
17913                    if diagnostic.range.start != selection.start
17914                        || active_group_id
17915                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17916                    {
17917                        found = Some(diagnostic);
17918                        break 'outer;
17919                    }
17920                }
17921            }
17922        } else {
17923            for diagnostic in after.chain(before) {
17924                if diagnostic.range.start != selection.start
17925                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17926                {
17927                    found = Some(diagnostic);
17928                    break;
17929                }
17930            }
17931        }
17932        let Some(next_diagnostic) = found else {
17933            return;
17934        };
17935
17936        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17937        let Some((buffer_anchor, _)) = buffer.anchor_to_buffer_anchor(next_diagnostic_start) else {
17938            return;
17939        };
17940        let buffer_id = buffer_anchor.buffer_id;
17941        let snapshot = self.snapshot(window, cx);
17942        if snapshot.intersects_fold(next_diagnostic.range.start) {
17943            self.unfold_ranges(
17944                std::slice::from_ref(&next_diagnostic.range),
17945                true,
17946                false,
17947                cx,
17948            );
17949        }
17950        self.change_selections(Default::default(), window, cx, |s| {
17951            s.select_ranges(vec![
17952                next_diagnostic.range.start..next_diagnostic.range.start,
17953            ])
17954        });
17955        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17956        self.refresh_edit_prediction(false, true, window, cx);
17957    }
17958
17959    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17960        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17961        let snapshot = self.snapshot(window, cx);
17962        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17963        self.go_to_hunk_before_or_after_position(
17964            &snapshot,
17965            selection.head(),
17966            Direction::Next,
17967            true,
17968            window,
17969            cx,
17970        );
17971    }
17972
17973    pub fn go_to_hunk_before_or_after_position(
17974        &mut self,
17975        snapshot: &EditorSnapshot,
17976        position: Point,
17977        direction: Direction,
17978        wrap_around: bool,
17979        window: &mut Window,
17980        cx: &mut Context<Editor>,
17981    ) {
17982        let row = if direction == Direction::Next {
17983            self.hunk_after_position(snapshot, position, wrap_around)
17984                .map(|hunk| hunk.row_range.start)
17985        } else {
17986            self.hunk_before_position(snapshot, position, wrap_around)
17987        };
17988
17989        if let Some(row) = row {
17990            let destination = Point::new(row.0, 0);
17991            let autoscroll = Autoscroll::center();
17992
17993            self.unfold_ranges(&[destination..destination], false, false, cx);
17994            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17995                s.select_ranges([destination..destination]);
17996            });
17997        }
17998    }
17999
18000    fn hunk_after_position(
18001        &mut self,
18002        snapshot: &EditorSnapshot,
18003        position: Point,
18004        wrap_around: bool,
18005    ) -> Option<MultiBufferDiffHunk> {
18006        let result = snapshot
18007            .buffer_snapshot()
18008            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18009            .find(|hunk| hunk.row_range.start.0 > position.row);
18010
18011        if wrap_around {
18012            result.or_else(|| {
18013                snapshot
18014                    .buffer_snapshot()
18015                    .diff_hunks_in_range(Point::zero()..position)
18016                    .find(|hunk| hunk.row_range.end.0 < position.row)
18017            })
18018        } else {
18019            result
18020        }
18021    }
18022
18023    fn go_to_prev_hunk(
18024        &mut self,
18025        _: &GoToPreviousHunk,
18026        window: &mut Window,
18027        cx: &mut Context<Self>,
18028    ) {
18029        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
18030        let snapshot = self.snapshot(window, cx);
18031        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
18032        self.go_to_hunk_before_or_after_position(
18033            &snapshot,
18034            selection.head(),
18035            Direction::Prev,
18036            true,
18037            window,
18038            cx,
18039        );
18040    }
18041
18042    fn hunk_before_position(
18043        &mut self,
18044        snapshot: &EditorSnapshot,
18045        position: Point,
18046        wrap_around: bool,
18047    ) -> Option<MultiBufferRow> {
18048        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
18049
18050        if wrap_around {
18051            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
18052        } else {
18053            result
18054        }
18055    }
18056
18057    fn go_to_next_change(
18058        &mut self,
18059        _: &GoToNextChange,
18060        window: &mut Window,
18061        cx: &mut Context<Self>,
18062    ) {
18063        if let Some(selections) = self
18064            .change_list
18065            .next_change(1, Direction::Next)
18066            .map(|s| s.to_vec())
18067        {
18068            self.change_selections(Default::default(), window, cx, |s| {
18069                let map = s.display_snapshot();
18070                s.select_display_ranges(selections.iter().map(|a| {
18071                    let point = a.to_display_point(&map);
18072                    point..point
18073                }))
18074            })
18075        }
18076    }
18077
18078    fn go_to_previous_change(
18079        &mut self,
18080        _: &GoToPreviousChange,
18081        window: &mut Window,
18082        cx: &mut Context<Self>,
18083    ) {
18084        if let Some(selections) = self
18085            .change_list
18086            .next_change(1, Direction::Prev)
18087            .map(|s| s.to_vec())
18088        {
18089            self.change_selections(Default::default(), window, cx, |s| {
18090                let map = s.display_snapshot();
18091                s.select_display_ranges(selections.iter().map(|a| {
18092                    let point = a.to_display_point(&map);
18093                    point..point
18094                }))
18095            })
18096        }
18097    }
18098
18099    pub fn go_to_next_document_highlight(
18100        &mut self,
18101        _: &GoToNextDocumentHighlight,
18102        window: &mut Window,
18103        cx: &mut Context<Self>,
18104    ) {
18105        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
18106    }
18107
18108    pub fn go_to_prev_document_highlight(
18109        &mut self,
18110        _: &GoToPreviousDocumentHighlight,
18111        window: &mut Window,
18112        cx: &mut Context<Self>,
18113    ) {
18114        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
18115    }
18116
18117    pub fn go_to_document_highlight_before_or_after_position(
18118        &mut self,
18119        direction: Direction,
18120        window: &mut Window,
18121        cx: &mut Context<Editor>,
18122    ) {
18123        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
18124        let snapshot = self.snapshot(window, cx);
18125        let buffer = &snapshot.buffer_snapshot();
18126        let position = self
18127            .selections
18128            .newest::<Point>(&snapshot.display_snapshot)
18129            .head();
18130        let anchor_position = buffer.anchor_after(position);
18131
18132        // Get all document highlights (both read and write)
18133        let mut all_highlights = Vec::new();
18134
18135        if let Some((_, read_highlights)) = self
18136            .background_highlights
18137            .get(&HighlightKey::DocumentHighlightRead)
18138        {
18139            all_highlights.extend(read_highlights.iter());
18140        }
18141
18142        if let Some((_, write_highlights)) = self
18143            .background_highlights
18144            .get(&HighlightKey::DocumentHighlightWrite)
18145        {
18146            all_highlights.extend(write_highlights.iter());
18147        }
18148
18149        if all_highlights.is_empty() {
18150            return;
18151        }
18152
18153        // Sort highlights by position
18154        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
18155
18156        let target_highlight = match direction {
18157            Direction::Next => {
18158                // Find the first highlight after the current position
18159                all_highlights
18160                    .iter()
18161                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
18162            }
18163            Direction::Prev => {
18164                // Find the last highlight before the current position
18165                all_highlights
18166                    .iter()
18167                    .rev()
18168                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
18169            }
18170        };
18171
18172        if let Some(highlight) = target_highlight {
18173            let destination = highlight.start.to_point(buffer);
18174            let autoscroll = Autoscroll::center();
18175
18176            self.unfold_ranges(&[destination..destination], false, false, cx);
18177            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18178                s.select_ranges([destination..destination]);
18179            });
18180        }
18181    }
18182
18183    fn go_to_line<T: 'static>(
18184        &mut self,
18185        position: Anchor,
18186        highlight_color: Option<Hsla>,
18187        window: &mut Window,
18188        cx: &mut Context<Self>,
18189    ) {
18190        let snapshot = self.snapshot(window, cx).display_snapshot;
18191        let position = position.to_point(&snapshot.buffer_snapshot());
18192        let start = snapshot
18193            .buffer_snapshot()
18194            .clip_point(Point::new(position.row, 0), Bias::Left);
18195        let end = start + Point::new(1, 0);
18196        let start = snapshot.buffer_snapshot().anchor_before(start);
18197        let end = snapshot.buffer_snapshot().anchor_before(end);
18198
18199        self.highlight_rows::<T>(
18200            start..end,
18201            highlight_color
18202                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
18203            Default::default(),
18204            cx,
18205        );
18206
18207        if self.buffer.read(cx).is_singleton() {
18208            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
18209        }
18210    }
18211
18212    pub fn go_to_definition(
18213        &mut self,
18214        _: &GoToDefinition,
18215        window: &mut Window,
18216        cx: &mut Context<Self>,
18217    ) -> Task<Result<Navigated>> {
18218        let definition =
18219            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
18220        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
18221        cx.spawn_in(window, async move |editor, cx| {
18222            if definition.await? == Navigated::Yes {
18223                return Ok(Navigated::Yes);
18224            }
18225            match fallback_strategy {
18226                GoToDefinitionFallback::None => Ok(Navigated::No),
18227                GoToDefinitionFallback::FindAllReferences => {
18228                    match editor.update_in(cx, |editor, window, cx| {
18229                        editor.find_all_references(&FindAllReferences::default(), window, cx)
18230                    })? {
18231                        Some(references) => references.await,
18232                        None => Ok(Navigated::No),
18233                    }
18234                }
18235            }
18236        })
18237    }
18238
18239    pub fn go_to_declaration(
18240        &mut self,
18241        _: &GoToDeclaration,
18242        window: &mut Window,
18243        cx: &mut Context<Self>,
18244    ) -> Task<Result<Navigated>> {
18245        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
18246    }
18247
18248    pub fn go_to_declaration_split(
18249        &mut self,
18250        _: &GoToDeclaration,
18251        window: &mut Window,
18252        cx: &mut Context<Self>,
18253    ) -> Task<Result<Navigated>> {
18254        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
18255    }
18256
18257    pub fn go_to_implementation(
18258        &mut self,
18259        _: &GoToImplementation,
18260        window: &mut Window,
18261        cx: &mut Context<Self>,
18262    ) -> Task<Result<Navigated>> {
18263        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
18264    }
18265
18266    pub fn go_to_implementation_split(
18267        &mut self,
18268        _: &GoToImplementationSplit,
18269        window: &mut Window,
18270        cx: &mut Context<Self>,
18271    ) -> Task<Result<Navigated>> {
18272        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
18273    }
18274
18275    pub fn go_to_type_definition(
18276        &mut self,
18277        _: &GoToTypeDefinition,
18278        window: &mut Window,
18279        cx: &mut Context<Self>,
18280    ) -> Task<Result<Navigated>> {
18281        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
18282    }
18283
18284    pub fn go_to_definition_split(
18285        &mut self,
18286        _: &GoToDefinitionSplit,
18287        window: &mut Window,
18288        cx: &mut Context<Self>,
18289    ) -> Task<Result<Navigated>> {
18290        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18291    }
18292
18293    pub fn go_to_type_definition_split(
18294        &mut self,
18295        _: &GoToTypeDefinitionSplit,
18296        window: &mut Window,
18297        cx: &mut Context<Self>,
18298    ) -> Task<Result<Navigated>> {
18299        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18300    }
18301
18302    fn go_to_definition_of_kind(
18303        &mut self,
18304        kind: GotoDefinitionKind,
18305        split: bool,
18306        window: &mut Window,
18307        cx: &mut Context<Self>,
18308    ) -> Task<Result<Navigated>> {
18309        let Some(provider) = self.semantics_provider.clone() else {
18310            return Task::ready(Ok(Navigated::No));
18311        };
18312        let head = self
18313            .selections
18314            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18315            .head();
18316        let buffer = self.buffer.read(cx);
18317        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18318            return Task::ready(Ok(Navigated::No));
18319        };
18320        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18321            return Task::ready(Ok(Navigated::No));
18322        };
18323
18324        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18325
18326        cx.spawn_in(window, async move |editor, cx| {
18327            let Some(definitions) = definitions.await? else {
18328                return Ok(Navigated::No);
18329            };
18330            let navigated = editor
18331                .update_in(cx, |editor, window, cx| {
18332                    editor.navigate_to_hover_links(
18333                        Some(kind),
18334                        definitions
18335                            .into_iter()
18336                            .filter(|location| {
18337                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18338                            })
18339                            .map(HoverLink::Text)
18340                            .collect::<Vec<_>>(),
18341                        nav_entry,
18342                        split,
18343                        window,
18344                        cx,
18345                    )
18346                })?
18347                .await?;
18348            anyhow::Ok(navigated)
18349        })
18350    }
18351
18352    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18353        let selection = self.selections.newest_anchor();
18354        let head = selection.head();
18355        let tail = selection.tail();
18356
18357        let Some((buffer, start_position)) =
18358            self.buffer.read(cx).text_anchor_for_position(head, cx)
18359        else {
18360            return;
18361        };
18362
18363        let end_position = if head != tail {
18364            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18365                return;
18366            };
18367            Some(pos)
18368        } else {
18369            None
18370        };
18371
18372        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18373            let url = if let Some(end_pos) = end_position {
18374                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18375            } else {
18376                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18377            };
18378
18379            if let Some(url) = url {
18380                cx.update(|window, cx| {
18381                    if parse_zed_link(&url, cx).is_some() {
18382                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18383                    } else {
18384                        cx.open_url(&url);
18385                    }
18386                })?;
18387            }
18388
18389            anyhow::Ok(())
18390        });
18391
18392        url_finder.detach();
18393    }
18394
18395    pub fn open_selected_filename(
18396        &mut self,
18397        _: &OpenSelectedFilename,
18398        window: &mut Window,
18399        cx: &mut Context<Self>,
18400    ) {
18401        let Some(workspace) = self.workspace() else {
18402            return;
18403        };
18404
18405        let position = self.selections.newest_anchor().head();
18406
18407        let Some((buffer, buffer_position)) =
18408            self.buffer.read(cx).text_anchor_for_position(position, cx)
18409        else {
18410            return;
18411        };
18412
18413        let project = self.project.clone();
18414
18415        cx.spawn_in(window, async move |_, cx| {
18416            let result = find_file(&buffer, project, buffer_position, cx).await;
18417
18418            if let Some((_, path)) = result {
18419                workspace
18420                    .update_in(cx, |workspace, window, cx| {
18421                        workspace.open_resolved_path(path, window, cx)
18422                    })?
18423                    .await?;
18424            }
18425            anyhow::Ok(())
18426        })
18427        .detach();
18428    }
18429
18430    pub(crate) fn navigate_to_hover_links(
18431        &mut self,
18432        kind: Option<GotoDefinitionKind>,
18433        definitions: Vec<HoverLink>,
18434        origin: Option<NavigationEntry>,
18435        split: bool,
18436        window: &mut Window,
18437        cx: &mut Context<Editor>,
18438    ) -> Task<Result<Navigated>> {
18439        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18440        let mut first_url_or_file = None;
18441        let definitions: Vec<_> = definitions
18442            .into_iter()
18443            .filter_map(|def| match def {
18444                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18445                HoverLink::InlayHint(lsp_location, server_id) => {
18446                    let computation =
18447                        self.compute_target_location(lsp_location, server_id, window, cx);
18448                    Some(cx.background_spawn(computation))
18449                }
18450                HoverLink::Url(url) => {
18451                    first_url_or_file = Some(Either::Left(url));
18452                    None
18453                }
18454                HoverLink::File(path) => {
18455                    first_url_or_file = Some(Either::Right(path));
18456                    None
18457                }
18458            })
18459            .collect();
18460
18461        let workspace = self.workspace();
18462
18463        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18464        cx.spawn_in(window, async move |editor, cx| {
18465            let locations: Vec<Location> = future::join_all(definitions)
18466                .await
18467                .into_iter()
18468                .filter_map(|location| location.transpose())
18469                .collect::<Result<_>>()
18470                .context("location tasks")?;
18471            let mut locations = cx.update(|_, cx| {
18472                locations
18473                    .into_iter()
18474                    .map(|location| {
18475                        let buffer = location.buffer.read(cx);
18476                        (location.buffer, location.range.to_point(buffer))
18477                    })
18478                    .into_group_map()
18479            })?;
18480            let mut num_locations = 0;
18481            for ranges in locations.values_mut() {
18482                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18483                ranges.dedup();
18484                // Merge overlapping or contained ranges. After sorting by
18485                // (start, Reverse(end)), we can merge in a single pass:
18486                // if the next range starts before the current one ends,
18487                // extend the current range's end if needed.
18488                let mut i = 0;
18489                while i + 1 < ranges.len() {
18490                    if ranges[i + 1].start <= ranges[i].end {
18491                        let merged_end = ranges[i].end.max(ranges[i + 1].end);
18492                        ranges[i].end = merged_end;
18493                        ranges.remove(i + 1);
18494                    } else {
18495                        i += 1;
18496                    }
18497                }
18498                let fits_in_one_excerpt = ranges
18499                    .iter()
18500                    .tuple_windows()
18501                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18502                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18503            }
18504
18505            if num_locations > 1 {
18506                let tab_kind = match kind {
18507                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18508                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18509                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18510                    Some(GotoDefinitionKind::Type) => "Types",
18511                };
18512                let title = editor
18513                    .update_in(cx, |_, _, cx| {
18514                        let target = locations
18515                            .iter()
18516                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18517                            .map(|(buffer, location)| {
18518                                buffer
18519                                    .read(cx)
18520                                    .text_for_range(location.clone())
18521                                    .collect::<String>()
18522                            })
18523                            .filter(|text| !text.contains('\n'))
18524                            .unique()
18525                            .take(3)
18526                            .join(", ");
18527                        if target.is_empty() {
18528                            tab_kind.to_owned()
18529                        } else {
18530                            format!("{tab_kind} for {target}")
18531                        }
18532                    })
18533                    .context("buffer title")?;
18534
18535                let Some(workspace) = workspace else {
18536                    return Ok(Navigated::No);
18537                };
18538
18539                let opened = workspace
18540                    .update_in(cx, |workspace, window, cx| {
18541                        let allow_preview = PreviewTabsSettings::get_global(cx)
18542                            .enable_preview_multibuffer_from_code_navigation;
18543                        if let Some((target_editor, target_pane)) =
18544                            Self::open_locations_in_multibuffer(
18545                                workspace,
18546                                locations,
18547                                title,
18548                                split,
18549                                allow_preview,
18550                                MultibufferSelectionMode::First,
18551                                window,
18552                                cx,
18553                            )
18554                        {
18555                            // We create our own nav history instead of using
18556                            // `target_editor.nav_history` because `nav_history`
18557                            // seems to be populated asynchronously when an item
18558                            // is added to a pane
18559                            let mut nav_history = target_pane
18560                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18561                            target_editor.update(cx, |editor, cx| {
18562                                let nav_data = editor
18563                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18564                                let target =
18565                                    Some(nav_history.navigation_entry(Some(
18566                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18567                                    )));
18568                                nav_history.push_tag(origin, target);
18569                            })
18570                        }
18571                    })
18572                    .is_ok();
18573
18574                anyhow::Ok(Navigated::from_bool(opened))
18575            } else if num_locations == 0 {
18576                // If there is one url or file, open it directly
18577                match first_url_or_file {
18578                    Some(Either::Left(url)) => {
18579                        cx.update(|window, cx| {
18580                            if parse_zed_link(&url, cx).is_some() {
18581                                window
18582                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18583                            } else {
18584                                cx.open_url(&url);
18585                            }
18586                        })?;
18587                        Ok(Navigated::Yes)
18588                    }
18589                    Some(Either::Right(path)) => {
18590                        // TODO(andrew): respect preview tab settings
18591                        //               `enable_keep_preview_on_code_navigation` and
18592                        //               `enable_preview_file_from_code_navigation`
18593                        let Some(workspace) = workspace else {
18594                            return Ok(Navigated::No);
18595                        };
18596                        workspace
18597                            .update_in(cx, |workspace, window, cx| {
18598                                workspace.open_resolved_path(path, window, cx)
18599                            })?
18600                            .await?;
18601                        Ok(Navigated::Yes)
18602                    }
18603                    None => Ok(Navigated::No),
18604                }
18605            } else {
18606                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18607
18608                editor.update_in(cx, |editor, window, cx| {
18609                    let target_ranges = target_ranges
18610                        .into_iter()
18611                        .map(|r| editor.range_for_match(&r))
18612                        .map(collapse_multiline_range)
18613                        .collect::<Vec<_>>();
18614                    if !split
18615                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18616                    {
18617                        let multibuffer = editor.buffer.read(cx);
18618                        let target_ranges = target_ranges
18619                            .into_iter()
18620                            .filter_map(|r| {
18621                                let start = multibuffer.buffer_point_to_anchor(
18622                                    &target_buffer,
18623                                    r.start,
18624                                    cx,
18625                                )?;
18626                                let end = multibuffer.buffer_point_to_anchor(
18627                                    &target_buffer,
18628                                    r.end,
18629                                    cx,
18630                                )?;
18631                                Some(start..end)
18632                            })
18633                            .collect::<Vec<_>>();
18634                        if target_ranges.is_empty() {
18635                            return Navigated::No;
18636                        }
18637
18638                        editor.change_selections(
18639                            SelectionEffects::default().nav_history(true),
18640                            window,
18641                            cx,
18642                            |s| s.select_anchor_ranges(target_ranges),
18643                        );
18644
18645                        let target =
18646                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18647                        if let Some(mut nav_history) = editor.nav_history.clone() {
18648                            nav_history.push_tag(origin, target);
18649                        }
18650                    } else {
18651                        let Some(workspace) = workspace else {
18652                            return Navigated::No;
18653                        };
18654                        let pane = workspace.read(cx).active_pane().clone();
18655                        window.defer(cx, move |window, cx| {
18656                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18657                                workspace.update(cx, |workspace, cx| {
18658                                    let pane = if split {
18659                                        workspace.adjacent_pane(window, cx)
18660                                    } else {
18661                                        workspace.active_pane().clone()
18662                                    };
18663
18664                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18665                                    let keep_old_preview = preview_tabs_settings
18666                                        .enable_keep_preview_on_code_navigation;
18667                                    let allow_new_preview = preview_tabs_settings
18668                                        .enable_preview_file_from_code_navigation;
18669
18670                                    let editor = workspace.open_project_item(
18671                                        pane.clone(),
18672                                        target_buffer.clone(),
18673                                        true,
18674                                        true,
18675                                        keep_old_preview,
18676                                        allow_new_preview,
18677                                        window,
18678                                        cx,
18679                                    );
18680                                    (editor, pane)
18681                                });
18682                            // We create our own nav history instead of using
18683                            // `target_editor.nav_history` because `nav_history`
18684                            // seems to be populated asynchronously when an item
18685                            // is added to a pane
18686                            let mut nav_history = target_pane
18687                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18688                            target_editor.update(cx, |target_editor, cx| {
18689                                // When selecting a definition in a different buffer, disable the nav history
18690                                // to avoid creating a history entry at the previous cursor location.
18691                                pane.update(cx, |pane, _| pane.disable_history());
18692
18693                                let multibuffer = target_editor.buffer.read(cx);
18694                                let Some(target_buffer) = multibuffer.as_singleton() else {
18695                                    return Navigated::No;
18696                                };
18697                                let target_ranges = target_ranges
18698                                    .into_iter()
18699                                    .filter_map(|r| {
18700                                        let start = multibuffer.buffer_point_to_anchor(
18701                                            &target_buffer,
18702                                            r.start,
18703                                            cx,
18704                                        )?;
18705                                        let end = multibuffer.buffer_point_to_anchor(
18706                                            &target_buffer,
18707                                            r.end,
18708                                            cx,
18709                                        )?;
18710                                        Some(start..end)
18711                                    })
18712                                    .collect::<Vec<_>>();
18713                                if target_ranges.is_empty() {
18714                                    return Navigated::No;
18715                                }
18716
18717                                target_editor.change_selections(
18718                                    SelectionEffects::default().nav_history(true),
18719                                    window,
18720                                    cx,
18721                                    |s| s.select_anchor_ranges(target_ranges),
18722                                );
18723
18724                                let nav_data = target_editor.navigation_data(
18725                                    target_editor.selections.newest_anchor().head(),
18726                                    cx,
18727                                );
18728                                let target =
18729                                    Some(nav_history.navigation_entry(Some(
18730                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18731                                    )));
18732                                nav_history.push_tag(origin, target);
18733                                pane.update(cx, |pane, _| pane.enable_history());
18734                                Navigated::Yes
18735                            });
18736                        });
18737                    }
18738                    Navigated::Yes
18739                })
18740            }
18741        })
18742    }
18743
18744    fn compute_target_location(
18745        &self,
18746        lsp_location: lsp::Location,
18747        server_id: LanguageServerId,
18748        window: &mut Window,
18749        cx: &mut Context<Self>,
18750    ) -> Task<anyhow::Result<Option<Location>>> {
18751        let Some(project) = self.project.clone() else {
18752            return Task::ready(Ok(None));
18753        };
18754
18755        cx.spawn_in(window, async move |editor, cx| {
18756            let location_task = editor.update(cx, |_, cx| {
18757                project.update(cx, |project, cx| {
18758                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18759                })
18760            })?;
18761            let location = Some({
18762                let target_buffer_handle = location_task.await.context("open local buffer")?;
18763                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18764                    let target_start = target_buffer
18765                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18766                    let target_end = target_buffer
18767                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18768                    target_buffer.anchor_after(target_start)
18769                        ..target_buffer.anchor_before(target_end)
18770                });
18771                Location {
18772                    buffer: target_buffer_handle,
18773                    range,
18774                }
18775            });
18776            Ok(location)
18777        })
18778    }
18779
18780    fn go_to_next_reference(
18781        &mut self,
18782        _: &GoToNextReference,
18783        window: &mut Window,
18784        cx: &mut Context<Self>,
18785    ) {
18786        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18787        if let Some(task) = task {
18788            task.detach();
18789        };
18790    }
18791
18792    fn go_to_prev_reference(
18793        &mut self,
18794        _: &GoToPreviousReference,
18795        window: &mut Window,
18796        cx: &mut Context<Self>,
18797    ) {
18798        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18799        if let Some(task) = task {
18800            task.detach();
18801        };
18802    }
18803
18804    fn go_to_symbol_by_offset(
18805        &mut self,
18806        window: &mut Window,
18807        cx: &mut Context<Self>,
18808        offset: i8,
18809    ) -> Task<Result<()>> {
18810        let editor_snapshot = self.snapshot(window, cx);
18811
18812        // We don't care about multi-buffer symbols
18813        if !editor_snapshot.is_singleton() {
18814            return Task::ready(Ok(()));
18815        }
18816
18817        let cursor_offset = self
18818            .selections
18819            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18820            .head();
18821
18822        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18823            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18824                let buffer = ed.buffer.read(cx).as_singleton()?;
18825                Some(buffer.read(cx).remote_id())
18826            }) else {
18827                return Ok(());
18828            };
18829
18830            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18831            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18832
18833            let multi_snapshot = editor_snapshot.buffer();
18834            let buffer_range = |range: &Range<_>| {
18835                Some(
18836                    multi_snapshot
18837                        .buffer_anchor_range_to_anchor_range(range.clone())?
18838                        .to_offset(multi_snapshot),
18839                )
18840            };
18841
18842            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18843                let current_idx = outline_items
18844                    .iter()
18845                    .enumerate()
18846                    .filter_map(|(idx, item)| {
18847                        // Find the closest outline item by distance between outline text and cursor location
18848                        let source_range = buffer_range(&item.source_range_for_text)?;
18849                        let distance_to_closest_endpoint = cmp::min(
18850                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18851                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18852                        );
18853
18854                        let item_towards_offset =
18855                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18856                                == (offset as isize).signum();
18857
18858                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18859
18860                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18861                        // we should not already be within the outline's source range. We then pick the closest outline
18862                        // item.
18863                        (item_towards_offset && !source_range_contains_cursor)
18864                            .then_some((distance_to_closest_endpoint, idx))
18865                    })
18866                    .min()
18867                    .map(|(_, idx)| idx);
18868
18869                let Some(idx) = current_idx else {
18870                    return;
18871                };
18872
18873                let Some(range) = buffer_range(&outline_items[idx].source_range_for_text) else {
18874                    return;
18875                };
18876                let selection = [range.start..range.start];
18877
18878                let _ = editor
18879                    .update(acx, |editor, ecx| {
18880                        editor.change_selections(
18881                            SelectionEffects::scroll(Autoscroll::newest()),
18882                            window,
18883                            ecx,
18884                            |s| s.select_ranges(selection),
18885                        );
18886                    })
18887                    .ok();
18888            })?;
18889
18890            Ok(())
18891        })
18892    }
18893
18894    fn go_to_next_symbol(
18895        &mut self,
18896        _: &GoToNextSymbol,
18897        window: &mut Window,
18898        cx: &mut Context<Self>,
18899    ) {
18900        self.go_to_symbol_by_offset(window, cx, 1).detach();
18901    }
18902
18903    fn go_to_previous_symbol(
18904        &mut self,
18905        _: &GoToPreviousSymbol,
18906        window: &mut Window,
18907        cx: &mut Context<Self>,
18908    ) {
18909        self.go_to_symbol_by_offset(window, cx, -1).detach();
18910    }
18911
18912    pub fn go_to_reference_before_or_after_position(
18913        &mut self,
18914        direction: Direction,
18915        count: usize,
18916        window: &mut Window,
18917        cx: &mut Context<Self>,
18918    ) -> Option<Task<Result<()>>> {
18919        let selection = self.selections.newest_anchor();
18920        let head = selection.head();
18921
18922        let multi_buffer = self.buffer.read(cx);
18923
18924        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18925        let workspace = self.workspace()?;
18926        let project = workspace.read(cx).project().clone();
18927        let references =
18928            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18929        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18930            let Some(locations) = references.await? else {
18931                return Ok(());
18932            };
18933
18934            if locations.is_empty() {
18935                // totally normal - the cursor may be on something which is not
18936                // a symbol (e.g. a keyword)
18937                log::info!("no references found under cursor");
18938                return Ok(());
18939            }
18940
18941            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18942
18943            let (locations, current_location_index) =
18944                multi_buffer.update(cx, |multi_buffer, cx| {
18945                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18946                    let mut locations = locations
18947                        .into_iter()
18948                        .filter_map(|loc| {
18949                            let start = multi_buffer_snapshot.anchor_in_excerpt(loc.range.start)?;
18950                            let end = multi_buffer_snapshot.anchor_in_excerpt(loc.range.end)?;
18951                            Some(start..end)
18952                        })
18953                        .collect::<Vec<_>>();
18954                    // There is an O(n) implementation, but given this list will be
18955                    // small (usually <100 items), the extra O(log(n)) factor isn't
18956                    // worth the (surprisingly large amount of) extra complexity.
18957                    locations
18958                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18959
18960                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18961
18962                    let current_location_index = locations.iter().position(|loc| {
18963                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18964                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18965                    });
18966
18967                    (locations, current_location_index)
18968                });
18969
18970            let Some(current_location_index) = current_location_index else {
18971                // This indicates something has gone wrong, because we already
18972                // handle the "no references" case above
18973                log::error!(
18974                    "failed to find current reference under cursor. Total references: {}",
18975                    locations.len()
18976                );
18977                return Ok(());
18978            };
18979
18980            let destination_location_index = match direction {
18981                Direction::Next => (current_location_index + count) % locations.len(),
18982                Direction::Prev => {
18983                    (current_location_index + locations.len() - count % locations.len())
18984                        % locations.len()
18985                }
18986            };
18987
18988            // TODO(cameron): is this needed?
18989            // the thinking is to avoid "jumping to the current location" (avoid
18990            // polluting "jumplist" in vim terms)
18991            if current_location_index == destination_location_index {
18992                return Ok(());
18993            }
18994
18995            let Range { start, end } = locations[destination_location_index];
18996
18997            editor.update_in(cx, |editor, window, cx| {
18998                let effects = SelectionEffects::default();
18999
19000                editor.unfold_ranges(&[start..end], false, false, cx);
19001                editor.change_selections(effects, window, cx, |s| {
19002                    s.select_ranges([start..start]);
19003                });
19004            })?;
19005
19006            Ok(())
19007        }))
19008    }
19009
19010    pub fn find_all_references(
19011        &mut self,
19012        action: &FindAllReferences,
19013        window: &mut Window,
19014        cx: &mut Context<Self>,
19015    ) -> Option<Task<Result<Navigated>>> {
19016        let always_open_multibuffer = action.always_open_multibuffer;
19017        let selection = self.selections.newest_anchor();
19018        let multi_buffer = self.buffer.read(cx);
19019        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19020        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
19021        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
19022        let head = selection_offset.head();
19023
19024        let head_anchor = multi_buffer_snapshot.anchor_at(
19025            head,
19026            if head < selection_offset.tail() {
19027                Bias::Right
19028            } else {
19029                Bias::Left
19030            },
19031        );
19032
19033        match self
19034            .find_all_references_task_sources
19035            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
19036        {
19037            Ok(_) => {
19038                log::info!(
19039                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
19040                );
19041                return None;
19042            }
19043            Err(i) => {
19044                self.find_all_references_task_sources.insert(i, head_anchor);
19045            }
19046        }
19047
19048        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
19049        let workspace = self.workspace()?;
19050        let project = workspace.read(cx).project().clone();
19051        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
19052        Some(cx.spawn_in(window, async move |editor, cx| {
19053            let _cleanup = cx.on_drop(&editor, move |editor, _| {
19054                if let Ok(i) = editor
19055                    .find_all_references_task_sources
19056                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
19057                {
19058                    editor.find_all_references_task_sources.remove(i);
19059                }
19060            });
19061
19062            let Some(locations) = references.await? else {
19063                return anyhow::Ok(Navigated::No);
19064            };
19065            let mut locations = cx.update(|_, cx| {
19066                locations
19067                    .into_iter()
19068                    .map(|location| {
19069                        let buffer = location.buffer.read(cx);
19070                        (location.buffer, location.range.to_point(buffer))
19071                    })
19072                    // if special-casing the single-match case, remove ranges
19073                    // that intersect current selection
19074                    .filter(|(location_buffer, location)| {
19075                        if always_open_multibuffer || &buffer != location_buffer {
19076                            return true;
19077                        }
19078
19079                        !location.contains_inclusive(&selection_point.range())
19080                    })
19081                    .into_group_map()
19082            })?;
19083            if locations.is_empty() {
19084                return anyhow::Ok(Navigated::No);
19085            }
19086            for ranges in locations.values_mut() {
19087                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
19088                ranges.dedup();
19089            }
19090            let mut num_locations = 0;
19091            for ranges in locations.values_mut() {
19092                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
19093                ranges.dedup();
19094                num_locations += ranges.len();
19095            }
19096
19097            if num_locations == 1 && !always_open_multibuffer {
19098                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
19099                let target_range = target_ranges.first().unwrap().clone();
19100
19101                return editor.update_in(cx, |editor, window, cx| {
19102                    let range = target_range.to_point(target_buffer.read(cx));
19103                    let range = editor.range_for_match(&range);
19104                    let range = range.start..range.start;
19105
19106                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
19107                        editor.go_to_singleton_buffer_range(range, window, cx);
19108                    } else {
19109                        let pane = workspace.read(cx).active_pane().clone();
19110                        window.defer(cx, move |window, cx| {
19111                            let target_editor: Entity<Self> =
19112                                workspace.update(cx, |workspace, cx| {
19113                                    let pane = workspace.active_pane().clone();
19114
19115                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
19116                                    let keep_old_preview = preview_tabs_settings
19117                                        .enable_keep_preview_on_code_navigation;
19118                                    let allow_new_preview = preview_tabs_settings
19119                                        .enable_preview_file_from_code_navigation;
19120
19121                                    workspace.open_project_item(
19122                                        pane,
19123                                        target_buffer.clone(),
19124                                        true,
19125                                        true,
19126                                        keep_old_preview,
19127                                        allow_new_preview,
19128                                        window,
19129                                        cx,
19130                                    )
19131                                });
19132                            target_editor.update(cx, |target_editor, cx| {
19133                                // When selecting a definition in a different buffer, disable the nav history
19134                                // to avoid creating a history entry at the previous cursor location.
19135                                pane.update(cx, |pane, _| pane.disable_history());
19136                                target_editor.go_to_singleton_buffer_range(range, window, cx);
19137                                pane.update(cx, |pane, _| pane.enable_history());
19138                            });
19139                        });
19140                    }
19141                    Navigated::No
19142                });
19143            }
19144
19145            workspace.update_in(cx, |workspace, window, cx| {
19146                let target = locations
19147                    .iter()
19148                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
19149                    .map(|(buffer, location)| {
19150                        buffer
19151                            .read(cx)
19152                            .text_for_range(location.clone())
19153                            .collect::<String>()
19154                    })
19155                    .filter(|text| !text.contains('\n'))
19156                    .unique()
19157                    .take(3)
19158                    .join(", ");
19159                let title = if target.is_empty() {
19160                    "References".to_owned()
19161                } else {
19162                    format!("References to {target}")
19163                };
19164                let allow_preview = PreviewTabsSettings::get_global(cx)
19165                    .enable_preview_multibuffer_from_code_navigation;
19166                Self::open_locations_in_multibuffer(
19167                    workspace,
19168                    locations,
19169                    title,
19170                    false,
19171                    allow_preview,
19172                    MultibufferSelectionMode::First,
19173                    window,
19174                    cx,
19175                );
19176                Navigated::Yes
19177            })
19178        }))
19179    }
19180
19181    /// Opens a multibuffer with the given project locations in it.
19182    pub fn open_locations_in_multibuffer(
19183        workspace: &mut Workspace,
19184        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
19185        title: String,
19186        split: bool,
19187        allow_preview: bool,
19188        multibuffer_selection_mode: MultibufferSelectionMode,
19189        window: &mut Window,
19190        cx: &mut Context<Workspace>,
19191    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
19192        if locations.is_empty() {
19193            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
19194            return None;
19195        }
19196
19197        let capability = workspace.project().read(cx).capability();
19198        let mut ranges = <Vec<Range<Anchor>>>::new();
19199
19200        // a key to find existing multibuffer editors with the same set of locations
19201        // to prevent us from opening more and more multibuffer tabs for searches and the like
19202        let mut key = (title.clone(), vec![]);
19203        let excerpt_buffer = cx.new(|cx| {
19204            let key = &mut key.1;
19205            let mut multibuffer = MultiBuffer::new(capability);
19206            for (buffer, mut ranges_for_buffer) in locations {
19207                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
19208                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
19209                multibuffer.set_excerpts_for_path(
19210                    PathKey::for_buffer(&buffer, cx),
19211                    buffer.clone(),
19212                    ranges_for_buffer.clone(),
19213                    multibuffer_context_lines(cx),
19214                    cx,
19215                );
19216                let snapshot = multibuffer.snapshot(cx);
19217                let buffer_snapshot = buffer.read(cx).snapshot();
19218                ranges.extend(ranges_for_buffer.into_iter().filter_map(|range| {
19219                    let text_range = buffer_snapshot.anchor_range_inside(range);
19220                    let start = snapshot.anchor_in_buffer(text_range.start)?;
19221                    let end = snapshot.anchor_in_buffer(text_range.end)?;
19222                    Some(start..end)
19223                }))
19224            }
19225
19226            multibuffer.with_title(title)
19227        });
19228        let existing = workspace.active_pane().update(cx, |pane, cx| {
19229            pane.items()
19230                .filter_map(|item| item.downcast::<Editor>())
19231                .find(|editor| {
19232                    editor
19233                        .read(cx)
19234                        .lookup_key
19235                        .as_ref()
19236                        .and_then(|it| {
19237                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
19238                        })
19239                        .is_some_and(|it| *it == key)
19240                })
19241        });
19242        let was_existing = existing.is_some();
19243        let editor = existing.unwrap_or_else(|| {
19244            cx.new(|cx| {
19245                let mut editor = Editor::for_multibuffer(
19246                    excerpt_buffer,
19247                    Some(workspace.project().clone()),
19248                    window,
19249                    cx,
19250                );
19251                editor.lookup_key = Some(Box::new(key));
19252                editor
19253            })
19254        });
19255        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
19256            MultibufferSelectionMode::First => {
19257                if let Some(first_range) = ranges.first() {
19258                    editor.change_selections(
19259                        SelectionEffects::no_scroll(),
19260                        window,
19261                        cx,
19262                        |selections| {
19263                            selections.clear_disjoint();
19264                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
19265                        },
19266                    );
19267                }
19268                editor.highlight_background(
19269                    HighlightKey::Editor,
19270                    &ranges,
19271                    |_, theme| theme.colors().editor_highlighted_line_background,
19272                    cx,
19273                );
19274            }
19275            MultibufferSelectionMode::All => {
19276                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
19277                    selections.clear_disjoint();
19278                    selections.select_anchor_ranges(ranges);
19279                });
19280            }
19281        });
19282
19283        let item = Box::new(editor.clone());
19284
19285        let pane = if split {
19286            workspace.adjacent_pane(window, cx)
19287        } else {
19288            workspace.active_pane().clone()
19289        };
19290        let activate_pane = split;
19291
19292        let mut destination_index = None;
19293        pane.update(cx, |pane, cx| {
19294            if allow_preview && !was_existing {
19295                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
19296            }
19297            if was_existing && !allow_preview {
19298                pane.unpreview_item_if_preview(item.item_id());
19299            }
19300            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19301        });
19302
19303        Some((editor, pane))
19304    }
19305
19306    pub fn rename(
19307        &mut self,
19308        _: &Rename,
19309        window: &mut Window,
19310        cx: &mut Context<Self>,
19311    ) -> Option<Task<Result<()>>> {
19312        use language::ToOffset as _;
19313
19314        let provider = self.semantics_provider.clone()?;
19315        let selection = self.selections.newest_anchor().clone();
19316        let (cursor_buffer, cursor_buffer_position) = self
19317            .buffer
19318            .read(cx)
19319            .text_anchor_for_position(selection.head(), cx)?;
19320        let (tail_buffer, cursor_buffer_position_end) = self
19321            .buffer
19322            .read(cx)
19323            .text_anchor_for_position(selection.tail(), cx)?;
19324        if tail_buffer != cursor_buffer {
19325            return None;
19326        }
19327
19328        let snapshot = cursor_buffer.read(cx).snapshot();
19329        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19330        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19331        let prepare_rename = provider.range_for_rename(&cursor_buffer, cursor_buffer_position, cx);
19332        drop(snapshot);
19333
19334        Some(cx.spawn_in(window, async move |this, cx| {
19335            let rename_range = prepare_rename.await?;
19336            if let Some(rename_range) = rename_range {
19337                this.update_in(cx, |this, window, cx| {
19338                    let snapshot = cursor_buffer.read(cx).snapshot();
19339                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19340                    let cursor_offset_in_rename_range =
19341                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19342                    let cursor_offset_in_rename_range_end =
19343                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19344
19345                    this.take_rename(false, window, cx);
19346                    let buffer = this.buffer.read(cx).read(cx);
19347                    let cursor_offset = selection.head().to_offset(&buffer);
19348                    let rename_start =
19349                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19350                    let rename_end = rename_start + rename_buffer_range.len();
19351                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19352                    let mut old_highlight_id = None;
19353                    let old_name: Arc<str> = buffer
19354                        .chunks(
19355                            rename_start..rename_end,
19356                            LanguageAwareStyling {
19357                                tree_sitter: true,
19358                                diagnostics: true,
19359                            },
19360                        )
19361                        .map(|chunk| {
19362                            if old_highlight_id.is_none() {
19363                                old_highlight_id = chunk.syntax_highlight_id;
19364                            }
19365                            chunk.text
19366                        })
19367                        .collect::<String>()
19368                        .into();
19369
19370                    drop(buffer);
19371
19372                    // Position the selection in the rename editor so that it matches the current selection.
19373                    this.show_local_selections = false;
19374                    let rename_editor = cx.new(|cx| {
19375                        let mut editor = Editor::single_line(window, cx);
19376                        editor.buffer.update(cx, |buffer, cx| {
19377                            buffer.edit(
19378                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19379                                None,
19380                                cx,
19381                            )
19382                        });
19383                        let cursor_offset_in_rename_range =
19384                            MultiBufferOffset(cursor_offset_in_rename_range);
19385                        let cursor_offset_in_rename_range_end =
19386                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19387                        let rename_selection_range = match cursor_offset_in_rename_range
19388                            .cmp(&cursor_offset_in_rename_range_end)
19389                        {
19390                            Ordering::Equal => {
19391                                editor.select_all(&SelectAll, window, cx);
19392                                return editor;
19393                            }
19394                            Ordering::Less => {
19395                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19396                            }
19397                            Ordering::Greater => {
19398                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19399                            }
19400                        };
19401                        if rename_selection_range.end.0 > old_name.len() {
19402                            editor.select_all(&SelectAll, window, cx);
19403                        } else {
19404                            editor.change_selections(Default::default(), window, cx, |s| {
19405                                s.select_ranges([rename_selection_range]);
19406                            });
19407                        }
19408                        editor
19409                    });
19410                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19411                        if e == &EditorEvent::Focused {
19412                            cx.emit(EditorEvent::FocusedIn)
19413                        }
19414                    })
19415                    .detach();
19416
19417                    let write_highlights =
19418                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19419                    let read_highlights =
19420                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19421                    let ranges = write_highlights
19422                        .iter()
19423                        .flat_map(|(_, ranges)| ranges.iter())
19424                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19425                        .cloned()
19426                        .collect();
19427
19428                    this.highlight_text(
19429                        HighlightKey::Rename,
19430                        ranges,
19431                        HighlightStyle {
19432                            fade_out: Some(0.6),
19433                            ..Default::default()
19434                        },
19435                        cx,
19436                    );
19437                    let rename_focus_handle = rename_editor.focus_handle(cx);
19438                    window.focus(&rename_focus_handle, cx);
19439                    let block_id = this.insert_blocks(
19440                        [BlockProperties {
19441                            style: BlockStyle::Flex,
19442                            placement: BlockPlacement::Below(range.start),
19443                            height: Some(1),
19444                            render: Arc::new({
19445                                let rename_editor = rename_editor.clone();
19446                                move |cx: &mut BlockContext| {
19447                                    let mut text_style = cx.editor_style.text.clone();
19448                                    if let Some(highlight_style) = old_highlight_id
19449                                        .and_then(|h| cx.editor_style.syntax.get(h).cloned())
19450                                    {
19451                                        text_style = text_style.highlight(highlight_style);
19452                                    }
19453                                    div()
19454                                        .block_mouse_except_scroll()
19455                                        .pl(cx.anchor_x)
19456                                        .child(EditorElement::new(
19457                                            &rename_editor,
19458                                            EditorStyle {
19459                                                background: cx.theme().system().transparent,
19460                                                local_player: cx.editor_style.local_player,
19461                                                text: text_style,
19462                                                scrollbar_width: cx.editor_style.scrollbar_width,
19463                                                syntax: cx.editor_style.syntax.clone(),
19464                                                status: cx.editor_style.status.clone(),
19465                                                inlay_hints_style: HighlightStyle {
19466                                                    font_weight: Some(FontWeight::BOLD),
19467                                                    ..make_inlay_hints_style(cx.app)
19468                                                },
19469                                                edit_prediction_styles: make_suggestion_styles(
19470                                                    cx.app,
19471                                                ),
19472                                                ..EditorStyle::default()
19473                                            },
19474                                        ))
19475                                        .into_any_element()
19476                                }
19477                            }),
19478                            priority: 0,
19479                        }],
19480                        Some(Autoscroll::fit()),
19481                        cx,
19482                    )[0];
19483                    this.pending_rename = Some(RenameState {
19484                        range,
19485                        old_name,
19486                        editor: rename_editor,
19487                        block_id,
19488                    });
19489                })?;
19490            }
19491
19492            Ok(())
19493        }))
19494    }
19495
19496    pub fn confirm_rename(
19497        &mut self,
19498        _: &ConfirmRename,
19499        window: &mut Window,
19500        cx: &mut Context<Self>,
19501    ) -> Option<Task<Result<()>>> {
19502        let rename = self.take_rename(false, window, cx)?;
19503        let workspace = self.workspace()?.downgrade();
19504        let (buffer, start) = self
19505            .buffer
19506            .read(cx)
19507            .text_anchor_for_position(rename.range.start, cx)?;
19508        let (end_buffer, _) = self
19509            .buffer
19510            .read(cx)
19511            .text_anchor_for_position(rename.range.end, cx)?;
19512        if buffer != end_buffer {
19513            return None;
19514        }
19515
19516        let old_name = rename.old_name;
19517        let new_name = rename.editor.read(cx).text(cx);
19518
19519        let rename = self.semantics_provider.as_ref()?.perform_rename(
19520            &buffer,
19521            start,
19522            new_name.clone(),
19523            cx,
19524        )?;
19525
19526        Some(cx.spawn_in(window, async move |editor, cx| {
19527            let project_transaction = rename.await?;
19528            Self::open_project_transaction(
19529                &editor,
19530                workspace,
19531                project_transaction,
19532                format!("Rename: {}{}", old_name, new_name),
19533                cx,
19534            )
19535            .await?;
19536
19537            editor.update(cx, |editor, cx| {
19538                editor.refresh_document_highlights(cx);
19539            })?;
19540            Ok(())
19541        }))
19542    }
19543
19544    fn take_rename(
19545        &mut self,
19546        moving_cursor: bool,
19547        window: &mut Window,
19548        cx: &mut Context<Self>,
19549    ) -> Option<RenameState> {
19550        let rename = self.pending_rename.take()?;
19551        if rename.editor.focus_handle(cx).is_focused(window) {
19552            window.focus(&self.focus_handle, cx);
19553        }
19554
19555        self.remove_blocks(
19556            [rename.block_id].into_iter().collect(),
19557            Some(Autoscroll::fit()),
19558            cx,
19559        );
19560        self.clear_highlights(HighlightKey::Rename, cx);
19561        self.show_local_selections = true;
19562
19563        if moving_cursor {
19564            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19565                editor
19566                    .selections
19567                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19568                    .head()
19569            });
19570
19571            // Update the selection to match the position of the selection inside
19572            // the rename editor.
19573            let snapshot = self.buffer.read(cx).read(cx);
19574            let rename_range = rename.range.to_offset(&snapshot);
19575            let cursor_in_editor = snapshot
19576                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19577                .min(rename_range.end);
19578            drop(snapshot);
19579
19580            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19581                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19582            });
19583        } else {
19584            self.refresh_document_highlights(cx);
19585        }
19586
19587        Some(rename)
19588    }
19589
19590    pub fn pending_rename(&self) -> Option<&RenameState> {
19591        self.pending_rename.as_ref()
19592    }
19593
19594    fn format(
19595        &mut self,
19596        _: &Format,
19597        window: &mut Window,
19598        cx: &mut Context<Self>,
19599    ) -> Option<Task<Result<()>>> {
19600        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19601
19602        let project = match &self.project {
19603            Some(project) => project.clone(),
19604            None => return None,
19605        };
19606
19607        Some(self.perform_format(
19608            project,
19609            FormatTrigger::Manual,
19610            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19611            window,
19612            cx,
19613        ))
19614    }
19615
19616    fn format_selections(
19617        &mut self,
19618        _: &FormatSelections,
19619        window: &mut Window,
19620        cx: &mut Context<Self>,
19621    ) -> Option<Task<Result<()>>> {
19622        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19623
19624        let project = match &self.project {
19625            Some(project) => project.clone(),
19626            None => return None,
19627        };
19628
19629        let ranges = self
19630            .selections
19631            .all_adjusted(&self.display_snapshot(cx))
19632            .into_iter()
19633            .map(|selection| selection.range())
19634            .collect_vec();
19635
19636        Some(self.perform_format(
19637            project,
19638            FormatTrigger::Manual,
19639            FormatTarget::Ranges(ranges),
19640            window,
19641            cx,
19642        ))
19643    }
19644
19645    fn perform_format(
19646        &mut self,
19647        project: Entity<Project>,
19648        trigger: FormatTrigger,
19649        target: FormatTarget,
19650        window: &mut Window,
19651        cx: &mut Context<Self>,
19652    ) -> Task<Result<()>> {
19653        let buffer = self.buffer.clone();
19654        let (buffers, target) = match target {
19655            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19656            FormatTarget::Ranges(selection_ranges) => {
19657                let multi_buffer = buffer.read(cx);
19658                let snapshot = multi_buffer.read(cx);
19659                let mut buffers = HashSet::default();
19660                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19661                    BTreeMap::new();
19662                for selection_range in selection_ranges {
19663                    for (buffer_snapshot, buffer_range, _) in
19664                        snapshot.range_to_buffer_ranges(selection_range.start..selection_range.end)
19665                    {
19666                        let buffer_id = buffer_snapshot.remote_id();
19667                        let start = buffer_snapshot.anchor_before(buffer_range.start);
19668                        let end = buffer_snapshot.anchor_after(buffer_range.end);
19669                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19670                        buffer_id_to_ranges
19671                            .entry(buffer_id)
19672                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19673                            .or_insert_with(|| vec![start..end]);
19674                    }
19675                }
19676                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19677            }
19678        };
19679
19680        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19681        let selections_prev = transaction_id_prev
19682            .and_then(|transaction_id_prev| {
19683                // default to selections as they were after the last edit, if we have them,
19684                // instead of how they are now.
19685                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19686                // will take you back to where you made the last edit, instead of staying where you scrolled
19687                self.selection_history
19688                    .transaction(transaction_id_prev)
19689                    .map(|t| t.0.clone())
19690            })
19691            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19692
19693        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19694        let format = project.update(cx, |project, cx| {
19695            project.format(buffers, target, true, trigger, cx)
19696        });
19697
19698        cx.spawn_in(window, async move |editor, cx| {
19699            let transaction = futures::select_biased! {
19700                transaction = format.log_err().fuse() => transaction,
19701                () = timeout => {
19702                    log::warn!("timed out waiting for formatting");
19703                    None
19704                }
19705            };
19706
19707            buffer.update(cx, |buffer, cx| {
19708                if let Some(transaction) = transaction
19709                    && !buffer.is_singleton()
19710                {
19711                    buffer.push_transaction(&transaction.0, cx);
19712                }
19713                cx.notify();
19714            });
19715
19716            if let Some(transaction_id_now) =
19717                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19718            {
19719                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19720                if has_new_transaction {
19721                    editor
19722                        .update(cx, |editor, _| {
19723                            editor
19724                                .selection_history
19725                                .insert_transaction(transaction_id_now, selections_prev);
19726                        })
19727                        .ok();
19728                }
19729            }
19730
19731            Ok(())
19732        })
19733    }
19734
19735    fn organize_imports(
19736        &mut self,
19737        _: &OrganizeImports,
19738        window: &mut Window,
19739        cx: &mut Context<Self>,
19740    ) -> Option<Task<Result<()>>> {
19741        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19742        let project = match &self.project {
19743            Some(project) => project.clone(),
19744            None => return None,
19745        };
19746        Some(self.perform_code_action_kind(
19747            project,
19748            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19749            window,
19750            cx,
19751        ))
19752    }
19753
19754    fn perform_code_action_kind(
19755        &mut self,
19756        project: Entity<Project>,
19757        kind: CodeActionKind,
19758        window: &mut Window,
19759        cx: &mut Context<Self>,
19760    ) -> Task<Result<()>> {
19761        let buffer = self.buffer.clone();
19762        let buffers = buffer.read(cx).all_buffers();
19763        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19764        let apply_action = project.update(cx, |project, cx| {
19765            project.apply_code_action_kind(buffers, kind, true, cx)
19766        });
19767        cx.spawn_in(window, async move |_, cx| {
19768            let transaction = futures::select_biased! {
19769                () = timeout => {
19770                    log::warn!("timed out waiting for executing code action");
19771                    None
19772                }
19773                transaction = apply_action.log_err().fuse() => transaction,
19774            };
19775            buffer.update(cx, |buffer, cx| {
19776                // check if we need this
19777                if let Some(transaction) = transaction
19778                    && !buffer.is_singleton()
19779                {
19780                    buffer.push_transaction(&transaction.0, cx);
19781                }
19782                cx.notify();
19783            });
19784            Ok(())
19785        })
19786    }
19787
19788    pub fn restart_language_server(
19789        &mut self,
19790        _: &RestartLanguageServer,
19791        _: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        if let Some(project) = self.project.clone() {
19795            self.buffer.update(cx, |multi_buffer, cx| {
19796                project.update(cx, |project, cx| {
19797                    project.restart_language_servers_for_buffers(
19798                        multi_buffer.all_buffers().into_iter().collect(),
19799                        HashSet::default(),
19800                        cx,
19801                    );
19802                });
19803            })
19804        }
19805    }
19806
19807    pub fn stop_language_server(
19808        &mut self,
19809        _: &StopLanguageServer,
19810        _: &mut Window,
19811        cx: &mut Context<Self>,
19812    ) {
19813        if let Some(project) = self.project.clone() {
19814            self.buffer.update(cx, |multi_buffer, cx| {
19815                project.update(cx, |project, cx| {
19816                    project.stop_language_servers_for_buffers(
19817                        multi_buffer.all_buffers().into_iter().collect(),
19818                        HashSet::default(),
19819                        cx,
19820                    );
19821                });
19822            });
19823        }
19824    }
19825
19826    fn cancel_language_server_work(
19827        workspace: &mut Workspace,
19828        _: &actions::CancelLanguageServerWork,
19829        _: &mut Window,
19830        cx: &mut Context<Workspace>,
19831    ) {
19832        let project = workspace.project();
19833        let buffers = workspace
19834            .active_item(cx)
19835            .and_then(|item| item.act_as::<Editor>(cx))
19836            .map_or(HashSet::default(), |editor| {
19837                editor.read(cx).buffer.read(cx).all_buffers()
19838            });
19839        project.update(cx, |project, cx| {
19840            project.cancel_language_server_work_for_buffers(buffers, cx);
19841        });
19842    }
19843
19844    fn show_character_palette(
19845        &mut self,
19846        _: &ShowCharacterPalette,
19847        window: &mut Window,
19848        _: &mut Context<Self>,
19849    ) {
19850        window.show_character_palette();
19851    }
19852
19853    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19854        if !self.diagnostics_enabled() {
19855            return;
19856        }
19857
19858        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19859            let buffer = self.buffer.read(cx).snapshot(cx);
19860            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19861            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19862            let is_valid = buffer
19863                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19864                .any(|entry| {
19865                    entry.diagnostic.is_primary
19866                        && !entry.range.is_empty()
19867                        && entry.range.start == primary_range_start
19868                        && entry.diagnostic.message == active_diagnostics.active_message
19869                });
19870
19871            if !is_valid {
19872                self.dismiss_diagnostics(cx);
19873            }
19874        }
19875    }
19876
19877    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19878        match &self.active_diagnostics {
19879            ActiveDiagnostic::Group(group) => Some(group),
19880            _ => None,
19881        }
19882    }
19883
19884    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19885        if !self.diagnostics_enabled() {
19886            return;
19887        }
19888        self.dismiss_diagnostics(cx);
19889        self.active_diagnostics = ActiveDiagnostic::All;
19890    }
19891
19892    fn activate_diagnostics(
19893        &mut self,
19894        buffer_id: BufferId,
19895        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19896        window: &mut Window,
19897        cx: &mut Context<Self>,
19898    ) {
19899        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19900            return;
19901        }
19902        self.dismiss_diagnostics(cx);
19903        let snapshot = self.snapshot(window, cx);
19904        let buffer = self.buffer.read(cx).snapshot(cx);
19905        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19906            return;
19907        };
19908
19909        let diagnostic_group = buffer
19910            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19911            .collect::<Vec<_>>();
19912
19913        let language_registry = self
19914            .project()
19915            .map(|project| project.read(cx).languages().clone());
19916
19917        let blocks = renderer.render_group(
19918            diagnostic_group,
19919            buffer_id,
19920            snapshot,
19921            cx.weak_entity(),
19922            language_registry,
19923            cx,
19924        );
19925
19926        let blocks = self.display_map.update(cx, |display_map, cx| {
19927            display_map.insert_blocks(blocks, cx).into_iter().collect()
19928        });
19929        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19930            active_range: buffer.anchor_before(diagnostic.range.start)
19931                ..buffer.anchor_after(diagnostic.range.end),
19932            active_message: diagnostic.diagnostic.message.clone(),
19933            group_id: diagnostic.diagnostic.group_id,
19934            blocks,
19935        });
19936        cx.notify();
19937    }
19938
19939    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19940        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19941            return;
19942        };
19943
19944        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19945        if let ActiveDiagnostic::Group(group) = prev {
19946            self.display_map.update(cx, |display_map, cx| {
19947                display_map.remove_blocks(group.blocks, cx);
19948            });
19949            cx.notify();
19950        }
19951    }
19952
19953    /// Disable inline diagnostics rendering for this editor.
19954    pub fn disable_inline_diagnostics(&mut self) {
19955        self.inline_diagnostics_enabled = false;
19956        self.inline_diagnostics_update = Task::ready(());
19957        self.inline_diagnostics.clear();
19958    }
19959
19960    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19961        self.diagnostics_enabled = false;
19962        self.dismiss_diagnostics(cx);
19963        self.inline_diagnostics_update = Task::ready(());
19964        self.inline_diagnostics.clear();
19965    }
19966
19967    pub fn disable_word_completions(&mut self) {
19968        self.word_completions_enabled = false;
19969    }
19970
19971    pub fn diagnostics_enabled(&self) -> bool {
19972        self.diagnostics_enabled && self.lsp_data_enabled()
19973    }
19974
19975    pub fn inline_diagnostics_enabled(&self) -> bool {
19976        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19977    }
19978
19979    pub fn show_inline_diagnostics(&self) -> bool {
19980        self.show_inline_diagnostics
19981    }
19982
19983    pub fn toggle_inline_diagnostics(
19984        &mut self,
19985        _: &ToggleInlineDiagnostics,
19986        window: &mut Window,
19987        cx: &mut Context<Editor>,
19988    ) {
19989        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19990        self.refresh_inline_diagnostics(false, window, cx);
19991    }
19992
19993    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19994        self.diagnostics_max_severity = severity;
19995        self.display_map.update(cx, |display_map, _| {
19996            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19997        });
19998    }
19999
20000    pub fn toggle_diagnostics(
20001        &mut self,
20002        _: &ToggleDiagnostics,
20003        window: &mut Window,
20004        cx: &mut Context<Editor>,
20005    ) {
20006        if !self.diagnostics_enabled() {
20007            return;
20008        }
20009
20010        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
20011            EditorSettings::get_global(cx)
20012                .diagnostics_max_severity
20013                .filter(|severity| severity != &DiagnosticSeverity::Off)
20014                .unwrap_or(DiagnosticSeverity::Hint)
20015        } else {
20016            DiagnosticSeverity::Off
20017        };
20018        self.set_max_diagnostics_severity(new_severity, cx);
20019        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
20020            self.active_diagnostics = ActiveDiagnostic::None;
20021            self.inline_diagnostics_update = Task::ready(());
20022            self.inline_diagnostics.clear();
20023        } else {
20024            self.refresh_inline_diagnostics(false, window, cx);
20025        }
20026
20027        cx.notify();
20028    }
20029
20030    pub fn toggle_minimap(
20031        &mut self,
20032        _: &ToggleMinimap,
20033        window: &mut Window,
20034        cx: &mut Context<Editor>,
20035    ) {
20036        if self.supports_minimap(cx) {
20037            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
20038        }
20039    }
20040
20041    fn refresh_inline_diagnostics(
20042        &mut self,
20043        debounce: bool,
20044        window: &mut Window,
20045        cx: &mut Context<Self>,
20046    ) {
20047        let max_severity = ProjectSettings::get_global(cx)
20048            .diagnostics
20049            .inline
20050            .max_severity
20051            .unwrap_or(self.diagnostics_max_severity);
20052
20053        if !self.inline_diagnostics_enabled()
20054            || !self.diagnostics_enabled()
20055            || !self.show_inline_diagnostics
20056            || max_severity == DiagnosticSeverity::Off
20057        {
20058            self.inline_diagnostics_update = Task::ready(());
20059            self.inline_diagnostics.clear();
20060            return;
20061        }
20062
20063        let debounce_ms = ProjectSettings::get_global(cx)
20064            .diagnostics
20065            .inline
20066            .update_debounce_ms;
20067        let debounce = if debounce && debounce_ms > 0 {
20068            Some(Duration::from_millis(debounce_ms))
20069        } else {
20070            None
20071        };
20072        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
20073            if let Some(debounce) = debounce {
20074                cx.background_executor().timer(debounce).await;
20075            }
20076            let Some(snapshot) = editor.upgrade().map(|editor| {
20077                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
20078            }) else {
20079                return;
20080            };
20081
20082            let new_inline_diagnostics = cx
20083                .background_spawn(async move {
20084                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
20085                    for diagnostic_entry in
20086                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
20087                    {
20088                        let message = diagnostic_entry
20089                            .diagnostic
20090                            .message
20091                            .split_once('\n')
20092                            .map(|(line, _)| line)
20093                            .map(SharedString::new)
20094                            .unwrap_or_else(|| {
20095                                SharedString::new(&*diagnostic_entry.diagnostic.message)
20096                            });
20097                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
20098                        let (Ok(i) | Err(i)) = inline_diagnostics
20099                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
20100                        inline_diagnostics.insert(
20101                            i,
20102                            (
20103                                start_anchor,
20104                                InlineDiagnostic {
20105                                    message,
20106                                    group_id: diagnostic_entry.diagnostic.group_id,
20107                                    start: diagnostic_entry.range.start.to_point(&snapshot),
20108                                    is_primary: diagnostic_entry.diagnostic.is_primary,
20109                                    severity: diagnostic_entry.diagnostic.severity,
20110                                },
20111                            ),
20112                        );
20113                    }
20114                    inline_diagnostics
20115                })
20116                .await;
20117
20118            editor
20119                .update(cx, |editor, cx| {
20120                    editor.inline_diagnostics = new_inline_diagnostics;
20121                    cx.notify();
20122                })
20123                .ok();
20124        });
20125    }
20126
20127    fn pull_diagnostics(
20128        &mut self,
20129        buffer_id: BufferId,
20130        _window: &Window,
20131        cx: &mut Context<Self>,
20132    ) -> Option<()> {
20133        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
20134        // skip any LSP updates for it.
20135
20136        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
20137            return None;
20138        }
20139        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
20140            .diagnostics
20141            .lsp_pull_diagnostics;
20142        if !pull_diagnostics_settings.enabled {
20143            return None;
20144        }
20145        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
20146        let project = self.project()?.downgrade();
20147        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
20148
20149        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
20150            cx.background_executor().timer(debounce).await;
20151            if let Ok(task) = project.update(cx, |project, cx| {
20152                project.lsp_store().update(cx, |lsp_store, cx| {
20153                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
20154                })
20155            }) {
20156                task.await.log_err();
20157            }
20158            project
20159                .update(cx, |project, cx| {
20160                    project.lsp_store().update(cx, |lsp_store, cx| {
20161                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
20162                    })
20163                })
20164                .log_err();
20165        });
20166
20167        Some(())
20168    }
20169
20170    pub fn set_selections_from_remote(
20171        &mut self,
20172        selections: Vec<Selection<Anchor>>,
20173        pending_selection: Option<Selection<Anchor>>,
20174        window: &mut Window,
20175        cx: &mut Context<Self>,
20176    ) {
20177        let old_cursor_position = self.selections.newest_anchor().head();
20178        self.selections
20179            .change_with(&self.display_snapshot(cx), |s| {
20180                s.select_anchors(selections);
20181                if let Some(pending_selection) = pending_selection {
20182                    s.set_pending(pending_selection, SelectMode::Character);
20183                } else {
20184                    s.clear_pending();
20185                }
20186            });
20187        self.selections_did_change(
20188            false,
20189            &old_cursor_position,
20190            SelectionEffects::default(),
20191            window,
20192            cx,
20193        );
20194    }
20195
20196    pub fn transact(
20197        &mut self,
20198        window: &mut Window,
20199        cx: &mut Context<Self>,
20200        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
20201    ) -> Option<TransactionId> {
20202        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
20203            this.start_transaction_at(Instant::now(), window, cx);
20204            update(this, window, cx);
20205            this.end_transaction_at(Instant::now(), cx)
20206        })
20207    }
20208
20209    pub fn start_transaction_at(
20210        &mut self,
20211        now: Instant,
20212        window: &mut Window,
20213        cx: &mut Context<Self>,
20214    ) -> Option<TransactionId> {
20215        self.end_selection(window, cx);
20216        if let Some(tx_id) = self
20217            .buffer
20218            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
20219        {
20220            self.selection_history
20221                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
20222            cx.emit(EditorEvent::TransactionBegun {
20223                transaction_id: tx_id,
20224            });
20225            Some(tx_id)
20226        } else {
20227            None
20228        }
20229    }
20230
20231    pub fn end_transaction_at(
20232        &mut self,
20233        now: Instant,
20234        cx: &mut Context<Self>,
20235    ) -> Option<TransactionId> {
20236        if let Some(transaction_id) = self
20237            .buffer
20238            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
20239        {
20240            if let Some((_, end_selections)) =
20241                self.selection_history.transaction_mut(transaction_id)
20242            {
20243                *end_selections = Some(self.selections.disjoint_anchors_arc());
20244            } else {
20245                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
20246            }
20247
20248            cx.emit(EditorEvent::Edited { transaction_id });
20249            Some(transaction_id)
20250        } else {
20251            None
20252        }
20253    }
20254
20255    pub fn modify_transaction_selection_history(
20256        &mut self,
20257        transaction_id: TransactionId,
20258        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
20259    ) -> bool {
20260        self.selection_history
20261            .transaction_mut(transaction_id)
20262            .map(modify)
20263            .is_some()
20264    }
20265
20266    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
20267        if self.selection_mark_mode {
20268            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20269                s.move_with(&mut |_, sel| {
20270                    sel.collapse_to(sel.head(), SelectionGoal::None);
20271                });
20272            })
20273        }
20274        self.selection_mark_mode = true;
20275        cx.notify();
20276    }
20277
20278    pub fn swap_selection_ends(
20279        &mut self,
20280        _: &actions::SwapSelectionEnds,
20281        window: &mut Window,
20282        cx: &mut Context<Self>,
20283    ) {
20284        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20285            s.move_with(&mut |_, sel| {
20286                if sel.start != sel.end {
20287                    sel.reversed = !sel.reversed
20288                }
20289            });
20290        });
20291        self.request_autoscroll(Autoscroll::newest(), cx);
20292        cx.notify();
20293    }
20294
20295    pub fn toggle_focus(
20296        workspace: &mut Workspace,
20297        _: &actions::ToggleFocus,
20298        window: &mut Window,
20299        cx: &mut Context<Workspace>,
20300    ) {
20301        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20302            return;
20303        };
20304        workspace.activate_item(&item, true, true, window, cx);
20305    }
20306
20307    pub fn toggle_fold(
20308        &mut self,
20309        _: &actions::ToggleFold,
20310        window: &mut Window,
20311        cx: &mut Context<Self>,
20312    ) {
20313        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20314            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20315            let selection = self.selections.newest::<Point>(&display_map);
20316
20317            let range = if selection.is_empty() {
20318                let point = selection.head().to_display_point(&display_map);
20319                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20320                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20321                    .to_point(&display_map);
20322                start..end
20323            } else {
20324                selection.range()
20325            };
20326            if display_map.folds_in_range(range).next().is_some() {
20327                self.unfold_lines(&Default::default(), window, cx)
20328            } else {
20329                self.fold(&Default::default(), window, cx)
20330            }
20331        } else {
20332            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20333            let buffer_ids: HashSet<_> = self
20334                .selections
20335                .disjoint_anchor_ranges()
20336                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20337                .collect();
20338
20339            let should_unfold = buffer_ids
20340                .iter()
20341                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20342
20343            for buffer_id in buffer_ids {
20344                if should_unfold {
20345                    self.unfold_buffer(buffer_id, cx);
20346                } else {
20347                    self.fold_buffer(buffer_id, cx);
20348                }
20349            }
20350        }
20351    }
20352
20353    pub fn toggle_fold_recursive(
20354        &mut self,
20355        _: &actions::ToggleFoldRecursive,
20356        window: &mut Window,
20357        cx: &mut Context<Self>,
20358    ) {
20359        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20360
20361        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20362        let range = if selection.is_empty() {
20363            let point = selection.head().to_display_point(&display_map);
20364            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20365            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20366                .to_point(&display_map);
20367            start..end
20368        } else {
20369            selection.range()
20370        };
20371        if display_map.folds_in_range(range).next().is_some() {
20372            self.unfold_recursive(&Default::default(), window, cx)
20373        } else {
20374            self.fold_recursive(&Default::default(), window, cx)
20375        }
20376    }
20377
20378    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20379        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20380            let mut to_fold = Vec::new();
20381            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20382            let selections = self.selections.all_adjusted(&display_map);
20383
20384            for selection in selections {
20385                let range = selection.range().sorted();
20386                let buffer_start_row = range.start.row;
20387
20388                if range.start.row != range.end.row {
20389                    let mut found = false;
20390                    let mut row = range.start.row;
20391                    while row <= range.end.row {
20392                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20393                        {
20394                            found = true;
20395                            row = crease.range().end.row + 1;
20396                            to_fold.push(crease);
20397                        } else {
20398                            row += 1
20399                        }
20400                    }
20401                    if found {
20402                        continue;
20403                    }
20404                }
20405
20406                for row in (0..=range.start.row).rev() {
20407                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20408                        && crease.range().end.row >= buffer_start_row
20409                    {
20410                        to_fold.push(crease);
20411                        if row <= range.start.row {
20412                            break;
20413                        }
20414                    }
20415                }
20416            }
20417
20418            self.fold_creases(to_fold, true, window, cx);
20419        } else {
20420            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20421            let buffer_ids = self
20422                .selections
20423                .disjoint_anchor_ranges()
20424                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20425                .collect::<HashSet<_>>();
20426            for buffer_id in buffer_ids {
20427                self.fold_buffer(buffer_id, cx);
20428            }
20429        }
20430    }
20431
20432    pub fn toggle_fold_all(
20433        &mut self,
20434        _: &actions::ToggleFoldAll,
20435        window: &mut Window,
20436        cx: &mut Context<Self>,
20437    ) {
20438        let has_folds = if self.buffer.read(cx).is_singleton() {
20439            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20440            let has_folds = display_map
20441                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20442                .next()
20443                .is_some();
20444            has_folds
20445        } else {
20446            let snapshot = self.buffer.read(cx).snapshot(cx);
20447            let has_folds = snapshot
20448                .all_buffer_ids()
20449                .any(|buffer_id| self.is_buffer_folded(buffer_id, cx));
20450            has_folds
20451        };
20452
20453        if has_folds {
20454            self.unfold_all(&actions::UnfoldAll, window, cx);
20455        } else {
20456            self.fold_all(&actions::FoldAll, window, cx);
20457        }
20458    }
20459
20460    fn fold_at_level(
20461        &mut self,
20462        fold_at: &FoldAtLevel,
20463        window: &mut Window,
20464        cx: &mut Context<Self>,
20465    ) {
20466        if !self.buffer.read(cx).is_singleton() {
20467            return;
20468        }
20469
20470        let fold_at_level = fold_at.0;
20471        let snapshot = self.buffer.read(cx).snapshot(cx);
20472        let mut to_fold = Vec::new();
20473        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20474
20475        let row_ranges_to_keep: Vec<Range<u32>> = self
20476            .selections
20477            .all::<Point>(&self.display_snapshot(cx))
20478            .into_iter()
20479            .map(|sel| sel.start.row..sel.end.row)
20480            .collect();
20481
20482        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20483            while start_row < end_row {
20484                match self
20485                    .snapshot(window, cx)
20486                    .crease_for_buffer_row(MultiBufferRow(start_row))
20487                {
20488                    Some(crease) => {
20489                        let nested_start_row = crease.range().start.row + 1;
20490                        let nested_end_row = crease.range().end.row;
20491
20492                        if current_level < fold_at_level {
20493                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20494                        } else if current_level == fold_at_level {
20495                            // Fold iff there is no selection completely contained within the fold region
20496                            if !row_ranges_to_keep.iter().any(|selection| {
20497                                selection.end >= nested_start_row
20498                                    && selection.start <= nested_end_row
20499                            }) {
20500                                to_fold.push(crease);
20501                            }
20502                        }
20503
20504                        start_row = nested_end_row + 1;
20505                    }
20506                    None => start_row += 1,
20507                }
20508            }
20509        }
20510
20511        self.fold_creases(to_fold, true, window, cx);
20512    }
20513
20514    pub fn fold_at_level_1(
20515        &mut self,
20516        _: &actions::FoldAtLevel1,
20517        window: &mut Window,
20518        cx: &mut Context<Self>,
20519    ) {
20520        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20521    }
20522
20523    pub fn fold_at_level_2(
20524        &mut self,
20525        _: &actions::FoldAtLevel2,
20526        window: &mut Window,
20527        cx: &mut Context<Self>,
20528    ) {
20529        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20530    }
20531
20532    pub fn fold_at_level_3(
20533        &mut self,
20534        _: &actions::FoldAtLevel3,
20535        window: &mut Window,
20536        cx: &mut Context<Self>,
20537    ) {
20538        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20539    }
20540
20541    pub fn fold_at_level_4(
20542        &mut self,
20543        _: &actions::FoldAtLevel4,
20544        window: &mut Window,
20545        cx: &mut Context<Self>,
20546    ) {
20547        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20548    }
20549
20550    pub fn fold_at_level_5(
20551        &mut self,
20552        _: &actions::FoldAtLevel5,
20553        window: &mut Window,
20554        cx: &mut Context<Self>,
20555    ) {
20556        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20557    }
20558
20559    pub fn fold_at_level_6(
20560        &mut self,
20561        _: &actions::FoldAtLevel6,
20562        window: &mut Window,
20563        cx: &mut Context<Self>,
20564    ) {
20565        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20566    }
20567
20568    pub fn fold_at_level_7(
20569        &mut self,
20570        _: &actions::FoldAtLevel7,
20571        window: &mut Window,
20572        cx: &mut Context<Self>,
20573    ) {
20574        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20575    }
20576
20577    pub fn fold_at_level_8(
20578        &mut self,
20579        _: &actions::FoldAtLevel8,
20580        window: &mut Window,
20581        cx: &mut Context<Self>,
20582    ) {
20583        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20584    }
20585
20586    pub fn fold_at_level_9(
20587        &mut self,
20588        _: &actions::FoldAtLevel9,
20589        window: &mut Window,
20590        cx: &mut Context<Self>,
20591    ) {
20592        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20593    }
20594
20595    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20596        if self.buffer.read(cx).is_singleton() {
20597            let mut fold_ranges = Vec::new();
20598            let snapshot = self.buffer.read(cx).snapshot(cx);
20599
20600            for row in 0..snapshot.max_row().0 {
20601                if let Some(foldable_range) = self
20602                    .snapshot(window, cx)
20603                    .crease_for_buffer_row(MultiBufferRow(row))
20604                {
20605                    fold_ranges.push(foldable_range);
20606                }
20607            }
20608
20609            self.fold_creases(fold_ranges, true, window, cx);
20610        } else {
20611            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20612                editor
20613                    .update_in(cx, |editor, _, cx| {
20614                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20615                        for buffer_id in snapshot.all_buffer_ids() {
20616                            editor.fold_buffer(buffer_id, cx);
20617                        }
20618                    })
20619                    .ok();
20620            });
20621        }
20622    }
20623
20624    pub fn fold_function_bodies(
20625        &mut self,
20626        _: &actions::FoldFunctionBodies,
20627        window: &mut Window,
20628        cx: &mut Context<Self>,
20629    ) {
20630        let snapshot = self.buffer.read(cx).snapshot(cx);
20631
20632        let ranges = snapshot
20633            .text_object_ranges(
20634                MultiBufferOffset(0)..snapshot.len(),
20635                TreeSitterOptions::default(),
20636            )
20637            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20638            .collect::<Vec<_>>();
20639
20640        let creases = ranges
20641            .into_iter()
20642            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20643            .collect();
20644
20645        self.fold_creases(creases, true, window, cx);
20646    }
20647
20648    pub fn fold_recursive(
20649        &mut self,
20650        _: &actions::FoldRecursive,
20651        window: &mut Window,
20652        cx: &mut Context<Self>,
20653    ) {
20654        let mut to_fold = Vec::new();
20655        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20656        let selections = self.selections.all_adjusted(&display_map);
20657
20658        for selection in selections {
20659            let range = selection.range().sorted();
20660            let buffer_start_row = range.start.row;
20661
20662            if range.start.row != range.end.row {
20663                let mut found = false;
20664                for row in range.start.row..=range.end.row {
20665                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20666                        found = true;
20667                        to_fold.push(crease);
20668                    }
20669                }
20670                if found {
20671                    continue;
20672                }
20673            }
20674
20675            for row in (0..=range.start.row).rev() {
20676                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20677                    if crease.range().end.row >= buffer_start_row {
20678                        to_fold.push(crease);
20679                    } else {
20680                        break;
20681                    }
20682                }
20683            }
20684        }
20685
20686        self.fold_creases(to_fold, true, window, cx);
20687    }
20688
20689    pub fn fold_at(
20690        &mut self,
20691        buffer_row: MultiBufferRow,
20692        window: &mut Window,
20693        cx: &mut Context<Self>,
20694    ) {
20695        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20696
20697        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20698            let autoscroll = self
20699                .selections
20700                .all::<Point>(&display_map)
20701                .iter()
20702                .any(|selection| crease.range().overlaps(&selection.range()));
20703
20704            self.fold_creases(vec![crease], autoscroll, window, cx);
20705        }
20706    }
20707
20708    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20709        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20710            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20711            let buffer = display_map.buffer_snapshot();
20712            let selections = self.selections.all::<Point>(&display_map);
20713            let ranges = selections
20714                .iter()
20715                .map(|s| {
20716                    let range = s.display_range(&display_map).sorted();
20717                    let mut start = range.start.to_point(&display_map);
20718                    let mut end = range.end.to_point(&display_map);
20719                    start.column = 0;
20720                    end.column = buffer.line_len(MultiBufferRow(end.row));
20721                    start..end
20722                })
20723                .collect::<Vec<_>>();
20724
20725            self.unfold_ranges(&ranges, true, true, cx);
20726        } else {
20727            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20728            let buffer_ids = self
20729                .selections
20730                .disjoint_anchor_ranges()
20731                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20732                .collect::<HashSet<_>>();
20733            for buffer_id in buffer_ids {
20734                self.unfold_buffer(buffer_id, cx);
20735            }
20736        }
20737    }
20738
20739    pub fn unfold_recursive(
20740        &mut self,
20741        _: &UnfoldRecursive,
20742        _window: &mut Window,
20743        cx: &mut Context<Self>,
20744    ) {
20745        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20746        let selections = self.selections.all::<Point>(&display_map);
20747        let ranges = selections
20748            .iter()
20749            .map(|s| {
20750                let mut range = s.display_range(&display_map).sorted();
20751                *range.start.column_mut() = 0;
20752                *range.end.column_mut() = display_map.line_len(range.end.row());
20753                let start = range.start.to_point(&display_map);
20754                let end = range.end.to_point(&display_map);
20755                start..end
20756            })
20757            .collect::<Vec<_>>();
20758
20759        self.unfold_ranges(&ranges, true, true, cx);
20760    }
20761
20762    pub fn unfold_at(
20763        &mut self,
20764        buffer_row: MultiBufferRow,
20765        _window: &mut Window,
20766        cx: &mut Context<Self>,
20767    ) {
20768        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20769
20770        let intersection_range = Point::new(buffer_row.0, 0)
20771            ..Point::new(
20772                buffer_row.0,
20773                display_map.buffer_snapshot().line_len(buffer_row),
20774            );
20775
20776        let autoscroll = self
20777            .selections
20778            .all::<Point>(&display_map)
20779            .iter()
20780            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20781
20782        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20783    }
20784
20785    pub fn unfold_all(
20786        &mut self,
20787        _: &actions::UnfoldAll,
20788        _window: &mut Window,
20789        cx: &mut Context<Self>,
20790    ) {
20791        if self.buffer.read(cx).is_singleton() {
20792            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20793            self.unfold_ranges(
20794                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20795                true,
20796                true,
20797                cx,
20798            );
20799        } else {
20800            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20801                editor
20802                    .update(cx, |editor, cx| {
20803                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20804                        for buffer_id in snapshot.all_buffer_ids() {
20805                            editor.unfold_buffer(buffer_id, cx);
20806                        }
20807                    })
20808                    .ok();
20809            });
20810        }
20811    }
20812
20813    pub fn fold_selected_ranges(
20814        &mut self,
20815        _: &FoldSelectedRanges,
20816        window: &mut Window,
20817        cx: &mut Context<Self>,
20818    ) {
20819        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20820        let selections = self.selections.all_adjusted(&display_map);
20821        let ranges = selections
20822            .into_iter()
20823            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20824            .collect::<Vec<_>>();
20825        self.fold_creases(ranges, true, window, cx);
20826    }
20827
20828    pub fn fold_ranges<T: ToOffset + Clone>(
20829        &mut self,
20830        ranges: Vec<Range<T>>,
20831        auto_scroll: bool,
20832        window: &mut Window,
20833        cx: &mut Context<Self>,
20834    ) {
20835        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20836        let ranges = ranges
20837            .into_iter()
20838            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20839            .collect::<Vec<_>>();
20840        self.fold_creases(ranges, auto_scroll, window, cx);
20841    }
20842
20843    pub fn fold_creases<T: ToOffset + Clone>(
20844        &mut self,
20845        creases: Vec<Crease<T>>,
20846        auto_scroll: bool,
20847        window: &mut Window,
20848        cx: &mut Context<Self>,
20849    ) {
20850        if creases.is_empty() {
20851            return;
20852        }
20853
20854        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20855
20856        if auto_scroll {
20857            self.request_autoscroll(Autoscroll::fit(), cx);
20858        }
20859
20860        cx.notify();
20861
20862        self.scrollbar_marker_state.dirty = true;
20863        self.update_data_on_scroll(window, cx);
20864        self.folds_did_change(cx);
20865    }
20866
20867    /// Removes any folds whose ranges intersect any of the given ranges.
20868    pub fn unfold_ranges<T: ToOffset + Clone>(
20869        &mut self,
20870        ranges: &[Range<T>],
20871        inclusive: bool,
20872        auto_scroll: bool,
20873        cx: &mut Context<Self>,
20874    ) {
20875        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20876            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20877        });
20878        self.folds_did_change(cx);
20879    }
20880
20881    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20882        self.fold_buffers([buffer_id], cx);
20883    }
20884
20885    pub fn fold_buffers(
20886        &mut self,
20887        buffer_ids: impl IntoIterator<Item = BufferId>,
20888        cx: &mut Context<Self>,
20889    ) {
20890        if self.buffer().read(cx).is_singleton() {
20891            return;
20892        }
20893
20894        let ids_to_fold: Vec<BufferId> = buffer_ids
20895            .into_iter()
20896            .filter(|id| !self.is_buffer_folded(*id, cx))
20897            .collect();
20898
20899        if ids_to_fold.is_empty() {
20900            return;
20901        }
20902
20903        self.display_map.update(cx, |display_map, cx| {
20904            display_map.fold_buffers(ids_to_fold.clone(), cx)
20905        });
20906
20907        let snapshot = self.display_snapshot(cx);
20908        self.selections.change_with(&snapshot, |selections| {
20909            for buffer_id in ids_to_fold.iter().copied() {
20910                selections.remove_selections_from_buffer(buffer_id);
20911            }
20912        });
20913
20914        cx.emit(EditorEvent::BufferFoldToggled {
20915            ids: ids_to_fold,
20916            folded: true,
20917        });
20918        cx.notify();
20919    }
20920
20921    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20922        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20923            return;
20924        }
20925        self.display_map.update(cx, |display_map, cx| {
20926            display_map.unfold_buffers([buffer_id], cx);
20927        });
20928        cx.emit(EditorEvent::BufferFoldToggled {
20929            ids: vec![buffer_id],
20930            folded: false,
20931        });
20932        cx.notify();
20933    }
20934
20935    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20936        self.display_map.read(cx).is_buffer_folded(buffer)
20937    }
20938
20939    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20940        if self.buffer().read(cx).is_singleton() {
20941            return false;
20942        }
20943        !self.folded_buffers(cx).is_empty()
20944    }
20945
20946    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20947        self.display_map.read(cx).folded_buffers()
20948    }
20949
20950    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20951        self.display_map.update(cx, |display_map, cx| {
20952            display_map.disable_header_for_buffer(buffer_id, cx);
20953        });
20954        cx.notify();
20955    }
20956
20957    /// Removes any folds with the given ranges.
20958    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20959        &mut self,
20960        ranges: &[Range<T>],
20961        type_id: TypeId,
20962        auto_scroll: bool,
20963        cx: &mut Context<Self>,
20964    ) {
20965        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20966            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20967        });
20968        self.folds_did_change(cx);
20969    }
20970
20971    fn remove_folds_with<T: ToOffset + Clone>(
20972        &mut self,
20973        ranges: &[Range<T>],
20974        auto_scroll: bool,
20975        cx: &mut Context<Self>,
20976        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20977    ) {
20978        if ranges.is_empty() {
20979            return;
20980        }
20981
20982        self.display_map.update(cx, update);
20983
20984        if auto_scroll {
20985            self.request_autoscroll(Autoscroll::fit(), cx);
20986        }
20987
20988        cx.notify();
20989        self.scrollbar_marker_state.dirty = true;
20990        self.active_indent_guides_state.dirty = true;
20991    }
20992
20993    pub fn update_renderer_widths(
20994        &mut self,
20995        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20996        cx: &mut Context<Self>,
20997    ) -> bool {
20998        self.display_map
20999            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
21000    }
21001
21002    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
21003        self.display_map.read(cx).fold_placeholder.clone()
21004    }
21005
21006    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
21007        self.buffer.update(cx, |buffer, cx| {
21008            buffer.set_all_diff_hunks_expanded(cx);
21009        });
21010    }
21011
21012    pub fn expand_all_diff_hunks(
21013        &mut self,
21014        _: &ExpandAllDiffHunks,
21015        _window: &mut Window,
21016        cx: &mut Context<Self>,
21017    ) {
21018        self.buffer.update(cx, |buffer, cx| {
21019            buffer.expand_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
21020        });
21021    }
21022
21023    pub fn collapse_all_diff_hunks(
21024        &mut self,
21025        _: &CollapseAllDiffHunks,
21026        _window: &mut Window,
21027        cx: &mut Context<Self>,
21028    ) {
21029        self.buffer.update(cx, |buffer, cx| {
21030            buffer.collapse_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
21031        });
21032    }
21033
21034    pub fn toggle_selected_diff_hunks(
21035        &mut self,
21036        _: &ToggleSelectedDiffHunks,
21037        _window: &mut Window,
21038        cx: &mut Context<Self>,
21039    ) {
21040        let ranges: Vec<_> = self
21041            .selections
21042            .disjoint_anchors()
21043            .iter()
21044            .map(|s| s.range())
21045            .collect();
21046        self.toggle_diff_hunks_in_ranges(ranges, cx);
21047    }
21048
21049    pub fn diff_hunks_in_ranges<'a>(
21050        &'a self,
21051        ranges: &'a [Range<Anchor>],
21052        buffer: &'a MultiBufferSnapshot,
21053    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
21054        ranges.iter().flat_map(move |range| {
21055            let end_excerpt = buffer.excerpt_containing(range.end..range.end);
21056            let range = range.to_point(buffer);
21057            let mut peek_end = range.end;
21058            if range.end.row < buffer.max_row().0 {
21059                peek_end = Point::new(range.end.row + 1, 0);
21060            }
21061            buffer
21062                .diff_hunks_in_range(range.start..peek_end)
21063                .filter(move |hunk| {
21064                    if let Some((_, excerpt_range)) = &end_excerpt
21065                        && let Some(end_anchor) =
21066                            buffer.anchor_in_excerpt(excerpt_range.context.end)
21067                        && let Some(hunk_end_anchor) =
21068                            buffer.anchor_in_excerpt(hunk.excerpt_range.context.end)
21069                        && hunk_end_anchor.cmp(&end_anchor, buffer).is_gt()
21070                    {
21071                        false
21072                    } else {
21073                        true
21074                    }
21075                })
21076        })
21077    }
21078
21079    pub fn has_stageable_diff_hunks_in_ranges(
21080        &self,
21081        ranges: &[Range<Anchor>],
21082        snapshot: &MultiBufferSnapshot,
21083    ) -> bool {
21084        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
21085        hunks.any(|hunk| hunk.status().has_secondary_hunk())
21086    }
21087
21088    pub fn toggle_staged_selected_diff_hunks(
21089        &mut self,
21090        _: &::git::ToggleStaged,
21091        _: &mut Window,
21092        cx: &mut Context<Self>,
21093    ) {
21094        let snapshot = self.buffer.read(cx).snapshot(cx);
21095        let ranges: Vec<_> = self
21096            .selections
21097            .disjoint_anchors()
21098            .iter()
21099            .map(|s| s.range())
21100            .collect();
21101        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
21102        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21103    }
21104
21105    pub fn set_render_diff_hunk_controls(
21106        &mut self,
21107        render_diff_hunk_controls: RenderDiffHunkControlsFn,
21108        cx: &mut Context<Self>,
21109    ) {
21110        self.render_diff_hunk_controls = render_diff_hunk_controls;
21111        cx.notify();
21112    }
21113
21114    pub fn stage_and_next(
21115        &mut self,
21116        _: &::git::StageAndNext,
21117        window: &mut Window,
21118        cx: &mut Context<Self>,
21119    ) {
21120        self.do_stage_or_unstage_and_next(true, window, cx);
21121    }
21122
21123    pub fn unstage_and_next(
21124        &mut self,
21125        _: &::git::UnstageAndNext,
21126        window: &mut Window,
21127        cx: &mut Context<Self>,
21128    ) {
21129        self.do_stage_or_unstage_and_next(false, window, cx);
21130    }
21131
21132    pub fn stage_or_unstage_diff_hunks(
21133        &mut self,
21134        stage: bool,
21135        ranges: Vec<Range<Anchor>>,
21136        cx: &mut Context<Self>,
21137    ) {
21138        if self.delegate_stage_and_restore {
21139            let snapshot = self.buffer.read(cx).snapshot(cx);
21140            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
21141            if !hunks.is_empty() {
21142                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
21143            }
21144            return;
21145        }
21146        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
21147        cx.spawn(async move |this, cx| {
21148            task.await?;
21149            this.update(cx, |this, cx| {
21150                let snapshot = this.buffer.read(cx).snapshot(cx);
21151                let chunk_by = this
21152                    .diff_hunks_in_ranges(&ranges, &snapshot)
21153                    .chunk_by(|hunk| hunk.buffer_id);
21154                for (buffer_id, hunks) in &chunk_by {
21155                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
21156                }
21157            })
21158        })
21159        .detach_and_log_err(cx);
21160    }
21161
21162    fn save_buffers_for_ranges_if_needed(
21163        &mut self,
21164        ranges: &[Range<Anchor>],
21165        cx: &mut Context<Editor>,
21166    ) -> Task<Result<()>> {
21167        let multibuffer = self.buffer.read(cx);
21168        let snapshot = multibuffer.read(cx);
21169        let buffer_ids: HashSet<_> = ranges
21170            .iter()
21171            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
21172            .collect();
21173        drop(snapshot);
21174
21175        let mut buffers = HashSet::default();
21176        for buffer_id in buffer_ids {
21177            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
21178                let buffer = buffer_entity.read(cx);
21179                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
21180                {
21181                    buffers.insert(buffer_entity);
21182                }
21183            }
21184        }
21185
21186        if let Some(project) = &self.project {
21187            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
21188        } else {
21189            Task::ready(Ok(()))
21190        }
21191    }
21192
21193    fn do_stage_or_unstage_and_next(
21194        &mut self,
21195        stage: bool,
21196        window: &mut Window,
21197        cx: &mut Context<Self>,
21198    ) {
21199        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
21200
21201        if ranges.iter().any(|range| range.start != range.end) {
21202            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21203            return;
21204        }
21205
21206        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21207
21208        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
21209        let wrap_around = !all_diff_hunks_expanded;
21210        let snapshot = self.snapshot(window, cx);
21211        let position = self
21212            .selections
21213            .newest::<Point>(&snapshot.display_snapshot)
21214            .head();
21215
21216        self.go_to_hunk_before_or_after_position(
21217            &snapshot,
21218            position,
21219            Direction::Next,
21220            wrap_around,
21221            window,
21222            cx,
21223        );
21224    }
21225
21226    pub(crate) fn do_stage_or_unstage(
21227        &self,
21228        stage: bool,
21229        buffer_id: BufferId,
21230        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
21231        cx: &mut App,
21232    ) -> Option<()> {
21233        let project = self.project()?;
21234        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
21235        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
21236        let buffer_snapshot = buffer.read(cx).snapshot();
21237        let file_exists = buffer_snapshot
21238            .file()
21239            .is_some_and(|file| file.disk_state().exists());
21240        diff.update(cx, |diff, cx| {
21241            diff.stage_or_unstage_hunks(
21242                stage,
21243                &hunks
21244                    .map(|hunk| buffer_diff::DiffHunk {
21245                        buffer_range: hunk.buffer_range,
21246                        // We don't need to pass in word diffs here because they're only used for rendering and
21247                        // this function changes internal state
21248                        base_word_diffs: Vec::default(),
21249                        buffer_word_diffs: Vec::default(),
21250                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
21251                            ..hunk.diff_base_byte_range.end.0,
21252                        secondary_status: hunk.status.secondary,
21253                        range: Point::zero()..Point::zero(), // unused
21254                    })
21255                    .collect::<Vec<_>>(),
21256                &buffer_snapshot,
21257                file_exists,
21258                cx,
21259            )
21260        });
21261        None
21262    }
21263
21264    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
21265        let ranges: Vec<_> = self
21266            .selections
21267            .disjoint_anchors()
21268            .iter()
21269            .map(|s| s.range())
21270            .collect();
21271        self.buffer
21272            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
21273    }
21274
21275    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
21276        self.buffer.update(cx, |buffer, cx| {
21277            let ranges = vec![Anchor::Min..Anchor::Max];
21278            if !buffer.all_diff_hunks_expanded()
21279                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
21280            {
21281                buffer.collapse_diff_hunks(ranges, cx);
21282                true
21283            } else {
21284                false
21285            }
21286        })
21287    }
21288
21289    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21290        if self.buffer.read(cx).all_diff_hunks_expanded() {
21291            return true;
21292        }
21293        let ranges = vec![Anchor::Min..Anchor::Max];
21294        self.buffer
21295            .read(cx)
21296            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21297    }
21298
21299    fn toggle_diff_hunks_in_ranges(
21300        &mut self,
21301        ranges: Vec<Range<Anchor>>,
21302        cx: &mut Context<Editor>,
21303    ) {
21304        self.buffer.update(cx, |buffer, cx| {
21305            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21306            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21307        })
21308    }
21309
21310    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21311        self.buffer.update(cx, |buffer, cx| {
21312            buffer.toggle_single_diff_hunk(range, cx);
21313        })
21314    }
21315
21316    pub(crate) fn apply_all_diff_hunks(
21317        &mut self,
21318        _: &ApplyAllDiffHunks,
21319        window: &mut Window,
21320        cx: &mut Context<Self>,
21321    ) {
21322        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21323
21324        let buffers = self.buffer.read(cx).all_buffers();
21325        for branch_buffer in buffers {
21326            branch_buffer.update(cx, |branch_buffer, cx| {
21327                branch_buffer.merge_into_base(Vec::new(), cx);
21328            });
21329        }
21330
21331        if let Some(project) = self.project.clone() {
21332            self.save(
21333                SaveOptions {
21334                    format: true,
21335                    autosave: false,
21336                },
21337                project,
21338                window,
21339                cx,
21340            )
21341            .detach_and_log_err(cx);
21342        }
21343    }
21344
21345    pub(crate) fn apply_selected_diff_hunks(
21346        &mut self,
21347        _: &ApplyDiffHunk,
21348        window: &mut Window,
21349        cx: &mut Context<Self>,
21350    ) {
21351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21352        let snapshot = self.snapshot(window, cx);
21353        let hunks = snapshot.hunks_for_ranges(
21354            self.selections
21355                .all(&snapshot.display_snapshot)
21356                .into_iter()
21357                .map(|selection| selection.range()),
21358        );
21359        let mut ranges_by_buffer = HashMap::default();
21360        self.transact(window, cx, |editor, _window, cx| {
21361            for hunk in hunks {
21362                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21363                    ranges_by_buffer
21364                        .entry(buffer.clone())
21365                        .or_insert_with(Vec::new)
21366                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21367                }
21368            }
21369
21370            for (buffer, ranges) in ranges_by_buffer {
21371                buffer.update(cx, |buffer, cx| {
21372                    buffer.merge_into_base(ranges, cx);
21373                });
21374            }
21375        });
21376
21377        if let Some(project) = self.project.clone() {
21378            self.save(
21379                SaveOptions {
21380                    format: true,
21381                    autosave: false,
21382                },
21383                project,
21384                window,
21385                cx,
21386            )
21387            .detach_and_log_err(cx);
21388        }
21389    }
21390
21391    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21392        if hovered != self.gutter_hovered {
21393            self.gutter_hovered = hovered;
21394            cx.notify();
21395        }
21396    }
21397
21398    pub fn insert_blocks(
21399        &mut self,
21400        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21401        autoscroll: Option<Autoscroll>,
21402        cx: &mut Context<Self>,
21403    ) -> Vec<CustomBlockId> {
21404        let blocks = self
21405            .display_map
21406            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21407        if let Some(autoscroll) = autoscroll {
21408            self.request_autoscroll(autoscroll, cx);
21409        }
21410        cx.notify();
21411        blocks
21412    }
21413
21414    pub fn resize_blocks(
21415        &mut self,
21416        heights: HashMap<CustomBlockId, u32>,
21417        autoscroll: Option<Autoscroll>,
21418        cx: &mut Context<Self>,
21419    ) {
21420        self.display_map
21421            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21422        if let Some(autoscroll) = autoscroll {
21423            self.request_autoscroll(autoscroll, cx);
21424        }
21425        cx.notify();
21426    }
21427
21428    pub fn replace_blocks(
21429        &mut self,
21430        renderers: HashMap<CustomBlockId, RenderBlock>,
21431        autoscroll: Option<Autoscroll>,
21432        cx: &mut Context<Self>,
21433    ) {
21434        self.display_map
21435            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21436        if let Some(autoscroll) = autoscroll {
21437            self.request_autoscroll(autoscroll, cx);
21438        }
21439        cx.notify();
21440    }
21441
21442    pub fn remove_blocks(
21443        &mut self,
21444        block_ids: HashSet<CustomBlockId>,
21445        autoscroll: Option<Autoscroll>,
21446        cx: &mut Context<Self>,
21447    ) {
21448        self.display_map.update(cx, |display_map, cx| {
21449            display_map.remove_blocks(block_ids, cx)
21450        });
21451        if let Some(autoscroll) = autoscroll {
21452            self.request_autoscroll(autoscroll, cx);
21453        }
21454        cx.notify();
21455    }
21456
21457    pub fn row_for_block(
21458        &self,
21459        block_id: CustomBlockId,
21460        cx: &mut Context<Self>,
21461    ) -> Option<DisplayRow> {
21462        self.display_map
21463            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21464    }
21465
21466    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21467        self.focused_block = Some(focused_block);
21468    }
21469
21470    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21471        self.focused_block.take()
21472    }
21473
21474    pub fn insert_creases(
21475        &mut self,
21476        creases: impl IntoIterator<Item = Crease<Anchor>>,
21477        cx: &mut Context<Self>,
21478    ) -> Vec<CreaseId> {
21479        self.display_map
21480            .update(cx, |map, cx| map.insert_creases(creases, cx))
21481    }
21482
21483    pub fn remove_creases(
21484        &mut self,
21485        ids: impl IntoIterator<Item = CreaseId>,
21486        cx: &mut Context<Self>,
21487    ) -> Vec<(CreaseId, Range<Anchor>)> {
21488        self.display_map
21489            .update(cx, |map, cx| map.remove_creases(ids, cx))
21490    }
21491
21492    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21493        self.display_map
21494            .update(cx, |map, cx| map.snapshot(cx))
21495            .longest_row()
21496    }
21497
21498    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21499        self.display_map
21500            .update(cx, |map, cx| map.snapshot(cx))
21501            .max_point()
21502    }
21503
21504    pub fn text(&self, cx: &App) -> String {
21505        self.buffer.read(cx).read(cx).text()
21506    }
21507
21508    pub fn is_empty(&self, cx: &App) -> bool {
21509        self.buffer.read(cx).read(cx).is_empty()
21510    }
21511
21512    pub fn text_option(&self, cx: &App) -> Option<String> {
21513        let text = self.text(cx);
21514        let text = text.trim();
21515
21516        if text.is_empty() {
21517            return None;
21518        }
21519
21520        Some(text.to_string())
21521    }
21522
21523    pub fn set_text(
21524        &mut self,
21525        text: impl Into<Arc<str>>,
21526        window: &mut Window,
21527        cx: &mut Context<Self>,
21528    ) {
21529        self.transact(window, cx, |this, _, cx| {
21530            this.buffer
21531                .read(cx)
21532                .as_singleton()
21533                .expect("you can only call set_text on editors for singleton buffers")
21534                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21535        });
21536    }
21537
21538    pub fn display_text(&self, cx: &mut App) -> String {
21539        self.display_map
21540            .update(cx, |map, cx| map.snapshot(cx))
21541            .text()
21542    }
21543
21544    fn create_minimap(
21545        &self,
21546        minimap_settings: MinimapSettings,
21547        window: &mut Window,
21548        cx: &mut Context<Self>,
21549    ) -> Option<Entity<Self>> {
21550        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21551            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21552    }
21553
21554    fn initialize_new_minimap(
21555        &self,
21556        minimap_settings: MinimapSettings,
21557        window: &mut Window,
21558        cx: &mut Context<Self>,
21559    ) -> Entity<Self> {
21560        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21561        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21562
21563        let mut minimap = Editor::new_internal(
21564            EditorMode::Minimap {
21565                parent: cx.weak_entity(),
21566            },
21567            self.buffer.clone(),
21568            None,
21569            Some(self.display_map.clone()),
21570            window,
21571            cx,
21572        );
21573        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21574        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21575        minimap.scroll_manager.clone_state(
21576            &self.scroll_manager,
21577            &my_snapshot,
21578            &minimap_snapshot,
21579            cx,
21580        );
21581        minimap.set_text_style_refinement(TextStyleRefinement {
21582            font_size: Some(MINIMAP_FONT_SIZE),
21583            font_weight: Some(MINIMAP_FONT_WEIGHT),
21584            font_family: Some(MINIMAP_FONT_FAMILY),
21585            ..Default::default()
21586        });
21587        minimap.update_minimap_configuration(minimap_settings, cx);
21588        cx.new(|_| minimap)
21589    }
21590
21591    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21592        let current_line_highlight = minimap_settings
21593            .current_line_highlight
21594            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21595        self.set_current_line_highlight(Some(current_line_highlight));
21596    }
21597
21598    pub fn minimap(&self) -> Option<&Entity<Self>> {
21599        self.minimap
21600            .as_ref()
21601            .filter(|_| self.minimap_visibility.visible())
21602    }
21603
21604    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21605        let mut wrap_guides = smallvec![];
21606
21607        if self.show_wrap_guides == Some(false) {
21608            return wrap_guides;
21609        }
21610
21611        let settings = self.buffer.read(cx).language_settings(cx);
21612        if settings.show_wrap_guides {
21613            match self.soft_wrap_mode(cx) {
21614                SoftWrap::Column(soft_wrap) => {
21615                    wrap_guides.push((soft_wrap as usize, true));
21616                }
21617                SoftWrap::Bounded(soft_wrap) => {
21618                    wrap_guides.push((soft_wrap as usize, true));
21619                }
21620                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21621            }
21622            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21623        }
21624
21625        wrap_guides
21626    }
21627
21628    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21629        let settings = self.buffer.read(cx).language_settings(cx);
21630        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21631        match mode {
21632            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21633                SoftWrap::None
21634            }
21635            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21636            language_settings::SoftWrap::PreferredLineLength => {
21637                SoftWrap::Column(settings.preferred_line_length)
21638            }
21639            language_settings::SoftWrap::Bounded => {
21640                SoftWrap::Bounded(settings.preferred_line_length)
21641            }
21642        }
21643    }
21644
21645    pub fn set_soft_wrap_mode(
21646        &mut self,
21647        mode: language_settings::SoftWrap,
21648        cx: &mut Context<Self>,
21649    ) {
21650        self.soft_wrap_mode_override = Some(mode);
21651        cx.notify();
21652    }
21653
21654    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21655        self.hard_wrap = hard_wrap;
21656        cx.notify();
21657    }
21658
21659    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21660        self.text_style_refinement = Some(style);
21661    }
21662
21663    /// called by the Element so we know what style we were most recently rendered with.
21664    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21665        // We intentionally do not inform the display map about the minimap style
21666        // so that wrapping is not recalculated and stays consistent for the editor
21667        // and its linked minimap.
21668        if !self.mode.is_minimap() {
21669            let font = style.text.font();
21670            let font_size = style.text.font_size.to_pixels(window.rem_size());
21671            let display_map = self
21672                .placeholder_display_map
21673                .as_ref()
21674                .filter(|_| self.is_empty(cx))
21675                .unwrap_or(&self.display_map);
21676
21677            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21678        }
21679        self.style = Some(style);
21680    }
21681
21682    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21683        if self.style.is_none() {
21684            self.style = Some(self.create_style(cx));
21685        }
21686        self.style.as_ref().unwrap()
21687    }
21688
21689    // Called by the element. This method is not designed to be called outside of the editor
21690    // element's layout code because it does not notify when rewrapping is computed synchronously.
21691    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21692        if self.is_empty(cx) {
21693            self.placeholder_display_map
21694                .as_ref()
21695                .map_or(false, |display_map| {
21696                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21697                })
21698        } else {
21699            self.display_map
21700                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21701        }
21702    }
21703
21704    pub fn set_soft_wrap(&mut self) {
21705        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21706    }
21707
21708    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21709        if self.soft_wrap_mode_override.is_some() {
21710            self.soft_wrap_mode_override.take();
21711        } else {
21712            let soft_wrap = match self.soft_wrap_mode(cx) {
21713                SoftWrap::GitDiff => return,
21714                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21715                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21716                    language_settings::SoftWrap::None
21717                }
21718            };
21719            self.soft_wrap_mode_override = Some(soft_wrap);
21720        }
21721        cx.notify();
21722    }
21723
21724    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21725        let Some(workspace) = self.workspace() else {
21726            return;
21727        };
21728        let fs = workspace.read(cx).app_state().fs.clone();
21729        let current_show = TabBarSettings::get_global(cx).show;
21730        update_settings_file(fs, cx, move |setting, _| {
21731            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21732        });
21733    }
21734
21735    pub fn toggle_indent_guides(
21736        &mut self,
21737        _: &ToggleIndentGuides,
21738        _: &mut Window,
21739        cx: &mut Context<Self>,
21740    ) {
21741        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21742            self.buffer
21743                .read(cx)
21744                .language_settings(cx)
21745                .indent_guides
21746                .enabled
21747        });
21748        self.show_indent_guides = Some(!currently_enabled);
21749        cx.notify();
21750    }
21751
21752    fn should_show_indent_guides(&self) -> Option<bool> {
21753        self.show_indent_guides
21754    }
21755
21756    pub fn disable_indent_guides_for_buffer(
21757        &mut self,
21758        buffer_id: BufferId,
21759        cx: &mut Context<Self>,
21760    ) {
21761        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21762        cx.notify();
21763    }
21764
21765    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21766        self.buffers_with_disabled_indent_guides
21767            .contains(&buffer_id)
21768    }
21769
21770    pub fn toggle_line_numbers(
21771        &mut self,
21772        _: &ToggleLineNumbers,
21773        _: &mut Window,
21774        cx: &mut Context<Self>,
21775    ) {
21776        let mut editor_settings = EditorSettings::get_global(cx).clone();
21777        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21778        EditorSettings::override_global(editor_settings, cx);
21779    }
21780
21781    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21782        if let Some(show_line_numbers) = self.show_line_numbers {
21783            return show_line_numbers;
21784        }
21785        EditorSettings::get_global(cx).gutter.line_numbers
21786    }
21787
21788    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21789        match (
21790            self.use_relative_line_numbers,
21791            EditorSettings::get_global(cx).relative_line_numbers,
21792        ) {
21793            (None, setting) => setting,
21794            (Some(false), _) => RelativeLineNumbers::Disabled,
21795            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21796            (Some(true), _) => RelativeLineNumbers::Enabled,
21797        }
21798    }
21799
21800    pub fn toggle_relative_line_numbers(
21801        &mut self,
21802        _: &ToggleRelativeLineNumbers,
21803        _: &mut Window,
21804        cx: &mut Context<Self>,
21805    ) {
21806        let is_relative = self.relative_line_numbers(cx);
21807        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21808    }
21809
21810    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21811        self.use_relative_line_numbers = is_relative;
21812        cx.notify();
21813    }
21814
21815    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21816        self.show_gutter = show_gutter;
21817        cx.notify();
21818    }
21819
21820    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21821        self.show_scrollbars = ScrollbarAxes {
21822            horizontal: show,
21823            vertical: show,
21824        };
21825        cx.notify();
21826    }
21827
21828    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21829        self.show_scrollbars.vertical = show;
21830        cx.notify();
21831    }
21832
21833    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21834        self.show_scrollbars.horizontal = show;
21835        cx.notify();
21836    }
21837
21838    pub fn set_minimap_visibility(
21839        &mut self,
21840        minimap_visibility: MinimapVisibility,
21841        window: &mut Window,
21842        cx: &mut Context<Self>,
21843    ) {
21844        if self.minimap_visibility != minimap_visibility {
21845            if minimap_visibility.visible() && self.minimap.is_none() {
21846                let minimap_settings = EditorSettings::get_global(cx).minimap;
21847                self.minimap =
21848                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21849            }
21850            self.minimap_visibility = minimap_visibility;
21851            cx.notify();
21852        }
21853    }
21854
21855    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21856        self.set_show_scrollbars(false, cx);
21857        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21858    }
21859
21860    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21861        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21862    }
21863
21864    /// Normally the text in full mode and auto height editors is padded on the
21865    /// left side by roughly half a character width for improved hit testing.
21866    ///
21867    /// Use this method to disable this for cases where this is not wanted (e.g.
21868    /// if you want to align the editor text with some other text above or below)
21869    /// or if you want to add this padding to single-line editors.
21870    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21871        self.offset_content = offset_content;
21872        cx.notify();
21873    }
21874
21875    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21876        self.show_line_numbers = Some(show_line_numbers);
21877        cx.notify();
21878    }
21879
21880    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21881        self.disable_expand_excerpt_buttons = true;
21882        cx.notify();
21883    }
21884
21885    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21886        self.number_deleted_lines = number;
21887        cx.notify();
21888    }
21889
21890    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21891        self.delegate_expand_excerpts = delegate;
21892    }
21893
21894    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21895        self.delegate_stage_and_restore = delegate;
21896    }
21897
21898    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21899        self.delegate_open_excerpts = delegate;
21900    }
21901
21902    pub fn set_on_local_selections_changed(
21903        &mut self,
21904        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21905    ) {
21906        self.on_local_selections_changed = callback;
21907    }
21908
21909    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21910        self.suppress_selection_callback = suppress;
21911    }
21912
21913    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21914        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21915        cx.notify();
21916    }
21917
21918    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21919        self.show_code_actions = Some(show_code_actions);
21920        cx.notify();
21921    }
21922
21923    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21924        self.show_runnables = Some(show_runnables);
21925        cx.notify();
21926    }
21927
21928    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21929        self.show_breakpoints = Some(show_breakpoints);
21930        cx.notify();
21931    }
21932
21933    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21934        self.show_diff_review_button = show;
21935        cx.notify();
21936    }
21937
21938    pub fn show_diff_review_button(&self) -> bool {
21939        self.show_diff_review_button
21940    }
21941
21942    pub fn render_diff_review_button(
21943        &self,
21944        display_row: DisplayRow,
21945        width: Pixels,
21946        cx: &mut Context<Self>,
21947    ) -> impl IntoElement {
21948        let text_color = cx.theme().colors().text;
21949        let icon_color = cx.theme().colors().icon_accent;
21950
21951        h_flex()
21952            .id("diff_review_button")
21953            .cursor_pointer()
21954            .w(width - px(1.))
21955            .h(relative(0.9))
21956            .justify_center()
21957            .rounded_sm()
21958            .border_1()
21959            .border_color(text_color.opacity(0.1))
21960            .bg(text_color.opacity(0.15))
21961            .hover(|s| {
21962                s.bg(icon_color.opacity(0.4))
21963                    .border_color(icon_color.opacity(0.5))
21964            })
21965            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21966            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21967            .on_mouse_down(
21968                gpui::MouseButton::Left,
21969                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21970                    editor.start_diff_review_drag(display_row, window, cx);
21971                }),
21972            )
21973    }
21974
21975    pub fn start_diff_review_drag(
21976        &mut self,
21977        display_row: DisplayRow,
21978        window: &mut Window,
21979        cx: &mut Context<Self>,
21980    ) {
21981        let snapshot = self.snapshot(window, cx);
21982        let point = snapshot
21983            .display_snapshot
21984            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21985        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21986        self.diff_review_drag_state = Some(DiffReviewDragState {
21987            start_anchor: anchor,
21988            current_anchor: anchor,
21989        });
21990        cx.notify();
21991    }
21992
21993    pub fn update_diff_review_drag(
21994        &mut self,
21995        display_row: DisplayRow,
21996        window: &mut Window,
21997        cx: &mut Context<Self>,
21998    ) {
21999        if self.diff_review_drag_state.is_none() {
22000            return;
22001        }
22002        let snapshot = self.snapshot(window, cx);
22003        let point = snapshot
22004            .display_snapshot
22005            .display_point_to_point(display_row.as_display_point(), Bias::Left);
22006        let anchor = snapshot.buffer_snapshot().anchor_before(point);
22007        if let Some(drag_state) = &mut self.diff_review_drag_state {
22008            drag_state.current_anchor = anchor;
22009            cx.notify();
22010        }
22011    }
22012
22013    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22014        if let Some(drag_state) = self.diff_review_drag_state.take() {
22015            let snapshot = self.snapshot(window, cx);
22016            let range = drag_state.row_range(&snapshot.display_snapshot);
22017            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
22018        }
22019        cx.notify();
22020    }
22021
22022    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
22023        self.diff_review_drag_state = None;
22024        cx.notify();
22025    }
22026
22027    /// Calculates the appropriate block height for the diff review overlay.
22028    /// Height is in lines: 2 for input row, 1 for header when comments exist,
22029    /// and 2 lines per comment when expanded.
22030    fn calculate_overlay_height(
22031        &self,
22032        hunk_key: &DiffHunkKey,
22033        comments_expanded: bool,
22034        snapshot: &MultiBufferSnapshot,
22035    ) -> u32 {
22036        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
22037        let base_height: u32 = 2; // Input row with avatar and buttons
22038
22039        if comment_count == 0 {
22040            base_height
22041        } else if comments_expanded {
22042            // Header (1 line) + 2 lines per comment
22043            base_height + 1 + (comment_count as u32 * 2)
22044        } else {
22045            // Just header when collapsed
22046            base_height + 1
22047        }
22048    }
22049
22050    pub fn show_diff_review_overlay(
22051        &mut self,
22052        display_range: Range<DisplayRow>,
22053        window: &mut Window,
22054        cx: &mut Context<Self>,
22055    ) {
22056        let Range { start, end } = display_range.sorted();
22057
22058        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22059        let editor_snapshot = self.snapshot(window, cx);
22060
22061        // Convert display rows to multibuffer points
22062        let start_point = editor_snapshot
22063            .display_snapshot
22064            .display_point_to_point(start.as_display_point(), Bias::Left);
22065        let end_point = editor_snapshot
22066            .display_snapshot
22067            .display_point_to_point(end.as_display_point(), Bias::Left);
22068        let end_multi_buffer_row = MultiBufferRow(end_point.row);
22069
22070        // Create anchor range for the selected lines (start of first line to end of last line)
22071        let line_end = Point::new(
22072            end_point.row,
22073            buffer_snapshot.line_len(end_multi_buffer_row),
22074        );
22075        let anchor_range =
22076            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
22077
22078        // Compute the hunk key for this display row
22079        let file_path = buffer_snapshot
22080            .file_at(start_point)
22081            .map(|file: &Arc<dyn language::File>| file.path().clone())
22082            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
22083        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
22084        let new_hunk_key = DiffHunkKey {
22085            file_path,
22086            hunk_start_anchor,
22087        };
22088
22089        // Check if we already have an overlay for this hunk
22090        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
22091            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
22092        }) {
22093            // Just focus the existing overlay's prompt editor
22094            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
22095            window.focus(&focus_handle, cx);
22096            return;
22097        }
22098
22099        // Dismiss overlays that have no comments for their hunks
22100        self.dismiss_overlays_without_comments(cx);
22101
22102        // Get the current user's avatar URI from the project's user_store
22103        let user_avatar_uri = self.project.as_ref().and_then(|project| {
22104            let user_store = project.read(cx).user_store();
22105            user_store
22106                .read(cx)
22107                .current_user()
22108                .map(|user| user.avatar_uri.clone())
22109        });
22110
22111        // Create anchor at the end of the last row so the block appears immediately below it
22112        // Use multibuffer coordinates for anchor creation
22113        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
22114        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
22115
22116        // Use the hunk key we already computed
22117        let hunk_key = new_hunk_key;
22118
22119        // Create the prompt editor for the review input
22120        let prompt_editor = cx.new(|cx| {
22121            let mut editor = Editor::single_line(window, cx);
22122            editor.set_placeholder_text("Add a review comment...", window, cx);
22123            editor
22124        });
22125
22126        // Register the Newline action on the prompt editor to submit the review
22127        let parent_editor = cx.entity().downgrade();
22128        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
22129            prompt_editor.register_action({
22130                let parent_editor = parent_editor.clone();
22131                move |_: &crate::actions::Newline, window, cx| {
22132                    if let Some(editor) = parent_editor.upgrade() {
22133                        editor.update(cx, |editor, cx| {
22134                            editor.submit_diff_review_comment(window, cx);
22135                        });
22136                    }
22137                }
22138            })
22139        });
22140
22141        // Calculate initial height based on existing comments for this hunk
22142        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
22143
22144        // Create the overlay block
22145        let prompt_editor_for_render = prompt_editor.clone();
22146        let hunk_key_for_render = hunk_key.clone();
22147        let editor_handle = cx.entity().downgrade();
22148        let block = BlockProperties {
22149            style: BlockStyle::Sticky,
22150            placement: BlockPlacement::Below(anchor),
22151            height: Some(initial_height),
22152            render: Arc::new(move |cx| {
22153                Self::render_diff_review_overlay(
22154                    &prompt_editor_for_render,
22155                    &hunk_key_for_render,
22156                    &editor_handle,
22157                    cx,
22158                )
22159            }),
22160            priority: 0,
22161        };
22162
22163        let block_ids = self.insert_blocks([block], None, cx);
22164        let Some(block_id) = block_ids.into_iter().next() else {
22165            log::error!("Failed to insert diff review overlay block");
22166            return;
22167        };
22168
22169        self.diff_review_overlays.push(DiffReviewOverlay {
22170            anchor_range,
22171            block_id,
22172            prompt_editor: prompt_editor.clone(),
22173            hunk_key,
22174            comments_expanded: true,
22175            inline_edit_editors: HashMap::default(),
22176            inline_edit_subscriptions: HashMap::default(),
22177            user_avatar_uri,
22178            _subscription: subscription,
22179        });
22180
22181        // Focus the prompt editor
22182        let focus_handle = prompt_editor.focus_handle(cx);
22183        window.focus(&focus_handle, cx);
22184
22185        cx.notify();
22186    }
22187
22188    /// Dismisses all diff review overlays.
22189    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
22190        if self.diff_review_overlays.is_empty() {
22191            return;
22192        }
22193        let block_ids: HashSet<_> = self
22194            .diff_review_overlays
22195            .drain(..)
22196            .map(|overlay| overlay.block_id)
22197            .collect();
22198        self.remove_blocks(block_ids, None, cx);
22199        cx.notify();
22200    }
22201
22202    /// Dismisses overlays that have no comments stored for their hunks.
22203    /// Keeps overlays that have at least one comment.
22204    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
22205        let snapshot = self.buffer.read(cx).snapshot(cx);
22206
22207        // First, compute which overlays have comments (to avoid borrow issues with retain)
22208        let overlays_with_comments: Vec<bool> = self
22209            .diff_review_overlays
22210            .iter()
22211            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
22212            .collect();
22213
22214        // Now collect block IDs to remove and retain overlays
22215        let mut block_ids_to_remove = HashSet::default();
22216        let mut index = 0;
22217        self.diff_review_overlays.retain(|overlay| {
22218            let has_comments = overlays_with_comments[index];
22219            index += 1;
22220            if !has_comments {
22221                block_ids_to_remove.insert(overlay.block_id);
22222            }
22223            has_comments
22224        });
22225
22226        if !block_ids_to_remove.is_empty() {
22227            self.remove_blocks(block_ids_to_remove, None, cx);
22228            cx.notify();
22229        }
22230    }
22231
22232    /// Refreshes the diff review overlay block to update its height and render function.
22233    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
22234    fn refresh_diff_review_overlay_height(
22235        &mut self,
22236        hunk_key: &DiffHunkKey,
22237        _window: &mut Window,
22238        cx: &mut Context<Self>,
22239    ) {
22240        // Extract all needed data from overlay first to avoid borrow conflicts
22241        let snapshot = self.buffer.read(cx).snapshot(cx);
22242        let (comments_expanded, block_id, prompt_editor) = {
22243            let Some(overlay) = self
22244                .diff_review_overlays
22245                .iter()
22246                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22247            else {
22248                return;
22249            };
22250
22251            (
22252                overlay.comments_expanded,
22253                overlay.block_id,
22254                overlay.prompt_editor.clone(),
22255            )
22256        };
22257
22258        // Calculate new height
22259        let snapshot = self.buffer.read(cx).snapshot(cx);
22260        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
22261
22262        // Update the block height using resize_blocks (avoids flicker)
22263        let mut heights = HashMap::default();
22264        heights.insert(block_id, new_height);
22265        self.resize_blocks(heights, None, cx);
22266
22267        // Update the render function using replace_blocks (avoids flicker)
22268        let hunk_key_for_render = hunk_key.clone();
22269        let editor_handle = cx.entity().downgrade();
22270        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
22271            Arc::new(move |cx| {
22272                Self::render_diff_review_overlay(
22273                    &prompt_editor,
22274                    &hunk_key_for_render,
22275                    &editor_handle,
22276                    cx,
22277                )
22278            });
22279
22280        let mut renderers = HashMap::default();
22281        renderers.insert(block_id, render);
22282        self.replace_blocks(renderers, None, cx);
22283    }
22284
22285    /// Action handler for SubmitDiffReviewComment.
22286    pub fn submit_diff_review_comment_action(
22287        &mut self,
22288        _: &SubmitDiffReviewComment,
22289        window: &mut Window,
22290        cx: &mut Context<Self>,
22291    ) {
22292        self.submit_diff_review_comment(window, cx);
22293    }
22294
22295    /// Stores the diff review comment locally.
22296    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22297    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22298        // Find the overlay that currently has focus
22299        let overlay_index = self
22300            .diff_review_overlays
22301            .iter()
22302            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22303        let Some(overlay_index) = overlay_index else {
22304            return;
22305        };
22306        let overlay = &self.diff_review_overlays[overlay_index];
22307
22308        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22309        if comment_text.is_empty() {
22310            return;
22311        }
22312
22313        let anchor_range = overlay.anchor_range.clone();
22314        let hunk_key = overlay.hunk_key.clone();
22315
22316        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22317
22318        // Clear the prompt editor but keep the overlay open
22319        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22320            overlay.prompt_editor.update(cx, |editor, cx| {
22321                editor.clear(window, cx);
22322            });
22323        }
22324
22325        // Refresh the overlay to update the block height for the new comment
22326        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22327
22328        cx.notify();
22329    }
22330
22331    /// Returns the prompt editor for the diff review overlay, if one is active.
22332    /// This is primarily used for testing.
22333    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22334        self.diff_review_overlays
22335            .first()
22336            .map(|overlay| &overlay.prompt_editor)
22337    }
22338
22339    /// Returns the line range for the first diff review overlay, if one is active.
22340    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22341    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22342        let overlay = self.diff_review_overlays.first()?;
22343        let snapshot = self.buffer.read(cx).snapshot(cx);
22344        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22345        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22346        let start_row = snapshot
22347            .point_to_buffer_point(start_point)
22348            .map(|(_, p)| p.row)
22349            .unwrap_or(start_point.row);
22350        let end_row = snapshot
22351            .point_to_buffer_point(end_point)
22352            .map(|(_, p)| p.row)
22353            .unwrap_or(end_point.row);
22354        Some((start_row, end_row))
22355    }
22356
22357    /// Sets whether the comments section is expanded in the diff review overlay.
22358    /// This is primarily used for testing.
22359    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22360        for overlay in &mut self.diff_review_overlays {
22361            overlay.comments_expanded = expanded;
22362        }
22363        cx.notify();
22364    }
22365
22366    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22367    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22368        a.file_path == b.file_path
22369            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22370    }
22371
22372    /// Returns comments for a specific hunk, ordered by creation time.
22373    pub fn comments_for_hunk<'a>(
22374        &'a self,
22375        key: &DiffHunkKey,
22376        snapshot: &MultiBufferSnapshot,
22377    ) -> &'a [StoredReviewComment] {
22378        let key_point = key.hunk_start_anchor.to_point(snapshot);
22379        self.stored_review_comments
22380            .iter()
22381            .find(|(k, _)| {
22382                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22383            })
22384            .map(|(_, comments)| comments.as_slice())
22385            .unwrap_or(&[])
22386    }
22387
22388    /// Returns the total count of stored review comments across all hunks.
22389    pub fn total_review_comment_count(&self) -> usize {
22390        self.stored_review_comments
22391            .iter()
22392            .map(|(_, v)| v.len())
22393            .sum()
22394    }
22395
22396    /// Returns the count of comments for a specific hunk.
22397    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22398        let key_point = key.hunk_start_anchor.to_point(snapshot);
22399        self.stored_review_comments
22400            .iter()
22401            .find(|(k, _)| {
22402                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22403            })
22404            .map(|(_, v)| v.len())
22405            .unwrap_or(0)
22406    }
22407
22408    /// Adds a new review comment to a specific hunk.
22409    pub fn add_review_comment(
22410        &mut self,
22411        hunk_key: DiffHunkKey,
22412        comment: String,
22413        anchor_range: Range<Anchor>,
22414        cx: &mut Context<Self>,
22415    ) -> usize {
22416        let id = self.next_review_comment_id;
22417        self.next_review_comment_id += 1;
22418
22419        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22420
22421        let snapshot = self.buffer.read(cx).snapshot(cx);
22422        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22423
22424        // Find existing entry for this hunk or add a new one
22425        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22426            k.file_path == hunk_key.file_path
22427                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22428        }) {
22429            comments.push(stored_comment);
22430        } else {
22431            self.stored_review_comments
22432                .push((hunk_key, vec![stored_comment]));
22433        }
22434
22435        cx.emit(EditorEvent::ReviewCommentsChanged {
22436            total_count: self.total_review_comment_count(),
22437        });
22438        cx.notify();
22439        id
22440    }
22441
22442    /// Removes a review comment by ID from any hunk.
22443    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22444        for (_, comments) in self.stored_review_comments.iter_mut() {
22445            if let Some(index) = comments.iter().position(|c| c.id == id) {
22446                comments.remove(index);
22447                cx.emit(EditorEvent::ReviewCommentsChanged {
22448                    total_count: self.total_review_comment_count(),
22449                });
22450                cx.notify();
22451                return true;
22452            }
22453        }
22454        false
22455    }
22456
22457    /// Updates a review comment's text by ID.
22458    pub fn update_review_comment(
22459        &mut self,
22460        id: usize,
22461        new_comment: String,
22462        cx: &mut Context<Self>,
22463    ) -> bool {
22464        for (_, comments) in self.stored_review_comments.iter_mut() {
22465            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22466                comment.comment = new_comment;
22467                comment.is_editing = false;
22468                cx.emit(EditorEvent::ReviewCommentsChanged {
22469                    total_count: self.total_review_comment_count(),
22470                });
22471                cx.notify();
22472                return true;
22473            }
22474        }
22475        false
22476    }
22477
22478    /// Sets a comment's editing state.
22479    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22480        for (_, comments) in self.stored_review_comments.iter_mut() {
22481            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22482                comment.is_editing = is_editing;
22483                cx.notify();
22484                return;
22485            }
22486        }
22487    }
22488
22489    /// Takes all stored comments from all hunks, clearing the storage.
22490    /// Returns a Vec of (hunk_key, comments) pairs.
22491    pub fn take_all_review_comments(
22492        &mut self,
22493        cx: &mut Context<Self>,
22494    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22495        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22496        self.dismiss_all_diff_review_overlays(cx);
22497        let comments = std::mem::take(&mut self.stored_review_comments);
22498        // Reset the ID counter since all comments have been taken
22499        self.next_review_comment_id = 0;
22500        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22501        cx.notify();
22502        comments
22503    }
22504
22505    /// Removes review comments whose anchors are no longer valid or whose
22506    /// associated diff hunks no longer exist.
22507    ///
22508    /// This should be called when the buffer changes to prevent orphaned comments
22509    /// from accumulating.
22510    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22511        let snapshot = self.buffer.read(cx).snapshot(cx);
22512        let original_count = self.total_review_comment_count();
22513
22514        // Remove comments with invalid hunk anchors
22515        self.stored_review_comments
22516            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22517
22518        // Also clean up individual comments with invalid anchor ranges
22519        for (_, comments) in &mut self.stored_review_comments {
22520            comments.retain(|comment| {
22521                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22522            });
22523        }
22524
22525        // Remove empty hunk entries
22526        self.stored_review_comments
22527            .retain(|(_, comments)| !comments.is_empty());
22528
22529        let new_count = self.total_review_comment_count();
22530        if new_count != original_count {
22531            cx.emit(EditorEvent::ReviewCommentsChanged {
22532                total_count: new_count,
22533            });
22534            cx.notify();
22535        }
22536    }
22537
22538    /// Toggles the expanded state of the comments section in the overlay.
22539    pub fn toggle_review_comments_expanded(
22540        &mut self,
22541        _: &ToggleReviewCommentsExpanded,
22542        window: &mut Window,
22543        cx: &mut Context<Self>,
22544    ) {
22545        // Find the overlay that currently has focus, or use the first one
22546        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22547            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22548                overlay.comments_expanded = !overlay.comments_expanded;
22549                Some(overlay.hunk_key.clone())
22550            } else {
22551                None
22552            }
22553        });
22554
22555        // If no focused overlay found, toggle the first one
22556        let hunk_key = overlay_info.or_else(|| {
22557            self.diff_review_overlays.first_mut().map(|overlay| {
22558                overlay.comments_expanded = !overlay.comments_expanded;
22559                overlay.hunk_key.clone()
22560            })
22561        });
22562
22563        if let Some(hunk_key) = hunk_key {
22564            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22565            cx.notify();
22566        }
22567    }
22568
22569    /// Handles the EditReviewComment action - sets a comment into editing mode.
22570    pub fn edit_review_comment(
22571        &mut self,
22572        action: &EditReviewComment,
22573        window: &mut Window,
22574        cx: &mut Context<Self>,
22575    ) {
22576        let comment_id = action.id;
22577
22578        // Set the comment to editing mode
22579        self.set_comment_editing(comment_id, true, cx);
22580
22581        // Find the overlay that contains this comment and create an inline editor if needed
22582        // First, find which hunk this comment belongs to
22583        let hunk_key = self
22584            .stored_review_comments
22585            .iter()
22586            .find_map(|(key, comments)| {
22587                if comments.iter().any(|c| c.id == comment_id) {
22588                    Some(key.clone())
22589                } else {
22590                    None
22591                }
22592            });
22593
22594        let snapshot = self.buffer.read(cx).snapshot(cx);
22595        if let Some(hunk_key) = hunk_key {
22596            if let Some(overlay) = self
22597                .diff_review_overlays
22598                .iter_mut()
22599                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22600            {
22601                if let std::collections::hash_map::Entry::Vacant(entry) =
22602                    overlay.inline_edit_editors.entry(comment_id)
22603                {
22604                    // Find the comment text
22605                    let comment_text = self
22606                        .stored_review_comments
22607                        .iter()
22608                        .flat_map(|(_, comments)| comments)
22609                        .find(|c| c.id == comment_id)
22610                        .map(|c| c.comment.clone())
22611                        .unwrap_or_default();
22612
22613                    // Create inline editor
22614                    let parent_editor = cx.entity().downgrade();
22615                    let inline_editor = cx.new(|cx| {
22616                        let mut editor = Editor::single_line(window, cx);
22617                        editor.set_text(&*comment_text, window, cx);
22618                        // Select all text for easy replacement
22619                        editor.select_all(&crate::actions::SelectAll, window, cx);
22620                        editor
22621                    });
22622
22623                    // Register the Newline action to confirm the edit
22624                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22625                        inline_editor.register_action({
22626                            let parent_editor = parent_editor.clone();
22627                            move |_: &crate::actions::Newline, window, cx| {
22628                                if let Some(editor) = parent_editor.upgrade() {
22629                                    editor.update(cx, |editor, cx| {
22630                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22631                                    });
22632                                }
22633                            }
22634                        })
22635                    });
22636
22637                    // Store the subscription to keep the action handler alive
22638                    overlay
22639                        .inline_edit_subscriptions
22640                        .insert(comment_id, subscription);
22641
22642                    // Focus the inline editor
22643                    let focus_handle = inline_editor.focus_handle(cx);
22644                    window.focus(&focus_handle, cx);
22645
22646                    entry.insert(inline_editor);
22647                }
22648            }
22649        }
22650
22651        cx.notify();
22652    }
22653
22654    /// Confirms an inline edit of a review comment.
22655    pub fn confirm_edit_review_comment(
22656        &mut self,
22657        comment_id: usize,
22658        _window: &mut Window,
22659        cx: &mut Context<Self>,
22660    ) {
22661        // Get the new text from the inline editor
22662        // Find the overlay containing this comment's inline editor
22663        let snapshot = self.buffer.read(cx).snapshot(cx);
22664        let hunk_key = self
22665            .stored_review_comments
22666            .iter()
22667            .find_map(|(key, comments)| {
22668                if comments.iter().any(|c| c.id == comment_id) {
22669                    Some(key.clone())
22670                } else {
22671                    None
22672                }
22673            });
22674
22675        let new_text = hunk_key
22676            .as_ref()
22677            .and_then(|hunk_key| {
22678                self.diff_review_overlays
22679                    .iter()
22680                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22681            })
22682            .as_ref()
22683            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22684            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22685
22686        if let Some(new_text) = new_text {
22687            if !new_text.is_empty() {
22688                self.update_review_comment(comment_id, new_text, cx);
22689            }
22690        }
22691
22692        // Remove the inline editor and its subscription
22693        if let Some(hunk_key) = hunk_key {
22694            if let Some(overlay) = self
22695                .diff_review_overlays
22696                .iter_mut()
22697                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22698            {
22699                overlay.inline_edit_editors.remove(&comment_id);
22700                overlay.inline_edit_subscriptions.remove(&comment_id);
22701            }
22702        }
22703
22704        // Clear editing state
22705        self.set_comment_editing(comment_id, false, cx);
22706    }
22707
22708    /// Cancels an inline edit of a review comment.
22709    pub fn cancel_edit_review_comment(
22710        &mut self,
22711        comment_id: usize,
22712        _window: &mut Window,
22713        cx: &mut Context<Self>,
22714    ) {
22715        // Find which hunk this comment belongs to
22716        let hunk_key = self
22717            .stored_review_comments
22718            .iter()
22719            .find_map(|(key, comments)| {
22720                if comments.iter().any(|c| c.id == comment_id) {
22721                    Some(key.clone())
22722                } else {
22723                    None
22724                }
22725            });
22726
22727        // Remove the inline editor and its subscription
22728        if let Some(hunk_key) = hunk_key {
22729            let snapshot = self.buffer.read(cx).snapshot(cx);
22730            if let Some(overlay) = self
22731                .diff_review_overlays
22732                .iter_mut()
22733                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22734            {
22735                overlay.inline_edit_editors.remove(&comment_id);
22736                overlay.inline_edit_subscriptions.remove(&comment_id);
22737            }
22738        }
22739
22740        // Clear editing state
22741        self.set_comment_editing(comment_id, false, cx);
22742    }
22743
22744    /// Action handler for ConfirmEditReviewComment.
22745    pub fn confirm_edit_review_comment_action(
22746        &mut self,
22747        action: &ConfirmEditReviewComment,
22748        window: &mut Window,
22749        cx: &mut Context<Self>,
22750    ) {
22751        self.confirm_edit_review_comment(action.id, window, cx);
22752    }
22753
22754    /// Action handler for CancelEditReviewComment.
22755    pub fn cancel_edit_review_comment_action(
22756        &mut self,
22757        action: &CancelEditReviewComment,
22758        window: &mut Window,
22759        cx: &mut Context<Self>,
22760    ) {
22761        self.cancel_edit_review_comment(action.id, window, cx);
22762    }
22763
22764    /// Handles the DeleteReviewComment action - removes a comment.
22765    pub fn delete_review_comment(
22766        &mut self,
22767        action: &DeleteReviewComment,
22768        window: &mut Window,
22769        cx: &mut Context<Self>,
22770    ) {
22771        // Get the hunk key before removing the comment
22772        // Find the hunk key from the comment itself
22773        let comment_id = action.id;
22774        let hunk_key = self
22775            .stored_review_comments
22776            .iter()
22777            .find_map(|(key, comments)| {
22778                if comments.iter().any(|c| c.id == comment_id) {
22779                    Some(key.clone())
22780                } else {
22781                    None
22782                }
22783            });
22784
22785        // Also get it from the overlay for refresh purposes
22786        let overlay_hunk_key = self
22787            .diff_review_overlays
22788            .first()
22789            .map(|o| o.hunk_key.clone());
22790
22791        self.remove_review_comment(action.id, cx);
22792
22793        // Refresh the overlay height after removing a comment
22794        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22795            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22796        }
22797    }
22798
22799    fn render_diff_review_overlay(
22800        prompt_editor: &Entity<Editor>,
22801        hunk_key: &DiffHunkKey,
22802        editor_handle: &WeakEntity<Editor>,
22803        cx: &mut BlockContext,
22804    ) -> AnyElement {
22805        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22806            if ranges.is_empty() {
22807                return None;
22808            }
22809            let formatted: Vec<String> = ranges
22810                .iter()
22811                .map(|(start, end)| {
22812                    let start_line = start + 1;
22813                    let end_line = end + 1;
22814                    if start_line == end_line {
22815                        format!("Line {start_line}")
22816                    } else {
22817                        format!("Lines {start_line}-{end_line}")
22818                    }
22819                })
22820                .collect();
22821            // Don't show label for single line in single excerpt
22822            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22823                return None;
22824            }
22825            Some(formatted.join(""))
22826        }
22827
22828        let theme = cx.theme();
22829        let colors = theme.colors();
22830
22831        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22832            editor_handle
22833                .upgrade()
22834                .map(|editor| {
22835                    let editor = editor.read(cx);
22836                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22837                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22838                    let (expanded, editors, avatar_uri, line_ranges) = editor
22839                        .diff_review_overlays
22840                        .iter()
22841                        .find(|overlay| {
22842                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22843                        })
22844                        .map(|o| {
22845                            let start_point = o.anchor_range.start.to_point(&snapshot);
22846                            let end_point = o.anchor_range.end.to_point(&snapshot);
22847                            // Get line ranges per excerpt to detect discontinuities
22848                            let buffer_ranges =
22849                                snapshot.range_to_buffer_ranges(start_point..end_point);
22850                            let ranges: Vec<(u32, u32)> = buffer_ranges
22851                                .iter()
22852                                .map(|(buffer_snapshot, range, _)| {
22853                                    let start = buffer_snapshot.offset_to_point(range.start.0).row;
22854                                    let end = buffer_snapshot.offset_to_point(range.end.0).row;
22855                                    (start, end)
22856                                })
22857                                .collect();
22858                            (
22859                                o.comments_expanded,
22860                                o.inline_edit_editors.clone(),
22861                                o.user_avatar_uri.clone(),
22862                                if ranges.is_empty() {
22863                                    None
22864                                } else {
22865                                    Some(ranges)
22866                                },
22867                            )
22868                        })
22869                        .unwrap_or((true, HashMap::default(), None, None));
22870                    (comments, expanded, editors, avatar_uri, line_ranges)
22871                })
22872                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22873
22874        let comment_count = comments.len();
22875        let avatar_size = px(20.);
22876        let action_icon_size = IconSize::XSmall;
22877
22878        v_flex()
22879            .w_full()
22880            .bg(colors.editor_background)
22881            .border_b_1()
22882            .border_color(colors.border)
22883            .px_2()
22884            .pb_2()
22885            .gap_2()
22886            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22887            .when_some(line_ranges, |el, ranges| {
22888                let label = format_line_ranges(&ranges);
22889                if let Some(label) = label {
22890                    el.child(
22891                        h_flex()
22892                            .w_full()
22893                            .px_2()
22894                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22895                    )
22896                } else {
22897                    el
22898                }
22899            })
22900            // Top row: editable input with user's avatar
22901            .child(
22902                h_flex()
22903                    .w_full()
22904                    .items_center()
22905                    .gap_2()
22906                    .px_2()
22907                    .py_1p5()
22908                    .rounded_md()
22909                    .bg(colors.surface_background)
22910                    .child(
22911                        div()
22912                            .size(avatar_size)
22913                            .flex_shrink_0()
22914                            .rounded_full()
22915                            .overflow_hidden()
22916                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22917                                Avatar::new(avatar_uri.clone())
22918                                    .size(avatar_size)
22919                                    .into_any_element()
22920                            } else {
22921                                Icon::new(IconName::Person)
22922                                    .size(IconSize::Small)
22923                                    .color(ui::Color::Muted)
22924                                    .into_any_element()
22925                            }),
22926                    )
22927                    .child(
22928                        div()
22929                            .flex_1()
22930                            .border_1()
22931                            .border_color(colors.border)
22932                            .rounded_md()
22933                            .bg(colors.editor_background)
22934                            .px_2()
22935                            .py_1()
22936                            .child(prompt_editor.clone()),
22937                    )
22938                    .child(
22939                        h_flex()
22940                            .flex_shrink_0()
22941                            .gap_1()
22942                            .child(
22943                                IconButton::new("diff-review-close", IconName::Close)
22944                                    .icon_color(ui::Color::Muted)
22945                                    .icon_size(action_icon_size)
22946                                    .tooltip(Tooltip::text("Close"))
22947                                    .on_click(|_, window, cx| {
22948                                        window
22949                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22950                                    }),
22951                            )
22952                            .child(
22953                                IconButton::new("diff-review-add", IconName::Return)
22954                                    .icon_color(ui::Color::Muted)
22955                                    .icon_size(action_icon_size)
22956                                    .tooltip(Tooltip::text("Add comment"))
22957                                    .on_click(|_, window, cx| {
22958                                        window.dispatch_action(
22959                                            Box::new(crate::actions::SubmitDiffReviewComment),
22960                                            cx,
22961                                        );
22962                                    }),
22963                            ),
22964                    ),
22965            )
22966            // Expandable comments section (only shown when there are comments)
22967            .when(comment_count > 0, |el| {
22968                el.child(Self::render_comments_section(
22969                    comments,
22970                    comments_expanded,
22971                    inline_editors,
22972                    user_avatar_uri,
22973                    avatar_size,
22974                    action_icon_size,
22975                    colors,
22976                ))
22977            })
22978            .into_any_element()
22979    }
22980
22981    fn render_comments_section(
22982        comments: Vec<StoredReviewComment>,
22983        expanded: bool,
22984        inline_editors: HashMap<usize, Entity<Editor>>,
22985        user_avatar_uri: Option<SharedUri>,
22986        avatar_size: Pixels,
22987        action_icon_size: IconSize,
22988        colors: &theme::ThemeColors,
22989    ) -> impl IntoElement {
22990        let comment_count = comments.len();
22991
22992        v_flex()
22993            .w_full()
22994            .gap_1()
22995            // Header with expand/collapse toggle
22996            .child(
22997                h_flex()
22998                    .id("review-comments-header")
22999                    .w_full()
23000                    .items_center()
23001                    .gap_1()
23002                    .px_2()
23003                    .py_1()
23004                    .cursor_pointer()
23005                    .rounded_md()
23006                    .hover(|style| style.bg(colors.ghost_element_hover))
23007                    .on_click(|_, window: &mut Window, cx| {
23008                        window.dispatch_action(
23009                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
23010                            cx,
23011                        );
23012                    })
23013                    .child(
23014                        Icon::new(if expanded {
23015                            IconName::ChevronDown
23016                        } else {
23017                            IconName::ChevronRight
23018                        })
23019                        .size(IconSize::Small)
23020                        .color(ui::Color::Muted),
23021                    )
23022                    .child(
23023                        Label::new(format!(
23024                            "{} Comment{}",
23025                            comment_count,
23026                            if comment_count == 1 { "" } else { "s" }
23027                        ))
23028                        .size(LabelSize::Small)
23029                        .color(Color::Muted),
23030                    ),
23031            )
23032            // Comments list (when expanded)
23033            .when(expanded, |el| {
23034                el.children(comments.into_iter().map(|comment| {
23035                    let inline_editor = inline_editors.get(&comment.id).cloned();
23036                    Self::render_comment_row(
23037                        comment,
23038                        inline_editor,
23039                        user_avatar_uri.clone(),
23040                        avatar_size,
23041                        action_icon_size,
23042                        colors,
23043                    )
23044                }))
23045            })
23046    }
23047
23048    fn render_comment_row(
23049        comment: StoredReviewComment,
23050        inline_editor: Option<Entity<Editor>>,
23051        user_avatar_uri: Option<SharedUri>,
23052        avatar_size: Pixels,
23053        action_icon_size: IconSize,
23054        colors: &theme::ThemeColors,
23055    ) -> impl IntoElement {
23056        let comment_id = comment.id;
23057        let is_editing = inline_editor.is_some();
23058
23059        h_flex()
23060            .w_full()
23061            .items_center()
23062            .gap_2()
23063            .px_2()
23064            .py_1p5()
23065            .rounded_md()
23066            .bg(colors.surface_background)
23067            .child(
23068                div()
23069                    .size(avatar_size)
23070                    .flex_shrink_0()
23071                    .rounded_full()
23072                    .overflow_hidden()
23073                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
23074                        Avatar::new(avatar_uri.clone())
23075                            .size(avatar_size)
23076                            .into_any_element()
23077                    } else {
23078                        Icon::new(IconName::Person)
23079                            .size(IconSize::Small)
23080                            .color(ui::Color::Muted)
23081                            .into_any_element()
23082                    }),
23083            )
23084            .child(if let Some(editor) = inline_editor {
23085                // Inline edit mode: show an editable text field
23086                div()
23087                    .flex_1()
23088                    .border_1()
23089                    .border_color(colors.border)
23090                    .rounded_md()
23091                    .bg(colors.editor_background)
23092                    .px_2()
23093                    .py_1()
23094                    .child(editor)
23095                    .into_any_element()
23096            } else {
23097                // Display mode: show the comment text
23098                div()
23099                    .flex_1()
23100                    .text_sm()
23101                    .text_color(colors.text)
23102                    .child(comment.comment)
23103                    .into_any_element()
23104            })
23105            .child(if is_editing {
23106                // Editing mode: show close and confirm buttons
23107                h_flex()
23108                    .gap_1()
23109                    .child(
23110                        IconButton::new(
23111                            format!("diff-review-cancel-edit-{comment_id}"),
23112                            IconName::Close,
23113                        )
23114                        .icon_color(ui::Color::Muted)
23115                        .icon_size(action_icon_size)
23116                        .tooltip(Tooltip::text("Cancel"))
23117                        .on_click(move |_, window, cx| {
23118                            window.dispatch_action(
23119                                Box::new(crate::actions::CancelEditReviewComment {
23120                                    id: comment_id,
23121                                }),
23122                                cx,
23123                            );
23124                        }),
23125                    )
23126                    .child(
23127                        IconButton::new(
23128                            format!("diff-review-confirm-edit-{comment_id}"),
23129                            IconName::Return,
23130                        )
23131                        .icon_color(ui::Color::Muted)
23132                        .icon_size(action_icon_size)
23133                        .tooltip(Tooltip::text("Confirm"))
23134                        .on_click(move |_, window, cx| {
23135                            window.dispatch_action(
23136                                Box::new(crate::actions::ConfirmEditReviewComment {
23137                                    id: comment_id,
23138                                }),
23139                                cx,
23140                            );
23141                        }),
23142                    )
23143                    .into_any_element()
23144            } else {
23145                // Display mode: no action buttons for now (edit/delete not yet implemented)
23146                gpui::Empty.into_any_element()
23147            })
23148    }
23149
23150    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
23151        if self.display_map.read(cx).masked != masked {
23152            self.display_map.update(cx, |map, _| map.masked = masked);
23153        }
23154        cx.notify()
23155    }
23156
23157    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
23158        self.show_wrap_guides = Some(show_wrap_guides);
23159        cx.notify();
23160    }
23161
23162    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
23163        self.show_indent_guides = Some(show_indent_guides);
23164        cx.notify();
23165    }
23166
23167    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
23168        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
23169            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
23170                && let Some(dir) = file.abs_path(cx).parent()
23171            {
23172                return Some(dir.to_owned());
23173            }
23174        }
23175
23176        None
23177    }
23178
23179    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
23180        self.active_buffer(cx)?
23181            .read(cx)
23182            .file()
23183            .and_then(|f| f.as_local())
23184    }
23185
23186    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
23187        self.active_buffer(cx).and_then(|buffer| {
23188            let buffer = buffer.read(cx);
23189            if let Some(project_path) = buffer.project_path(cx) {
23190                let project = self.project()?.read(cx);
23191                project.absolute_path(&project_path, cx)
23192            } else {
23193                buffer
23194                    .file()
23195                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
23196            }
23197        })
23198    }
23199
23200    pub fn reveal_in_finder(
23201        &mut self,
23202        _: &RevealInFileManager,
23203        _window: &mut Window,
23204        cx: &mut Context<Self>,
23205    ) {
23206        if let Some(path) = self.target_file_abs_path(cx) {
23207            if let Some(project) = self.project() {
23208                project.update(cx, |project, cx| project.reveal_path(&path, cx));
23209            } else {
23210                cx.reveal_path(&path);
23211            }
23212        }
23213    }
23214
23215    pub fn copy_path(
23216        &mut self,
23217        _: &zed_actions::workspace::CopyPath,
23218        _window: &mut Window,
23219        cx: &mut Context<Self>,
23220    ) {
23221        if let Some(path) = self.target_file_abs_path(cx)
23222            && let Some(path) = path.to_str()
23223        {
23224            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23225        } else {
23226            cx.propagate();
23227        }
23228    }
23229
23230    pub fn copy_relative_path(
23231        &mut self,
23232        _: &zed_actions::workspace::CopyRelativePath,
23233        _window: &mut Window,
23234        cx: &mut Context<Self>,
23235    ) {
23236        if let Some(path) = self.active_buffer(cx).and_then(|buffer| {
23237            let project = self.project()?.read(cx);
23238            let path = buffer.read(cx).file()?.path();
23239            let path = path.display(project.path_style(cx));
23240            Some(path)
23241        }) {
23242            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23243        } else {
23244            cx.propagate();
23245        }
23246    }
23247
23248    /// Returns the project path for the editor's buffer, if any buffer is
23249    /// opened in the editor.
23250    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
23251        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
23252            buffer.read(cx).project_path(cx)
23253        } else {
23254            None
23255        }
23256    }
23257
23258    // Returns true if the editor handled a go-to-line request
23259    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
23260        maybe!({
23261            let breakpoint_store = self.breakpoint_store.as_ref()?;
23262
23263            let (active_stack_frame, debug_line_pane_id) = {
23264                let store = breakpoint_store.read(cx);
23265                let active_stack_frame = store.active_position().cloned();
23266                let debug_line_pane_id = store.active_debug_line_pane_id();
23267                (active_stack_frame, debug_line_pane_id)
23268            };
23269
23270            let Some(active_stack_frame) = active_stack_frame else {
23271                self.clear_row_highlights::<ActiveDebugLine>();
23272                return None;
23273            };
23274
23275            if let Some(debug_line_pane_id) = debug_line_pane_id {
23276                if let Some(workspace) = self
23277                    .workspace
23278                    .as_ref()
23279                    .and_then(|(workspace, _)| workspace.upgrade())
23280                {
23281                    let editor_pane_id = workspace
23282                        .read(cx)
23283                        .pane_for_item_id(cx.entity_id())
23284                        .map(|pane| pane.entity_id());
23285
23286                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
23287                        self.clear_row_highlights::<ActiveDebugLine>();
23288                        return None;
23289                    }
23290                }
23291            }
23292
23293            let position = active_stack_frame.position;
23294
23295            let snapshot = self.buffer.read(cx).snapshot(cx);
23296            let multibuffer_anchor = snapshot.anchor_in_excerpt(position)?;
23297
23298            self.clear_row_highlights::<ActiveDebugLine>();
23299
23300            self.go_to_line::<ActiveDebugLine>(
23301                multibuffer_anchor,
23302                Some(cx.theme().colors().editor_debugger_active_line_background),
23303                window,
23304                cx,
23305            );
23306
23307            cx.notify();
23308
23309            Some(())
23310        })
23311        .is_some()
23312    }
23313
23314    pub fn copy_file_name_without_extension(
23315        &mut self,
23316        _: &CopyFileNameWithoutExtension,
23317        _: &mut Window,
23318        cx: &mut Context<Self>,
23319    ) {
23320        if let Some(file_stem) = self.active_buffer(cx).and_then(|buffer| {
23321            let file = buffer.read(cx).file()?;
23322            file.path().file_stem()
23323        }) {
23324            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23325        }
23326    }
23327
23328    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23329        if let Some(file_name) = self.active_buffer(cx).and_then(|buffer| {
23330            let file = buffer.read(cx).file()?;
23331            Some(file.file_name(cx))
23332        }) {
23333            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23334        }
23335    }
23336
23337    pub fn toggle_git_blame(
23338        &mut self,
23339        _: &::git::Blame,
23340        window: &mut Window,
23341        cx: &mut Context<Self>,
23342    ) {
23343        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23344
23345        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23346            self.start_git_blame(true, window, cx);
23347        }
23348
23349        cx.notify();
23350    }
23351
23352    pub fn toggle_git_blame_inline(
23353        &mut self,
23354        _: &ToggleGitBlameInline,
23355        window: &mut Window,
23356        cx: &mut Context<Self>,
23357    ) {
23358        self.toggle_git_blame_inline_internal(true, window, cx);
23359        cx.notify();
23360    }
23361
23362    pub fn open_git_blame_commit(
23363        &mut self,
23364        _: &OpenGitBlameCommit,
23365        window: &mut Window,
23366        cx: &mut Context<Self>,
23367    ) {
23368        self.open_git_blame_commit_internal(window, cx);
23369    }
23370
23371    fn open_git_blame_commit_internal(
23372        &mut self,
23373        window: &mut Window,
23374        cx: &mut Context<Self>,
23375    ) -> Option<()> {
23376        let blame = self.blame.as_ref()?;
23377        let snapshot = self.snapshot(window, cx);
23378        let cursor = self
23379            .selections
23380            .newest::<Point>(&snapshot.display_snapshot)
23381            .head();
23382        let (buffer, point) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23383        let (_, blame_entry) = blame
23384            .update(cx, |blame, cx| {
23385                blame
23386                    .blame_for_rows(
23387                        &[RowInfo {
23388                            buffer_id: Some(buffer.remote_id()),
23389                            buffer_row: Some(point.row),
23390                            ..Default::default()
23391                        }],
23392                        cx,
23393                    )
23394                    .next()
23395            })
23396            .flatten()?;
23397        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23398        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23399        let workspace = self.workspace()?.downgrade();
23400        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23401        None
23402    }
23403
23404    pub fn git_blame_inline_enabled(&self) -> bool {
23405        self.git_blame_inline_enabled
23406    }
23407
23408    pub fn toggle_selection_menu(
23409        &mut self,
23410        _: &ToggleSelectionMenu,
23411        _: &mut Window,
23412        cx: &mut Context<Self>,
23413    ) {
23414        self.show_selection_menu = self
23415            .show_selection_menu
23416            .map(|show_selections_menu| !show_selections_menu)
23417            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23418
23419        cx.notify();
23420    }
23421
23422    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23423        self.show_selection_menu
23424            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23425    }
23426
23427    fn start_git_blame(
23428        &mut self,
23429        user_triggered: bool,
23430        window: &mut Window,
23431        cx: &mut Context<Self>,
23432    ) {
23433        if let Some(project) = self.project() {
23434            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23435                && buffer.read(cx).file().is_none()
23436            {
23437                return;
23438            }
23439
23440            let focused = self.focus_handle(cx).contains_focused(window, cx);
23441
23442            let project = project.clone();
23443            let blame = cx
23444                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23445            self.blame_subscription =
23446                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23447            self.blame = Some(blame);
23448        }
23449    }
23450
23451    fn toggle_git_blame_inline_internal(
23452        &mut self,
23453        user_triggered: bool,
23454        window: &mut Window,
23455        cx: &mut Context<Self>,
23456    ) {
23457        if self.git_blame_inline_enabled {
23458            self.git_blame_inline_enabled = false;
23459            self.show_git_blame_inline = false;
23460            self.show_git_blame_inline_delay_task.take();
23461        } else {
23462            self.git_blame_inline_enabled = true;
23463            self.start_git_blame_inline(user_triggered, window, cx);
23464        }
23465
23466        cx.notify();
23467    }
23468
23469    fn start_git_blame_inline(
23470        &mut self,
23471        user_triggered: bool,
23472        window: &mut Window,
23473        cx: &mut Context<Self>,
23474    ) {
23475        self.start_git_blame(user_triggered, window, cx);
23476
23477        if ProjectSettings::get_global(cx)
23478            .git
23479            .inline_blame_delay()
23480            .is_some()
23481        {
23482            self.start_inline_blame_timer(window, cx);
23483        } else {
23484            self.show_git_blame_inline = true
23485        }
23486    }
23487
23488    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23489        self.blame.as_ref()
23490    }
23491
23492    pub fn show_git_blame_gutter(&self) -> bool {
23493        self.show_git_blame_gutter
23494    }
23495
23496    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23497        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23498    }
23499
23500    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23501        self.show_git_blame_inline
23502            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23503            && !self.newest_selection_head_on_empty_line(cx)
23504            && self.has_blame_entries(cx)
23505    }
23506
23507    fn has_blame_entries(&self, cx: &App) -> bool {
23508        self.blame()
23509            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23510    }
23511
23512    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23513        let cursor_anchor = self.selections.newest_anchor().head();
23514
23515        let snapshot = self.buffer.read(cx).snapshot(cx);
23516        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23517
23518        snapshot.line_len(buffer_row) == 0
23519    }
23520
23521    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23522        let buffer_and_selection = maybe!({
23523            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23524            let selection_range = selection.range();
23525
23526            let multi_buffer = self.buffer().read(cx);
23527            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23528            let buffer_ranges = multi_buffer_snapshot
23529                .range_to_buffer_ranges(selection_range.start..selection_range.end);
23530
23531            let (buffer_snapshot, range, _) = if selection.reversed {
23532                buffer_ranges.first()
23533            } else {
23534                buffer_ranges.last()
23535            }?;
23536
23537            let buffer_range = range.to_point(buffer_snapshot);
23538            let buffer = multi_buffer.buffer(buffer_snapshot.remote_id()).unwrap();
23539
23540            let Some(buffer_diff) = multi_buffer.diff_for(buffer_snapshot.remote_id()) else {
23541                return Some((buffer, buffer_range.start.row..buffer_range.end.row));
23542            };
23543
23544            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23545            let start = buffer_diff_snapshot
23546                .buffer_point_to_base_text_point(buffer_range.start, &buffer_snapshot);
23547            let end = buffer_diff_snapshot
23548                .buffer_point_to_base_text_point(buffer_range.end, &buffer_snapshot);
23549
23550            Some((buffer, start.row..end.row))
23551        });
23552
23553        let Some((buffer, selection)) = buffer_and_selection else {
23554            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23555        };
23556
23557        let Some(project) = self.project() else {
23558            return Task::ready(Err(anyhow!("editor does not have project")));
23559        };
23560
23561        project.update(cx, |project, cx| {
23562            project.get_permalink_to_line(&buffer, selection, cx)
23563        })
23564    }
23565
23566    pub fn copy_permalink_to_line(
23567        &mut self,
23568        _: &CopyPermalinkToLine,
23569        window: &mut Window,
23570        cx: &mut Context<Self>,
23571    ) {
23572        let permalink_task = self.get_permalink_to_line(cx);
23573        let workspace = self.workspace();
23574
23575        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23576            Ok(permalink) => {
23577                cx.update(|_, cx| {
23578                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23579                })
23580                .ok();
23581            }
23582            Err(err) => {
23583                let message = format!("Failed to copy permalink: {err}");
23584
23585                anyhow::Result::<()>::Err(err).log_err();
23586
23587                if let Some(workspace) = workspace {
23588                    workspace
23589                        .update_in(cx, |workspace, _, cx| {
23590                            struct CopyPermalinkToLine;
23591
23592                            workspace.show_toast(
23593                                Toast::new(
23594                                    NotificationId::unique::<CopyPermalinkToLine>(),
23595                                    message,
23596                                ),
23597                                cx,
23598                            )
23599                        })
23600                        .ok();
23601                }
23602            }
23603        })
23604        .detach();
23605    }
23606
23607    pub fn copy_file_location(
23608        &mut self,
23609        _: &CopyFileLocation,
23610        _: &mut Window,
23611        cx: &mut Context<Self>,
23612    ) {
23613        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23614
23615        let start_line = selection.start.row + 1;
23616        let end_line = selection.end.row + 1;
23617
23618        let end_line = if selection.end.column == 0 && end_line > start_line {
23619            end_line - 1
23620        } else {
23621            end_line
23622        };
23623
23624        if let Some(file_location) = self.active_buffer(cx).and_then(|buffer| {
23625            let project = self.project()?.read(cx);
23626            let file = buffer.read(cx).file()?;
23627            let path = file.path().display(project.path_style(cx));
23628
23629            let location = if start_line == end_line {
23630                format!("{path}:{start_line}")
23631            } else {
23632                format!("{path}:{start_line}-{end_line}")
23633            };
23634            Some(location)
23635        }) {
23636            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23637        }
23638    }
23639
23640    pub fn open_permalink_to_line(
23641        &mut self,
23642        _: &OpenPermalinkToLine,
23643        window: &mut Window,
23644        cx: &mut Context<Self>,
23645    ) {
23646        let permalink_task = self.get_permalink_to_line(cx);
23647        let workspace = self.workspace();
23648
23649        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23650            Ok(permalink) => {
23651                cx.update(|_, cx| {
23652                    cx.open_url(permalink.as_ref());
23653                })
23654                .ok();
23655            }
23656            Err(err) => {
23657                let message = format!("Failed to open permalink: {err}");
23658
23659                anyhow::Result::<()>::Err(err).log_err();
23660
23661                if let Some(workspace) = workspace {
23662                    workspace.update(cx, |workspace, cx| {
23663                        struct OpenPermalinkToLine;
23664
23665                        workspace.show_toast(
23666                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23667                            cx,
23668                        )
23669                    });
23670                }
23671            }
23672        })
23673        .detach();
23674    }
23675
23676    pub fn insert_uuid_v4(
23677        &mut self,
23678        _: &InsertUuidV4,
23679        window: &mut Window,
23680        cx: &mut Context<Self>,
23681    ) {
23682        self.insert_uuid(UuidVersion::V4, window, cx);
23683    }
23684
23685    pub fn insert_uuid_v7(
23686        &mut self,
23687        _: &InsertUuidV7,
23688        window: &mut Window,
23689        cx: &mut Context<Self>,
23690    ) {
23691        self.insert_uuid(UuidVersion::V7, window, cx);
23692    }
23693
23694    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23695        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23696        self.transact(window, cx, |this, window, cx| {
23697            let edits = this
23698                .selections
23699                .all::<Point>(&this.display_snapshot(cx))
23700                .into_iter()
23701                .map(|selection| {
23702                    let uuid = match version {
23703                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23704                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23705                    };
23706
23707                    (selection.range(), uuid.to_string())
23708                });
23709            this.edit(edits, cx);
23710            this.refresh_edit_prediction(true, false, window, cx);
23711        });
23712    }
23713
23714    pub fn open_selections_in_multibuffer(
23715        &mut self,
23716        _: &OpenSelectionsInMultibuffer,
23717        window: &mut Window,
23718        cx: &mut Context<Self>,
23719    ) {
23720        let multibuffer = self.buffer.read(cx);
23721
23722        let Some(buffer) = multibuffer.as_singleton() else {
23723            return;
23724        };
23725        let buffer_snapshot = buffer.read(cx).snapshot();
23726
23727        let Some(workspace) = self.workspace() else {
23728            return;
23729        };
23730
23731        let title = multibuffer.title(cx).to_string();
23732
23733        let locations = self
23734            .selections
23735            .all_anchors(&self.display_snapshot(cx))
23736            .iter()
23737            .map(|selection| {
23738                (
23739                    buffer.clone(),
23740                    (selection.start.text_anchor_in(&buffer_snapshot)
23741                        ..selection.end.text_anchor_in(&buffer_snapshot))
23742                        .to_point(buffer.read(cx)),
23743                )
23744            })
23745            .into_group_map();
23746
23747        cx.spawn_in(window, async move |_, cx| {
23748            workspace.update_in(cx, |workspace, window, cx| {
23749                Self::open_locations_in_multibuffer(
23750                    workspace,
23751                    locations,
23752                    format!("Selections for '{title}'"),
23753                    false,
23754                    false,
23755                    MultibufferSelectionMode::All,
23756                    window,
23757                    cx,
23758                );
23759            })
23760        })
23761        .detach();
23762    }
23763
23764    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23765    /// last highlight added will be used.
23766    ///
23767    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23768    pub fn highlight_rows<T: 'static>(
23769        &mut self,
23770        range: Range<Anchor>,
23771        color: Hsla,
23772        options: RowHighlightOptions,
23773        cx: &mut Context<Self>,
23774    ) {
23775        let snapshot = self.buffer().read(cx).snapshot(cx);
23776        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23777        let ix = row_highlights.binary_search_by(|highlight| {
23778            Ordering::Equal
23779                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23780                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23781        });
23782
23783        if let Err(mut ix) = ix {
23784            let index = post_inc(&mut self.highlight_order);
23785
23786            // If this range intersects with the preceding highlight, then merge it with
23787            // the preceding highlight. Otherwise insert a new highlight.
23788            let mut merged = false;
23789            if ix > 0 {
23790                let prev_highlight = &mut row_highlights[ix - 1];
23791                if prev_highlight
23792                    .range
23793                    .end
23794                    .cmp(&range.start, &snapshot)
23795                    .is_ge()
23796                {
23797                    ix -= 1;
23798                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23799                        prev_highlight.range.end = range.end;
23800                    }
23801                    merged = true;
23802                    prev_highlight.index = index;
23803                    prev_highlight.color = color;
23804                    prev_highlight.options = options;
23805                }
23806            }
23807
23808            if !merged {
23809                row_highlights.insert(
23810                    ix,
23811                    RowHighlight {
23812                        range,
23813                        index,
23814                        color,
23815                        options,
23816                        type_id: TypeId::of::<T>(),
23817                    },
23818                );
23819            }
23820
23821            // If any of the following highlights intersect with this one, merge them.
23822            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23823                let highlight = &row_highlights[ix];
23824                if next_highlight
23825                    .range
23826                    .start
23827                    .cmp(&highlight.range.end, &snapshot)
23828                    .is_le()
23829                {
23830                    if next_highlight
23831                        .range
23832                        .end
23833                        .cmp(&highlight.range.end, &snapshot)
23834                        .is_gt()
23835                    {
23836                        row_highlights[ix].range.end = next_highlight.range.end;
23837                    }
23838                    row_highlights.remove(ix + 1);
23839                } else {
23840                    break;
23841                }
23842            }
23843        }
23844    }
23845
23846    /// Remove any highlighted row ranges of the given type that intersect the
23847    /// given ranges.
23848    pub fn remove_highlighted_rows<T: 'static>(
23849        &mut self,
23850        ranges_to_remove: Vec<Range<Anchor>>,
23851        cx: &mut Context<Self>,
23852    ) {
23853        let snapshot = self.buffer().read(cx).snapshot(cx);
23854        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23855        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23856        row_highlights.retain(|highlight| {
23857            while let Some(range_to_remove) = ranges_to_remove.peek() {
23858                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23859                    Ordering::Less | Ordering::Equal => {
23860                        ranges_to_remove.next();
23861                    }
23862                    Ordering::Greater => {
23863                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23864                            Ordering::Less | Ordering::Equal => {
23865                                return false;
23866                            }
23867                            Ordering::Greater => break,
23868                        }
23869                    }
23870                }
23871            }
23872
23873            true
23874        })
23875    }
23876
23877    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23878    pub fn clear_row_highlights<T: 'static>(&mut self) {
23879        self.highlighted_rows.remove(&TypeId::of::<T>());
23880    }
23881
23882    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23883    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23884        self.highlighted_rows
23885            .get(&TypeId::of::<T>())
23886            .map_or(&[] as &[_], |vec| vec.as_slice())
23887            .iter()
23888            .map(|highlight| (highlight.range.clone(), highlight.color))
23889    }
23890
23891    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23892    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23893    /// Allows to ignore certain kinds of highlights.
23894    pub fn highlighted_display_rows(
23895        &self,
23896        window: &mut Window,
23897        cx: &mut App,
23898    ) -> BTreeMap<DisplayRow, LineHighlight> {
23899        let snapshot = self.snapshot(window, cx);
23900        let mut used_highlight_orders = HashMap::default();
23901        self.highlighted_rows
23902            .iter()
23903            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23904            .fold(
23905                BTreeMap::<DisplayRow, LineHighlight>::new(),
23906                |mut unique_rows, highlight| {
23907                    let start = highlight.range.start.to_display_point(&snapshot);
23908                    let end = highlight.range.end.to_display_point(&snapshot);
23909                    let start_row = start.row().0;
23910                    let end_row = if !highlight.range.end.is_max() && end.column() == 0 {
23911                        end.row().0.saturating_sub(1)
23912                    } else {
23913                        end.row().0
23914                    };
23915                    for row in start_row..=end_row {
23916                        let used_index =
23917                            used_highlight_orders.entry(row).or_insert(highlight.index);
23918                        if highlight.index >= *used_index {
23919                            *used_index = highlight.index;
23920                            unique_rows.insert(
23921                                DisplayRow(row),
23922                                LineHighlight {
23923                                    include_gutter: highlight.options.include_gutter,
23924                                    border: None,
23925                                    background: highlight.color.into(),
23926                                    type_id: Some(highlight.type_id),
23927                                },
23928                            );
23929                        }
23930                    }
23931                    unique_rows
23932                },
23933            )
23934    }
23935
23936    pub fn highlighted_display_row_for_autoscroll(
23937        &self,
23938        snapshot: &DisplaySnapshot,
23939    ) -> Option<DisplayRow> {
23940        self.highlighted_rows
23941            .values()
23942            .flat_map(|highlighted_rows| highlighted_rows.iter())
23943            .filter_map(|highlight| {
23944                if highlight.options.autoscroll {
23945                    Some(highlight.range.start.to_display_point(snapshot).row())
23946                } else {
23947                    None
23948                }
23949            })
23950            .min()
23951    }
23952
23953    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23954        self.highlight_background(
23955            HighlightKey::SearchWithinRange,
23956            ranges,
23957            |_, colors| colors.colors().editor_document_highlight_read_background,
23958            cx,
23959        )
23960    }
23961
23962    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23963        self.breadcrumb_header = Some(new_header);
23964    }
23965
23966    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23967        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23968    }
23969
23970    pub fn highlight_background(
23971        &mut self,
23972        key: HighlightKey,
23973        ranges: &[Range<Anchor>],
23974        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23975        cx: &mut Context<Self>,
23976    ) {
23977        self.background_highlights
23978            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23979        self.scrollbar_marker_state.dirty = true;
23980        cx.notify();
23981    }
23982
23983    pub fn clear_background_highlights(
23984        &mut self,
23985        key: HighlightKey,
23986        cx: &mut Context<Self>,
23987    ) -> Option<BackgroundHighlight> {
23988        let text_highlights = self.background_highlights.remove(&key)?;
23989        if !text_highlights.1.is_empty() {
23990            self.scrollbar_marker_state.dirty = true;
23991            cx.notify();
23992        }
23993        Some(text_highlights)
23994    }
23995
23996    pub fn highlight_gutter<T: 'static>(
23997        &mut self,
23998        ranges: impl Into<Vec<Range<Anchor>>>,
23999        color_fetcher: fn(&App) -> Hsla,
24000        cx: &mut Context<Self>,
24001    ) {
24002        self.gutter_highlights
24003            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
24004        cx.notify();
24005    }
24006
24007    pub fn clear_gutter_highlights<T: 'static>(
24008        &mut self,
24009        cx: &mut Context<Self>,
24010    ) -> Option<GutterHighlight> {
24011        cx.notify();
24012        self.gutter_highlights.remove(&TypeId::of::<T>())
24013    }
24014
24015    pub fn insert_gutter_highlight<T: 'static>(
24016        &mut self,
24017        range: Range<Anchor>,
24018        color_fetcher: fn(&App) -> Hsla,
24019        cx: &mut Context<Self>,
24020    ) {
24021        let snapshot = self.buffer().read(cx).snapshot(cx);
24022        let mut highlights = self
24023            .gutter_highlights
24024            .remove(&TypeId::of::<T>())
24025            .map(|(_, highlights)| highlights)
24026            .unwrap_or_default();
24027        let ix = highlights.binary_search_by(|highlight| {
24028            Ordering::Equal
24029                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
24030                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
24031        });
24032        if let Err(ix) = ix {
24033            highlights.insert(ix, range);
24034        }
24035        self.gutter_highlights
24036            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
24037    }
24038
24039    pub fn remove_gutter_highlights<T: 'static>(
24040        &mut self,
24041        ranges_to_remove: Vec<Range<Anchor>>,
24042        cx: &mut Context<Self>,
24043    ) {
24044        let snapshot = self.buffer().read(cx).snapshot(cx);
24045        let Some((color_fetcher, mut gutter_highlights)) =
24046            self.gutter_highlights.remove(&TypeId::of::<T>())
24047        else {
24048            return;
24049        };
24050        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
24051        gutter_highlights.retain(|highlight| {
24052            while let Some(range_to_remove) = ranges_to_remove.peek() {
24053                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
24054                    Ordering::Less | Ordering::Equal => {
24055                        ranges_to_remove.next();
24056                    }
24057                    Ordering::Greater => {
24058                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
24059                            Ordering::Less | Ordering::Equal => {
24060                                return false;
24061                            }
24062                            Ordering::Greater => break,
24063                        }
24064                    }
24065                }
24066            }
24067
24068            true
24069        });
24070        self.gutter_highlights
24071            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
24072    }
24073
24074    #[cfg(any(test, feature = "test-support"))]
24075    pub fn all_text_highlights(
24076        &self,
24077        window: &mut Window,
24078        cx: &mut Context<Self>,
24079    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
24080        let snapshot = self.snapshot(window, cx);
24081        self.display_map.update(cx, |display_map, _| {
24082            display_map
24083                .all_text_highlights()
24084                .map(|(_, highlight)| {
24085                    let (style, ranges) = highlight.as_ref();
24086                    (
24087                        *style,
24088                        ranges
24089                            .iter()
24090                            .map(|range| range.clone().to_display_points(&snapshot))
24091                            .collect(),
24092                    )
24093                })
24094                .collect()
24095        })
24096    }
24097
24098    #[cfg(any(test, feature = "test-support"))]
24099    pub fn all_text_background_highlights(
24100        &self,
24101        window: &mut Window,
24102        cx: &mut Context<Self>,
24103    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24104        let snapshot = self.snapshot(window, cx);
24105        let buffer = &snapshot.buffer_snapshot();
24106        let start = buffer.anchor_before(MultiBufferOffset(0));
24107        let end = buffer.anchor_after(buffer.len());
24108        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
24109    }
24110
24111    #[cfg(any(test, feature = "test-support"))]
24112    pub fn sorted_background_highlights_in_range(
24113        &self,
24114        search_range: Range<Anchor>,
24115        display_snapshot: &DisplaySnapshot,
24116        theme: &Theme,
24117    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24118        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
24119        res.sort_by(|a, b| {
24120            a.0.start
24121                .cmp(&b.0.start)
24122                .then_with(|| a.0.end.cmp(&b.0.end))
24123                .then_with(|| a.1.cmp(&b.1))
24124        });
24125        res
24126    }
24127
24128    #[cfg(any(test, feature = "test-support"))]
24129    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
24130        let snapshot = self.buffer().read(cx).snapshot(cx);
24131
24132        let highlights = self
24133            .background_highlights
24134            .get(&HighlightKey::BufferSearchHighlights);
24135
24136        if let Some((_color, ranges)) = highlights {
24137            ranges
24138                .iter()
24139                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
24140                .collect_vec()
24141        } else {
24142            vec![]
24143        }
24144    }
24145
24146    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
24147        self.background_highlights
24148            .get(&key)
24149            .is_some_and(|(_, highlights)| !highlights.is_empty())
24150    }
24151
24152    /// Returns all background highlights for a given range.
24153    ///
24154    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
24155    pub fn background_highlights_in_range(
24156        &self,
24157        search_range: Range<Anchor>,
24158        display_snapshot: &DisplaySnapshot,
24159        theme: &Theme,
24160    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24161        let mut results = Vec::new();
24162        for (color_fetcher, ranges) in self.background_highlights.values() {
24163            let start_ix = match ranges.binary_search_by(|probe| {
24164                let cmp = probe
24165                    .end
24166                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
24167                if cmp.is_gt() {
24168                    Ordering::Greater
24169                } else {
24170                    Ordering::Less
24171                }
24172            }) {
24173                Ok(i) | Err(i) => i,
24174            };
24175            for (index, range) in ranges[start_ix..].iter().enumerate() {
24176                if range
24177                    .start
24178                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24179                    .is_ge()
24180                {
24181                    break;
24182                }
24183
24184                let color = color_fetcher(&(start_ix + index), theme);
24185                let start = range.start.to_display_point(display_snapshot);
24186                let end = range.end.to_display_point(display_snapshot);
24187                results.push((start..end, color))
24188            }
24189        }
24190        results
24191    }
24192
24193    pub fn gutter_highlights_in_range(
24194        &self,
24195        search_range: Range<Anchor>,
24196        display_snapshot: &DisplaySnapshot,
24197        cx: &App,
24198    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24199        let mut results = Vec::new();
24200        for (color_fetcher, ranges) in self.gutter_highlights.values() {
24201            let color = color_fetcher(cx);
24202            let start_ix = match ranges.binary_search_by(|probe| {
24203                let cmp = probe
24204                    .end
24205                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
24206                if cmp.is_gt() {
24207                    Ordering::Greater
24208                } else {
24209                    Ordering::Less
24210                }
24211            }) {
24212                Ok(i) | Err(i) => i,
24213            };
24214            for range in &ranges[start_ix..] {
24215                if range
24216                    .start
24217                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24218                    .is_ge()
24219                {
24220                    break;
24221                }
24222
24223                let start = range.start.to_display_point(display_snapshot);
24224                let end = range.end.to_display_point(display_snapshot);
24225                results.push((start..end, color))
24226            }
24227        }
24228        results
24229    }
24230
24231    /// Get the text ranges corresponding to the redaction query
24232    pub fn redacted_ranges(
24233        &self,
24234        search_range: Range<Anchor>,
24235        display_snapshot: &DisplaySnapshot,
24236        cx: &App,
24237    ) -> Vec<Range<DisplayPoint>> {
24238        display_snapshot
24239            .buffer_snapshot()
24240            .redacted_ranges(search_range, |file| {
24241                if let Some(file) = file {
24242                    file.is_private()
24243                        && EditorSettings::get(
24244                            Some(SettingsLocation {
24245                                worktree_id: file.worktree_id(cx),
24246                                path: file.path().as_ref(),
24247                            }),
24248                            cx,
24249                        )
24250                        .redact_private_values
24251                } else {
24252                    false
24253                }
24254            })
24255            .map(|range| {
24256                range.start.to_display_point(display_snapshot)
24257                    ..range.end.to_display_point(display_snapshot)
24258            })
24259            .collect()
24260    }
24261
24262    pub fn highlight_text_key(
24263        &mut self,
24264        key: HighlightKey,
24265        ranges: Vec<Range<Anchor>>,
24266        style: HighlightStyle,
24267        merge: bool,
24268        cx: &mut Context<Self>,
24269    ) {
24270        self.display_map.update(cx, |map, cx| {
24271            map.highlight_text(key, ranges, style, merge, cx);
24272        });
24273        cx.notify();
24274    }
24275
24276    pub fn highlight_text(
24277        &mut self,
24278        key: HighlightKey,
24279        ranges: Vec<Range<Anchor>>,
24280        style: HighlightStyle,
24281        cx: &mut Context<Self>,
24282    ) {
24283        self.display_map.update(cx, |map, cx| {
24284            map.highlight_text(key, ranges, style, false, cx)
24285        });
24286        cx.notify();
24287    }
24288
24289    pub fn text_highlights<'a>(
24290        &'a self,
24291        key: HighlightKey,
24292        cx: &'a App,
24293    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24294        self.display_map.read(cx).text_highlights(key)
24295    }
24296
24297    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24298        let cleared = self
24299            .display_map
24300            .update(cx, |map, _| map.clear_highlights(key));
24301        if cleared {
24302            cx.notify();
24303        }
24304    }
24305
24306    pub fn clear_highlights_with(
24307        &mut self,
24308        f: &mut dyn FnMut(&HighlightKey) -> bool,
24309        cx: &mut Context<Self>,
24310    ) {
24311        let cleared = self
24312            .display_map
24313            .update(cx, |map, _| map.clear_highlights_with(f));
24314        if cleared {
24315            cx.notify();
24316        }
24317    }
24318
24319    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24320        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24321            && self.focus_handle.is_focused(window)
24322    }
24323
24324    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24325        self.show_cursor_when_unfocused = is_enabled;
24326        cx.notify();
24327    }
24328
24329    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24330        cx.notify();
24331    }
24332
24333    fn on_debug_session_event(
24334        &mut self,
24335        _session: Entity<Session>,
24336        event: &SessionEvent,
24337        cx: &mut Context<Self>,
24338    ) {
24339        if let SessionEvent::InvalidateInlineValue = event {
24340            self.refresh_inline_values(cx);
24341        }
24342    }
24343
24344    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24345        let Some(semantics) = self.semantics_provider.clone() else {
24346            return;
24347        };
24348
24349        if !self.inline_value_cache.enabled {
24350            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24351            self.splice_inlays(&inlays, Vec::new(), cx);
24352            return;
24353        }
24354
24355        let current_execution_position = self
24356            .highlighted_rows
24357            .get(&TypeId::of::<ActiveDebugLine>())
24358            .and_then(|lines| lines.last().map(|line| line.range.end));
24359
24360        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24361            let inline_values = editor
24362                .update(cx, |editor, cx| {
24363                    let Some(current_execution_position) = current_execution_position else {
24364                        return Some(Task::ready(Ok(Vec::new())));
24365                    };
24366
24367                    let (buffer, buffer_anchor) =
24368                        editor.buffer.read_with(cx, |multibuffer, cx| {
24369                            let multibuffer_snapshot = multibuffer.snapshot(cx);
24370                            let (buffer_anchor, _) = multibuffer_snapshot
24371                                .anchor_to_buffer_anchor(current_execution_position)?;
24372                            let buffer = multibuffer.buffer(buffer_anchor.buffer_id)?;
24373                            Some((buffer, buffer_anchor))
24374                        })?;
24375
24376                    let range = buffer.read(cx).anchor_before(0)..buffer_anchor;
24377
24378                    semantics.inline_values(buffer, range, cx)
24379                })
24380                .ok()
24381                .flatten()?
24382                .await
24383                .context("refreshing debugger inlays")
24384                .log_err()?;
24385
24386            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24387
24388            for (buffer_id, inline_value) in inline_values
24389                .into_iter()
24390                .map(|hint| (hint.position.buffer_id, hint))
24391            {
24392                buffer_inline_values
24393                    .entry(buffer_id)
24394                    .or_default()
24395                    .push(inline_value);
24396            }
24397
24398            editor
24399                .update(cx, |editor, cx| {
24400                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24401                    let mut new_inlays = Vec::default();
24402
24403                    for (_buffer_id, inline_values) in buffer_inline_values {
24404                        for hint in inline_values {
24405                            let Some(anchor) = snapshot.anchor_in_excerpt(hint.position) else {
24406                                continue;
24407                            };
24408                            let inlay = Inlay::debugger(
24409                                post_inc(&mut editor.next_inlay_id),
24410                                anchor,
24411                                hint.text(),
24412                            );
24413                            if !inlay.text().chars().contains(&'\n') {
24414                                new_inlays.push(inlay);
24415                            }
24416                        }
24417                    }
24418
24419                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24420                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24421
24422                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24423                })
24424                .ok()?;
24425            Some(())
24426        });
24427    }
24428
24429    fn on_buffer_event(
24430        &mut self,
24431        multibuffer: &Entity<MultiBuffer>,
24432        event: &multi_buffer::Event,
24433        window: &mut Window,
24434        cx: &mut Context<Self>,
24435    ) {
24436        match event {
24437            multi_buffer::Event::Edited {
24438                edited_buffer,
24439                is_local,
24440            } => {
24441                self.scrollbar_marker_state.dirty = true;
24442                self.active_indent_guides_state.dirty = true;
24443                self.refresh_active_diagnostics(cx);
24444                self.refresh_code_actions(window, cx);
24445                self.refresh_single_line_folds(window, cx);
24446                let snapshot = self.snapshot(window, cx);
24447                self.refresh_matching_bracket_highlights(&snapshot, cx);
24448                self.refresh_outline_symbols_at_cursor(cx);
24449                self.refresh_sticky_headers(&snapshot, cx);
24450                if *is_local && self.has_active_edit_prediction() {
24451                    self.update_visible_edit_prediction(window, cx);
24452                }
24453
24454                // Clean up orphaned review comments after edits
24455                self.cleanup_orphaned_review_comments(cx);
24456
24457                if let Some(buffer) = edited_buffer {
24458                    if buffer.read(cx).file().is_none() {
24459                        cx.emit(EditorEvent::TitleChanged);
24460                    }
24461
24462                    if self.project.is_some() {
24463                        let buffer_id = buffer.read(cx).remote_id();
24464                        self.register_buffer(buffer_id, cx);
24465                        self.update_lsp_data(Some(buffer_id), window, cx);
24466                        self.refresh_inlay_hints(
24467                            InlayHintRefreshReason::BufferEdited(buffer_id),
24468                            cx,
24469                        );
24470                    }
24471                }
24472
24473                cx.emit(EditorEvent::BufferEdited);
24474                cx.emit(SearchEvent::MatchesInvalidated);
24475
24476                let Some(project) = &self.project else { return };
24477                let (telemetry, is_via_ssh) = {
24478                    let project = project.read(cx);
24479                    let telemetry = project.client().telemetry().clone();
24480                    let is_via_ssh = project.is_via_remote_server();
24481                    (telemetry, is_via_ssh)
24482                };
24483                telemetry.log_edit_event("editor", is_via_ssh);
24484            }
24485            multi_buffer::Event::BufferRangesUpdated {
24486                buffer,
24487                ranges,
24488                path_key,
24489            } => {
24490                self.refresh_document_highlights(cx);
24491                let buffer_id = buffer.read(cx).remote_id();
24492                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24493                    && let Some(project) = &self.project
24494                {
24495                    update_uncommitted_diff_for_buffer(
24496                        cx.entity(),
24497                        project,
24498                        [buffer.clone()],
24499                        self.buffer.clone(),
24500                        cx,
24501                    )
24502                    .detach();
24503                }
24504                self.register_visible_buffers(cx);
24505                self.update_lsp_data(Some(buffer_id), window, cx);
24506                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24507                self.refresh_runnables(None, window, cx);
24508                self.bracket_fetched_tree_sitter_chunks
24509                    .retain(|range, _| range.start.buffer_id != buffer_id);
24510                self.colorize_brackets(false, cx);
24511                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24512                self.semantic_token_state.invalidate_buffer(&buffer_id);
24513                cx.emit(EditorEvent::BufferRangesUpdated {
24514                    buffer: buffer.clone(),
24515                    ranges: ranges.clone(),
24516                    path_key: path_key.clone(),
24517                });
24518            }
24519            multi_buffer::Event::BuffersRemoved { removed_buffer_ids } => {
24520                if let Some(inlay_hints) = &mut self.inlay_hints {
24521                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24522                }
24523                self.refresh_inlay_hints(
24524                    InlayHintRefreshReason::BuffersRemoved(removed_buffer_ids.clone()),
24525                    cx,
24526                );
24527                for buffer_id in removed_buffer_ids {
24528                    self.registered_buffers.remove(buffer_id);
24529                    self.clear_runnables(Some(*buffer_id));
24530                    self.semantic_token_state.invalidate_buffer(buffer_id);
24531                    self.display_map.update(cx, |display_map, cx| {
24532                        display_map.invalidate_semantic_highlights(*buffer_id);
24533                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24534                    });
24535                }
24536
24537                self.display_map.update(cx, |display_map, cx| {
24538                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24539                });
24540
24541                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24542                cx.emit(EditorEvent::BuffersRemoved {
24543                    removed_buffer_ids: removed_buffer_ids.clone(),
24544                });
24545            }
24546            multi_buffer::Event::BuffersEdited { buffer_ids } => {
24547                self.display_map.update(cx, |map, cx| {
24548                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24549                });
24550                cx.emit(EditorEvent::BuffersEdited {
24551                    buffer_ids: buffer_ids.clone(),
24552                });
24553            }
24554            multi_buffer::Event::Reparsed(buffer_id) => {
24555                self.refresh_runnables(Some(*buffer_id), window, cx);
24556                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24557                self.colorize_brackets(true, cx);
24558                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24559
24560                cx.emit(EditorEvent::Reparsed(*buffer_id));
24561            }
24562            multi_buffer::Event::DiffHunksToggled => {
24563                self.refresh_runnables(None, window, cx);
24564            }
24565            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24566                if !is_fresh_language {
24567                    self.registered_buffers.remove(&buffer_id);
24568                }
24569                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24570                cx.emit(EditorEvent::Reparsed(*buffer_id));
24571                self.update_edit_prediction_settings(cx);
24572                cx.notify();
24573            }
24574            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24575            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24576            multi_buffer::Event::FileHandleChanged
24577            | multi_buffer::Event::Reloaded
24578            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24579            multi_buffer::Event::DiagnosticsUpdated => {
24580                self.update_diagnostics_state(window, cx);
24581            }
24582            _ => {}
24583        };
24584    }
24585
24586    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24587        if !self.diagnostics_enabled() {
24588            return;
24589        }
24590        self.refresh_active_diagnostics(cx);
24591        self.refresh_inline_diagnostics(true, window, cx);
24592        self.scrollbar_marker_state.dirty = true;
24593        cx.notify();
24594    }
24595
24596    pub fn start_temporary_diff_override(&mut self) {
24597        self.load_diff_task.take();
24598        self.temporary_diff_override = true;
24599    }
24600
24601    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24602        self.temporary_diff_override = false;
24603        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24604        self.buffer.update(cx, |buffer, cx| {
24605            buffer.set_all_diff_hunks_collapsed(cx);
24606        });
24607
24608        if let Some(project) = self.project.clone() {
24609            self.load_diff_task = Some(
24610                update_uncommitted_diff_for_buffer(
24611                    cx.entity(),
24612                    &project,
24613                    self.buffer.read(cx).all_buffers(),
24614                    self.buffer.clone(),
24615                    cx,
24616                )
24617                .shared(),
24618            );
24619        }
24620    }
24621
24622    fn on_display_map_changed(
24623        &mut self,
24624        _: Entity<DisplayMap>,
24625        _: &mut Window,
24626        cx: &mut Context<Self>,
24627    ) {
24628        cx.notify();
24629    }
24630
24631    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24632        if !self.mode.is_full() {
24633            return None;
24634        }
24635
24636        let theme_settings = theme_settings::ThemeSettings::get_global(cx);
24637        let theme = cx.theme();
24638        let accent_colors = theme.accents().clone();
24639
24640        let accent_overrides = theme_settings
24641            .theme_overrides
24642            .get(theme.name.as_ref())
24643            .map(|theme_style| &theme_style.accents)
24644            .into_iter()
24645            .flatten()
24646            .chain(
24647                theme_settings
24648                    .experimental_theme_overrides
24649                    .as_ref()
24650                    .map(|overrides| &overrides.accents)
24651                    .into_iter()
24652                    .flatten(),
24653            )
24654            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24655            .collect();
24656
24657        Some(AccentData {
24658            colors: accent_colors,
24659            overrides: accent_overrides,
24660        })
24661    }
24662
24663    fn fetch_applicable_language_settings(
24664        &self,
24665        cx: &App,
24666    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24667        if !self.mode.is_full() {
24668            return HashMap::default();
24669        }
24670
24671        self.buffer().read(cx).all_buffers().into_iter().fold(
24672            HashMap::default(),
24673            |mut acc, buffer| {
24674                let buffer = buffer.read(cx);
24675                let language = buffer.language().map(|language| language.name());
24676                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24677                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24678                }
24679                acc
24680            },
24681        )
24682    }
24683
24684    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24685        let new_language_settings = self.fetch_applicable_language_settings(cx);
24686        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24687        self.applicable_language_settings = new_language_settings;
24688
24689        let new_accents = self.fetch_accent_data(cx);
24690        let accents_changed = new_accents != self.accent_data;
24691        self.accent_data = new_accents;
24692
24693        if self.diagnostics_enabled() {
24694            let new_severity = EditorSettings::get_global(cx)
24695                .diagnostics_max_severity
24696                .unwrap_or(DiagnosticSeverity::Hint);
24697            self.set_max_diagnostics_severity(new_severity, cx);
24698        }
24699        self.refresh_runnables(None, window, cx);
24700        self.update_edit_prediction_settings(cx);
24701        self.refresh_edit_prediction(true, false, window, cx);
24702        self.refresh_inline_values(cx);
24703
24704        let old_cursor_shape = self.cursor_shape;
24705        let old_show_breadcrumbs = self.show_breadcrumbs;
24706
24707        {
24708            let editor_settings = EditorSettings::get_global(cx);
24709            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24710            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24711            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24712            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24713        }
24714
24715        if old_cursor_shape != self.cursor_shape {
24716            cx.emit(EditorEvent::CursorShapeChanged);
24717        }
24718
24719        if old_show_breadcrumbs != self.show_breadcrumbs {
24720            cx.emit(EditorEvent::BreadcrumbsChanged);
24721        }
24722
24723        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24724            let project_settings = ProjectSettings::get_global(cx);
24725            (
24726                project_settings.session.restore_unsaved_buffers,
24727                project_settings.diagnostics.inline.enabled,
24728                project_settings.git.inline_blame.enabled,
24729            )
24730        };
24731        self.buffer_serialization = self
24732            .should_serialize_buffer()
24733            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24734
24735        if self.mode.is_full() {
24736            if self.show_inline_diagnostics != show_inline_diagnostics {
24737                self.show_inline_diagnostics = show_inline_diagnostics;
24738                self.refresh_inline_diagnostics(false, window, cx);
24739            }
24740
24741            if self.git_blame_inline_enabled != inline_blame_enabled {
24742                self.toggle_git_blame_inline_internal(false, window, cx);
24743            }
24744
24745            let minimap_settings = EditorSettings::get_global(cx).minimap;
24746            if self.minimap_visibility != MinimapVisibility::Disabled {
24747                if self.minimap_visibility.settings_visibility()
24748                    != minimap_settings.minimap_enabled()
24749                {
24750                    self.set_minimap_visibility(
24751                        MinimapVisibility::for_mode(self.mode(), cx),
24752                        window,
24753                        cx,
24754                    );
24755                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24756                    minimap_entity.update(cx, |minimap_editor, cx| {
24757                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24758                    })
24759                }
24760            }
24761
24762            if language_settings_changed || accents_changed {
24763                self.colorize_brackets(true, cx);
24764            }
24765
24766            if language_settings_changed {
24767                self.clear_disabled_lsp_folding_ranges(window, cx);
24768                self.refresh_document_symbols(None, cx);
24769            }
24770
24771            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24772                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24773            }) {
24774                if !inlay_splice.is_empty() {
24775                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24776                }
24777                self.refresh_document_colors(None, window, cx);
24778            }
24779
24780            self.refresh_inlay_hints(
24781                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24782                    self.selections.newest_anchor().head(),
24783                    &self.buffer.read(cx).snapshot(cx),
24784                    cx,
24785                )),
24786                cx,
24787            );
24788
24789            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24790                .global_lsp_settings
24791                .semantic_token_rules
24792                .clone();
24793            let semantic_token_rules_changed = self
24794                .semantic_token_state
24795                .update_rules(new_semantic_token_rules);
24796            if language_settings_changed || semantic_token_rules_changed {
24797                self.invalidate_semantic_tokens(None);
24798                self.refresh_semantic_tokens(None, None, cx);
24799            }
24800        }
24801
24802        cx.notify();
24803    }
24804
24805    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24806        if !self.mode.is_full() {
24807            return;
24808        }
24809
24810        let new_accents = self.fetch_accent_data(cx);
24811        if new_accents != self.accent_data {
24812            self.accent_data = new_accents;
24813            self.colorize_brackets(true, cx);
24814        }
24815
24816        self.invalidate_semantic_tokens(None);
24817        self.refresh_semantic_tokens(None, None, cx);
24818    }
24819
24820    pub fn set_searchable(&mut self, searchable: bool) {
24821        self.searchable = searchable;
24822    }
24823
24824    pub fn searchable(&self) -> bool {
24825        self.searchable
24826    }
24827
24828    pub fn open_excerpts_in_split(
24829        &mut self,
24830        _: &OpenExcerptsSplit,
24831        window: &mut Window,
24832        cx: &mut Context<Self>,
24833    ) {
24834        self.open_excerpts_common(None, true, window, cx)
24835    }
24836
24837    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24838        self.open_excerpts_common(None, false, window, cx)
24839    }
24840
24841    pub(crate) fn open_excerpts_common(
24842        &mut self,
24843        jump_data: Option<JumpData>,
24844        split: bool,
24845        window: &mut Window,
24846        cx: &mut Context<Self>,
24847    ) {
24848        if self.buffer.read(cx).is_singleton() {
24849            cx.propagate();
24850            return;
24851        }
24852
24853        let mut new_selections_by_buffer = HashMap::default();
24854        match &jump_data {
24855            Some(JumpData::MultiBufferPoint {
24856                anchor,
24857                position,
24858                line_offset_from_top,
24859            }) => {
24860                if let Some(buffer) = self.buffer.read(cx).buffer(anchor.buffer_id) {
24861                    let buffer_snapshot = buffer.read(cx).snapshot();
24862                    let jump_to_point = if buffer_snapshot.can_resolve(&anchor) {
24863                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24864                    } else {
24865                        buffer_snapshot.clip_point(*position, Bias::Left)
24866                    };
24867                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24868                    new_selections_by_buffer.insert(
24869                        buffer,
24870                        (
24871                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24872                            Some(*line_offset_from_top),
24873                        ),
24874                    );
24875                }
24876            }
24877            Some(JumpData::MultiBufferRow {
24878                row,
24879                line_offset_from_top,
24880            }) => {
24881                let point = MultiBufferPoint::new(row.0, 0);
24882                if let Some((buffer, buffer_point)) =
24883                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24884                {
24885                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24886                    new_selections_by_buffer
24887                        .entry(buffer)
24888                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24889                        .0
24890                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24891                }
24892            }
24893            None => {
24894                let selections = self
24895                    .selections
24896                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24897                let multi_buffer = self.buffer.read(cx);
24898                let multi_buffer_snapshot = multi_buffer.snapshot(cx);
24899                for selection in selections {
24900                    for (snapshot, range, anchor) in multi_buffer_snapshot
24901                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24902                    {
24903                        if let Some((text_anchor, _)) = anchor.and_then(|anchor| {
24904                            multi_buffer_snapshot.anchor_to_buffer_anchor(anchor)
24905                        }) {
24906                            let Some(buffer_handle) = multi_buffer.buffer(text_anchor.buffer_id)
24907                            else {
24908                                continue;
24909                            };
24910                            let offset = text::ToOffset::to_offset(
24911                                &text_anchor,
24912                                &buffer_handle.read(cx).snapshot(),
24913                            );
24914                            let range = BufferOffset(offset)..BufferOffset(offset);
24915                            new_selections_by_buffer
24916                                .entry(buffer_handle)
24917                                .or_insert((Vec::new(), None))
24918                                .0
24919                                .push(range)
24920                        } else {
24921                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24922                            else {
24923                                continue;
24924                            };
24925                            new_selections_by_buffer
24926                                .entry(buffer_handle)
24927                                .or_insert((Vec::new(), None))
24928                                .0
24929                                .push(range)
24930                        }
24931                    }
24932                }
24933            }
24934        }
24935
24936        if self.delegate_open_excerpts {
24937            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24938                .into_iter()
24939                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24940                .collect();
24941            if !selections_by_buffer.is_empty() {
24942                cx.emit(EditorEvent::OpenExcerptsRequested {
24943                    selections_by_buffer,
24944                    split,
24945                });
24946            }
24947            return;
24948        }
24949
24950        let Some(workspace) = self.workspace() else {
24951            cx.propagate();
24952            return;
24953        };
24954
24955        new_selections_by_buffer
24956            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24957
24958        if new_selections_by_buffer.is_empty() {
24959            return;
24960        }
24961
24962        Self::open_buffers_in_workspace(
24963            workspace.downgrade(),
24964            new_selections_by_buffer,
24965            split,
24966            window,
24967            cx,
24968        );
24969    }
24970
24971    pub(crate) fn open_buffers_in_workspace(
24972        workspace: WeakEntity<Workspace>,
24973        new_selections_by_buffer: HashMap<
24974            Entity<language::Buffer>,
24975            (Vec<Range<BufferOffset>>, Option<u32>),
24976        >,
24977        split: bool,
24978        window: &mut Window,
24979        cx: &mut App,
24980    ) {
24981        // We defer the pane interaction because we ourselves are a workspace item
24982        // and activating a new item causes the pane to call a method on us reentrantly,
24983        // which panics if we're on the stack.
24984        window.defer(cx, move |window, cx| {
24985            workspace
24986                .update(cx, |workspace, cx| {
24987                    let pane = if split {
24988                        workspace.adjacent_pane(window, cx)
24989                    } else {
24990                        workspace.active_pane().clone()
24991                    };
24992
24993                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24994                        let buffer_read = buffer.read(cx);
24995                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24996                            (true, project::File::from_dyn(Some(file)).is_some())
24997                        } else {
24998                            (false, false)
24999                        };
25000
25001                        // If project file is none workspace.open_project_item will fail to open the excerpt
25002                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
25003                        // so we check if there's a tab match in that case first
25004                        let editor = (!has_file || !is_project_file)
25005                            .then(|| {
25006                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
25007                                // so `workspace.open_project_item` will never find them, always opening a new editor.
25008                                // Instead, we try to activate the existing editor in the pane first.
25009                                let (editor, pane_item_index, pane_item_id) =
25010                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
25011                                        let editor = item.downcast::<Editor>()?;
25012                                        let singleton_buffer =
25013                                            editor.read(cx).buffer().read(cx).as_singleton()?;
25014                                        if singleton_buffer == buffer {
25015                                            Some((editor, i, item.item_id()))
25016                                        } else {
25017                                            None
25018                                        }
25019                                    })?;
25020                                pane.update(cx, |pane, cx| {
25021                                    pane.activate_item(pane_item_index, true, true, window, cx);
25022                                    if !PreviewTabsSettings::get_global(cx)
25023                                        .enable_preview_from_multibuffer
25024                                    {
25025                                        pane.unpreview_item_if_preview(pane_item_id);
25026                                    }
25027                                });
25028                                Some(editor)
25029                            })
25030                            .flatten()
25031                            .unwrap_or_else(|| {
25032                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
25033                                    .enable_keep_preview_on_code_navigation;
25034                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
25035                                    .enable_preview_from_multibuffer;
25036                                workspace.open_project_item::<Self>(
25037                                    pane.clone(),
25038                                    buffer,
25039                                    true,
25040                                    true,
25041                                    keep_old_preview,
25042                                    allow_new_preview,
25043                                    window,
25044                                    cx,
25045                                )
25046                            });
25047
25048                        editor.update(cx, |editor, cx| {
25049                            if has_file && !is_project_file {
25050                                editor.set_read_only(true);
25051                            }
25052                            let autoscroll = match scroll_offset {
25053                                Some(scroll_offset) => {
25054                                    Autoscroll::top_relative(scroll_offset as usize)
25055                                }
25056                                None => Autoscroll::newest(),
25057                            };
25058                            let nav_history = editor.nav_history.take();
25059                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
25060                            let Some(buffer_snapshot) = multibuffer_snapshot.as_singleton() else {
25061                                return;
25062                            };
25063                            editor.change_selections(
25064                                SelectionEffects::scroll(autoscroll),
25065                                window,
25066                                cx,
25067                                |s| {
25068                                    s.select_ranges(ranges.into_iter().map(|range| {
25069                                        let range = buffer_snapshot.anchor_before(range.start)
25070                                            ..buffer_snapshot.anchor_after(range.end);
25071                                        multibuffer_snapshot
25072                                            .buffer_anchor_range_to_anchor_range(range)
25073                                            .unwrap()
25074                                    }));
25075                                },
25076                            );
25077                            editor.nav_history = nav_history;
25078                        });
25079                    }
25080                })
25081                .ok();
25082        });
25083    }
25084
25085    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
25086        let snapshot = self.buffer.read(cx).read(cx);
25087        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
25088        Some(
25089            ranges
25090                .iter()
25091                .map(move |range| {
25092                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
25093                })
25094                .collect(),
25095        )
25096    }
25097
25098    fn selection_replacement_ranges(
25099        &self,
25100        range: Range<MultiBufferOffsetUtf16>,
25101        cx: &mut App,
25102    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
25103        let selections = self
25104            .selections
25105            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25106        let newest_selection = selections
25107            .iter()
25108            .max_by_key(|selection| selection.id)
25109            .unwrap();
25110        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
25111        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
25112        let snapshot = self.buffer.read(cx).read(cx);
25113        selections
25114            .into_iter()
25115            .map(|mut selection| {
25116                selection.start.0.0 =
25117                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
25118                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
25119                snapshot.clip_offset_utf16(selection.start, Bias::Left)
25120                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
25121            })
25122            .collect()
25123    }
25124
25125    fn report_editor_event(
25126        &self,
25127        reported_event: ReportEditorEvent,
25128        file_extension: Option<String>,
25129        cx: &App,
25130    ) {
25131        if cfg!(any(test, feature = "test-support")) {
25132            return;
25133        }
25134
25135        let Some(project) = &self.project else { return };
25136
25137        // If None, we are in a file without an extension
25138        let file = self
25139            .buffer
25140            .read(cx)
25141            .as_singleton()
25142            .and_then(|b| b.read(cx).file());
25143        let file_extension = file_extension.or(file
25144            .as_ref()
25145            .and_then(|file| Path::new(file.file_name(cx)).extension())
25146            .and_then(|e| e.to_str())
25147            .map(|a| a.to_string()));
25148
25149        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
25150            .map(|vim_mode| vim_mode.0)
25151            .unwrap_or(false);
25152
25153        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
25154        let copilot_enabled = edit_predictions_provider
25155            == language::language_settings::EditPredictionProvider::Copilot;
25156        let copilot_enabled_for_language = self
25157            .buffer
25158            .read(cx)
25159            .language_settings(cx)
25160            .show_edit_predictions;
25161
25162        let project = project.read(cx);
25163        let event_type = reported_event.event_type();
25164
25165        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
25166            telemetry::event!(
25167                event_type,
25168                type = if auto_saved {"autosave"} else {"manual"},
25169                file_extension,
25170                vim_mode,
25171                copilot_enabled,
25172                copilot_enabled_for_language,
25173                edit_predictions_provider,
25174                is_via_ssh = project.is_via_remote_server(),
25175            );
25176        } else {
25177            telemetry::event!(
25178                event_type,
25179                file_extension,
25180                vim_mode,
25181                copilot_enabled,
25182                copilot_enabled_for_language,
25183                edit_predictions_provider,
25184                is_via_ssh = project.is_via_remote_server(),
25185            );
25186        };
25187    }
25188
25189    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
25190    /// with each line being an array of {text, highlight} objects.
25191    fn copy_highlight_json(
25192        &mut self,
25193        _: &CopyHighlightJson,
25194        _: &mut Window,
25195        cx: &mut Context<Self>,
25196    ) {
25197        #[derive(Serialize)]
25198        struct Chunk<'a> {
25199            text: String,
25200            highlight: Option<&'a str>,
25201        }
25202
25203        let snapshot = self.buffer.read(cx).snapshot(cx);
25204        let mut selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
25205        let max_point = snapshot.max_point();
25206
25207        let range = if self.selections.line_mode() {
25208            selection.start = Point::new(selection.start.row, 0);
25209            selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
25210            selection.goal = SelectionGoal::None;
25211            selection.range()
25212        } else if selection.is_empty() {
25213            Point::new(0, 0)..max_point
25214        } else {
25215            selection.range()
25216        };
25217
25218        let chunks = snapshot.chunks(
25219            range,
25220            LanguageAwareStyling {
25221                tree_sitter: true,
25222                diagnostics: true,
25223            },
25224        );
25225        let mut lines = Vec::new();
25226        let mut line: VecDeque<Chunk> = VecDeque::new();
25227
25228        let Some(style) = self.style.as_ref() else {
25229            return;
25230        };
25231
25232        for chunk in chunks {
25233            let highlight = chunk
25234                .syntax_highlight_id
25235                .and_then(|id| style.syntax.get_capture_name(id));
25236
25237            let mut chunk_lines = chunk.text.split('\n').peekable();
25238            while let Some(text) = chunk_lines.next() {
25239                let mut merged_with_last_token = false;
25240                if let Some(last_token) = line.back_mut()
25241                    && last_token.highlight == highlight
25242                {
25243                    last_token.text.push_str(text);
25244                    merged_with_last_token = true;
25245                }
25246
25247                if !merged_with_last_token {
25248                    line.push_back(Chunk {
25249                        text: text.into(),
25250                        highlight,
25251                    });
25252                }
25253
25254                if chunk_lines.peek().is_some() {
25255                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25256                        line.pop_front();
25257                    }
25258                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25259                        line.pop_back();
25260                    }
25261
25262                    lines.push(mem::take(&mut line));
25263                }
25264            }
25265        }
25266
25267        if line.iter().any(|chunk| !chunk.text.is_empty()) {
25268            lines.push(line);
25269        }
25270
25271        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25272            return;
25273        };
25274        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25275    }
25276
25277    pub fn open_context_menu(
25278        &mut self,
25279        _: &OpenContextMenu,
25280        window: &mut Window,
25281        cx: &mut Context<Self>,
25282    ) {
25283        self.request_autoscroll(Autoscroll::newest(), cx);
25284        let position = self
25285            .selections
25286            .newest_display(&self.display_snapshot(cx))
25287            .start;
25288        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25289    }
25290
25291    pub fn replay_insert_event(
25292        &mut self,
25293        text: &str,
25294        relative_utf16_range: Option<Range<isize>>,
25295        window: &mut Window,
25296        cx: &mut Context<Self>,
25297    ) {
25298        if !self.input_enabled {
25299            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25300            return;
25301        }
25302        if let Some(relative_utf16_range) = relative_utf16_range {
25303            let selections = self
25304                .selections
25305                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25306            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25307                let new_ranges = selections.into_iter().map(|range| {
25308                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25309                        range
25310                            .head()
25311                            .0
25312                            .0
25313                            .saturating_add_signed(relative_utf16_range.start),
25314                    ));
25315                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25316                        range
25317                            .head()
25318                            .0
25319                            .0
25320                            .saturating_add_signed(relative_utf16_range.end),
25321                    ));
25322                    start..end
25323                });
25324                s.select_ranges(new_ranges);
25325            });
25326        }
25327
25328        self.handle_input(text, window, cx);
25329    }
25330
25331    pub fn is_focused(&self, window: &Window) -> bool {
25332        self.focus_handle.is_focused(window)
25333    }
25334
25335    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25336        cx.emit(EditorEvent::Focused);
25337
25338        if let Some(descendant) = self
25339            .last_focused_descendant
25340            .take()
25341            .and_then(|descendant| descendant.upgrade())
25342        {
25343            window.focus(&descendant, cx);
25344        } else {
25345            if let Some(blame) = self.blame.as_ref() {
25346                blame.update(cx, GitBlame::focus)
25347            }
25348
25349            self.blink_manager.update(cx, BlinkManager::enable);
25350            self.show_cursor_names(window, cx);
25351            self.buffer.update(cx, |buffer, cx| {
25352                buffer.finalize_last_transaction(cx);
25353                if self.leader_id.is_none() {
25354                    buffer.set_active_selections(
25355                        &self.selections.disjoint_anchors_arc(),
25356                        self.selections.line_mode(),
25357                        self.cursor_shape,
25358                        cx,
25359                    );
25360                }
25361            });
25362
25363            if let Some(position_map) = self.last_position_map.clone()
25364                && !self.mouse_cursor_hidden
25365            {
25366                EditorElement::mouse_moved(
25367                    self,
25368                    &MouseMoveEvent {
25369                        position: window.mouse_position(),
25370                        pressed_button: None,
25371                        modifiers: window.modifiers(),
25372                    },
25373                    &position_map,
25374                    None,
25375                    window,
25376                    cx,
25377                );
25378            }
25379        }
25380    }
25381
25382    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25383        cx.emit(EditorEvent::FocusedIn)
25384    }
25385
25386    fn handle_focus_out(
25387        &mut self,
25388        event: FocusOutEvent,
25389        _window: &mut Window,
25390        cx: &mut Context<Self>,
25391    ) {
25392        if event.blurred != self.focus_handle {
25393            self.last_focused_descendant = Some(event.blurred);
25394        }
25395        self.selection_drag_state = SelectionDragState::None;
25396        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25397    }
25398
25399    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25400        self.blink_manager.update(cx, BlinkManager::disable);
25401        self.buffer
25402            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25403
25404        if let Some(blame) = self.blame.as_ref() {
25405            blame.update(cx, GitBlame::blur)
25406        }
25407        if !self.hover_state.focused(window, cx) {
25408            hide_hover(self, cx);
25409        }
25410        if !self
25411            .context_menu
25412            .borrow()
25413            .as_ref()
25414            .is_some_and(|context_menu| context_menu.focused(window, cx))
25415        {
25416            self.hide_context_menu(window, cx);
25417        }
25418        self.take_active_edit_prediction(true, cx);
25419        cx.emit(EditorEvent::Blurred);
25420        cx.notify();
25421    }
25422
25423    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25424        let mut pending: String = window
25425            .pending_input_keystrokes()
25426            .into_iter()
25427            .flatten()
25428            .filter_map(|keystroke| keystroke.key_char.clone())
25429            .collect();
25430
25431        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25432            pending = "".to_string();
25433        }
25434
25435        let existing_pending = self
25436            .text_highlights(HighlightKey::PendingInput, cx)
25437            .map(|(_, ranges)| ranges.to_vec());
25438        if existing_pending.is_none() && pending.is_empty() {
25439            return;
25440        }
25441        let transaction =
25442            self.transact(window, cx, |this, window, cx| {
25443                let selections = this
25444                    .selections
25445                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25446                let edits = selections
25447                    .iter()
25448                    .map(|selection| (selection.end..selection.end, pending.clone()));
25449                this.edit(edits, cx);
25450                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25451                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25452                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25453                    }));
25454                });
25455                if let Some(existing_ranges) = existing_pending {
25456                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25457                    this.edit(edits, cx);
25458                }
25459            });
25460
25461        let snapshot = self.snapshot(window, cx);
25462        let ranges = self
25463            .selections
25464            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25465            .into_iter()
25466            .map(|selection| {
25467                snapshot.buffer_snapshot().anchor_after(selection.end)
25468                    ..snapshot
25469                        .buffer_snapshot()
25470                        .anchor_before(selection.end + pending.len())
25471            })
25472            .collect();
25473
25474        if pending.is_empty() {
25475            self.clear_highlights(HighlightKey::PendingInput, cx);
25476        } else {
25477            self.highlight_text(
25478                HighlightKey::PendingInput,
25479                ranges,
25480                HighlightStyle {
25481                    underline: Some(UnderlineStyle {
25482                        thickness: px(1.),
25483                        color: None,
25484                        wavy: false,
25485                    }),
25486                    ..Default::default()
25487                },
25488                cx,
25489            );
25490        }
25491
25492        self.ime_transaction = self.ime_transaction.or(transaction);
25493        if let Some(transaction) = self.ime_transaction {
25494            self.buffer.update(cx, |buffer, cx| {
25495                buffer.group_until_transaction(transaction, cx);
25496            });
25497        }
25498
25499        if self
25500            .text_highlights(HighlightKey::PendingInput, cx)
25501            .is_none()
25502        {
25503            self.ime_transaction.take();
25504        }
25505    }
25506
25507    pub fn register_action_renderer(
25508        &mut self,
25509        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25510    ) -> Subscription {
25511        let id = self.next_editor_action_id.post_inc();
25512        self.editor_actions
25513            .borrow_mut()
25514            .insert(id, Box::new(listener));
25515
25516        let editor_actions = self.editor_actions.clone();
25517        Subscription::new(move || {
25518            editor_actions.borrow_mut().remove(&id);
25519        })
25520    }
25521
25522    pub fn register_action<A: Action>(
25523        &mut self,
25524        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25525    ) -> Subscription {
25526        let id = self.next_editor_action_id.post_inc();
25527        let listener = Arc::new(listener);
25528        self.editor_actions.borrow_mut().insert(
25529            id,
25530            Box::new(move |_, window, _| {
25531                let listener = listener.clone();
25532                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25533                    let action = action.downcast_ref().unwrap();
25534                    if phase == DispatchPhase::Bubble {
25535                        listener(action, window, cx)
25536                    }
25537                })
25538            }),
25539        );
25540
25541        let editor_actions = self.editor_actions.clone();
25542        Subscription::new(move || {
25543            editor_actions.borrow_mut().remove(&id);
25544        })
25545    }
25546
25547    pub fn file_header_size(&self) -> u32 {
25548        FILE_HEADER_HEIGHT
25549    }
25550
25551    pub fn restore(
25552        &mut self,
25553        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25554        window: &mut Window,
25555        cx: &mut Context<Self>,
25556    ) {
25557        self.buffer().update(cx, |multi_buffer, cx| {
25558            for (buffer_id, changes) in revert_changes {
25559                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25560                    buffer.update(cx, |buffer, cx| {
25561                        buffer.edit(
25562                            changes
25563                                .into_iter()
25564                                .map(|(range, text)| (range, text.to_string())),
25565                            None,
25566                            cx,
25567                        );
25568                    });
25569                }
25570            }
25571        });
25572        let selections = self
25573            .selections
25574            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
25575        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25576            s.select(selections);
25577        });
25578    }
25579
25580    pub fn to_pixel_point(
25581        &mut self,
25582        source: Anchor,
25583        editor_snapshot: &EditorSnapshot,
25584        window: &mut Window,
25585        cx: &mut App,
25586    ) -> Option<gpui::Point<Pixels>> {
25587        let source_point = source.to_display_point(editor_snapshot);
25588        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25589    }
25590
25591    pub fn display_to_pixel_point(
25592        &mut self,
25593        source: DisplayPoint,
25594        editor_snapshot: &EditorSnapshot,
25595        window: &mut Window,
25596        cx: &mut App,
25597    ) -> Option<gpui::Point<Pixels>> {
25598        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25599        let text_layout_details = self.text_layout_details(window, cx);
25600        let scroll_top = text_layout_details
25601            .scroll_anchor
25602            .scroll_position(editor_snapshot)
25603            .y;
25604
25605        if source.row().as_f64() < scroll_top.floor() {
25606            return None;
25607        }
25608        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25609        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25610        Some(gpui::Point::new(source_x, source_y))
25611    }
25612
25613    pub fn has_visible_completions_menu(&self) -> bool {
25614        !self.edit_prediction_preview_is_active()
25615            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25616                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25617            })
25618    }
25619
25620    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25621        if self.mode.is_minimap() {
25622            return;
25623        }
25624        self.addons
25625            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25626    }
25627
25628    pub fn unregister_addon<T: Addon>(&mut self) {
25629        self.addons.remove(&std::any::TypeId::of::<T>());
25630    }
25631
25632    pub fn addon<T: Addon>(&self) -> Option<&T> {
25633        let type_id = std::any::TypeId::of::<T>();
25634        self.addons
25635            .get(&type_id)
25636            .and_then(|item| item.to_any().downcast_ref::<T>())
25637    }
25638
25639    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25640        let type_id = std::any::TypeId::of::<T>();
25641        self.addons
25642            .get_mut(&type_id)
25643            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25644    }
25645
25646    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25647        let text_layout_details = self.text_layout_details(window, cx);
25648        let style = &text_layout_details.editor_style;
25649        let font_id = window.text_system().resolve_font(&style.text.font());
25650        let font_size = style.text.font_size.to_pixels(window.rem_size());
25651        let line_height = style.text.line_height_in_pixels(window.rem_size());
25652        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25653        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25654
25655        CharacterDimensions {
25656            em_width,
25657            em_advance,
25658            line_height,
25659        }
25660    }
25661
25662    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25663        self.load_diff_task.clone()
25664    }
25665
25666    fn read_metadata_from_db(
25667        &mut self,
25668        item_id: u64,
25669        workspace_id: WorkspaceId,
25670        window: &mut Window,
25671        cx: &mut Context<Editor>,
25672    ) {
25673        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25674            && !self.mode.is_minimap()
25675            && WorkspaceSettings::get(None, cx).restore_on_startup
25676                != RestoreOnStartupBehavior::EmptyTab
25677        {
25678            let buffer_snapshot = OnceCell::new();
25679
25680            // Get file path for path-based fold lookup
25681            let file_path: Option<Arc<Path>> =
25682                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25683                    project::File::from_dyn(buffer.read(cx).file())
25684                        .map(|file| Arc::from(file.abs_path(cx)))
25685                });
25686
25687            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25688            let db = EditorDb::global(cx);
25689            let (folds, needs_migration) = if let Some(ref path) = file_path {
25690                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25691                    && !folds.is_empty()
25692                {
25693                    (Some(folds), false)
25694                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25695                    && !folds.is_empty()
25696                {
25697                    // Found old editor_folds data, will migrate to file_folds
25698                    (Some(folds), true)
25699                } else {
25700                    (None, false)
25701                }
25702            } else {
25703                // No file path, try editor_folds as fallback
25704                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25705                (folds.filter(|f| !f.is_empty()), false)
25706            };
25707
25708            if let Some(folds) = folds {
25709                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25710                let snapshot_len = snapshot.len().0;
25711
25712                // Helper: search for fingerprint in buffer, return offset if found
25713                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25714                    // Ensure we start at a character boundary (defensive)
25715                    let search_start = snapshot
25716                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25717                        .0;
25718                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25719
25720                    let mut byte_offset = search_start;
25721                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25722                        if byte_offset > search_end {
25723                            break;
25724                        }
25725                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25726                            return Some(byte_offset);
25727                        }
25728                        byte_offset += ch.len_utf8();
25729                    }
25730                    None
25731                };
25732
25733                // Track search position to handle duplicate fingerprints correctly.
25734                // Folds are stored in document order, so we advance after each match.
25735                let mut search_start = 0usize;
25736
25737                // Collect db_folds for migration (only folds with valid fingerprints)
25738                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25739
25740                let valid_folds: Vec<_> = folds
25741                    .into_iter()
25742                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25743                        // Skip folds without fingerprints (old data before migration)
25744                        let sfp = start_fp?;
25745                        let efp = end_fp?;
25746                        let efp_len = efp.len();
25747
25748                        // Fast path: check if fingerprints match at stored offsets
25749                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25750                        let start_matches = stored_start < snapshot_len
25751                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25752                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25753                        let end_matches = efp_check_pos >= stored_start
25754                            && stored_end <= snapshot_len
25755                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25756
25757                        let (new_start, new_end) = if start_matches && end_matches {
25758                            // Offsets unchanged, use stored values
25759                            (stored_start, stored_end)
25760                        } else if sfp == efp {
25761                            // Short fold: identical fingerprints can only match once per search
25762                            // Use stored fold length to compute new_end
25763                            let new_start = find_fingerprint(&sfp, search_start)?;
25764                            let fold_len = stored_end - stored_start;
25765                            let new_end = new_start + fold_len;
25766                            (new_start, new_end)
25767                        } else {
25768                            // Slow path: search for fingerprints in buffer
25769                            let new_start = find_fingerprint(&sfp, search_start)?;
25770                            // Search for end_fp after start, then add efp_len to get actual fold end
25771                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25772                            let new_end = efp_pos + efp_len;
25773                            (new_start, new_end)
25774                        };
25775
25776                        // Advance search position for next fold
25777                        search_start = new_end;
25778
25779                        // Validate fold makes sense (end must be after start)
25780                        if new_end <= new_start {
25781                            return None;
25782                        }
25783
25784                        // Collect for migration if needed
25785                        if needs_migration {
25786                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25787                        }
25788
25789                        Some(
25790                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25791                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25792                        )
25793                    })
25794                    .collect();
25795
25796                if !valid_folds.is_empty() {
25797                    self.fold_ranges(valid_folds, false, window, cx);
25798
25799                    // Migrate from editor_folds to file_folds if we loaded from old table
25800                    if needs_migration {
25801                        if let Some(ref path) = file_path {
25802                            let path = path.clone();
25803                            let db = EditorDb::global(cx);
25804                            cx.spawn(async move |_, _| {
25805                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25806                                    .await
25807                                    .log_err();
25808                            })
25809                            .detach();
25810                        }
25811                    }
25812                }
25813            }
25814
25815            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25816                && !selections.is_empty()
25817            {
25818                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25819                // skip adding the initial selection to selection history
25820                self.selection_history.mode = SelectionHistoryMode::Skipping;
25821                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25822                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25823                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25824                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25825                    }));
25826                });
25827                self.selection_history.mode = SelectionHistoryMode::Normal;
25828            };
25829        }
25830
25831        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25832    }
25833
25834    /// Load folds from the file_folds database table by file path.
25835    /// Used when manually opening a file that was previously closed.
25836    fn load_folds_from_db(
25837        &mut self,
25838        workspace_id: WorkspaceId,
25839        file_path: PathBuf,
25840        window: &mut Window,
25841        cx: &mut Context<Editor>,
25842    ) {
25843        if self.mode.is_minimap()
25844            || WorkspaceSettings::get(None, cx).restore_on_startup
25845                == RestoreOnStartupBehavior::EmptyTab
25846        {
25847            return;
25848        }
25849
25850        let Some(folds) = EditorDb::global(cx)
25851            .get_file_folds(workspace_id, &file_path)
25852            .log_err()
25853        else {
25854            return;
25855        };
25856        if folds.is_empty() {
25857            return;
25858        }
25859
25860        let snapshot = self.buffer.read(cx).snapshot(cx);
25861        let snapshot_len = snapshot.len().0;
25862
25863        // Helper: search for fingerprint in buffer, return offset if found
25864        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25865            let search_start = snapshot
25866                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25867                .0;
25868            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25869
25870            let mut byte_offset = search_start;
25871            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25872                if byte_offset > search_end {
25873                    break;
25874                }
25875                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25876                    return Some(byte_offset);
25877                }
25878                byte_offset += ch.len_utf8();
25879            }
25880            None
25881        };
25882
25883        let mut search_start = 0usize;
25884
25885        let valid_folds: Vec<_> = folds
25886            .into_iter()
25887            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25888                let sfp = start_fp?;
25889                let efp = end_fp?;
25890                let efp_len = efp.len();
25891
25892                let start_matches = stored_start < snapshot_len
25893                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25894                let efp_check_pos = stored_end.saturating_sub(efp_len);
25895                let end_matches = efp_check_pos >= stored_start
25896                    && stored_end <= snapshot_len
25897                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25898
25899                let (new_start, new_end) = if start_matches && end_matches {
25900                    (stored_start, stored_end)
25901                } else if sfp == efp {
25902                    let new_start = find_fingerprint(&sfp, search_start)?;
25903                    let fold_len = stored_end - stored_start;
25904                    let new_end = new_start + fold_len;
25905                    (new_start, new_end)
25906                } else {
25907                    let new_start = find_fingerprint(&sfp, search_start)?;
25908                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25909                    let new_end = efp_pos + efp_len;
25910                    (new_start, new_end)
25911                };
25912
25913                search_start = new_end;
25914
25915                if new_end <= new_start {
25916                    return None;
25917                }
25918
25919                Some(
25920                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25921                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25922                )
25923            })
25924            .collect();
25925
25926        if !valid_folds.is_empty() {
25927            self.fold_ranges(valid_folds, false, window, cx);
25928        }
25929    }
25930
25931    fn lsp_data_enabled(&self) -> bool {
25932        self.enable_lsp_data && self.mode().is_full()
25933    }
25934
25935    fn update_lsp_data(
25936        &mut self,
25937        for_buffer: Option<BufferId>,
25938        window: &mut Window,
25939        cx: &mut Context<'_, Self>,
25940    ) {
25941        if !self.lsp_data_enabled() {
25942            return;
25943        }
25944
25945        if let Some(buffer_id) = for_buffer {
25946            self.pull_diagnostics(buffer_id, window, cx);
25947        }
25948        self.refresh_semantic_tokens(for_buffer, None, cx);
25949        self.refresh_document_colors(for_buffer, window, cx);
25950        self.refresh_folding_ranges(for_buffer, window, cx);
25951        self.refresh_document_symbols(for_buffer, cx);
25952    }
25953
25954    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25955        if !self.lsp_data_enabled() {
25956            return;
25957        }
25958        let visible_buffers: Vec<_> = self
25959            .visible_buffers(cx)
25960            .into_iter()
25961            .filter(|buffer| self.is_lsp_relevant(buffer.read(cx).file(), cx))
25962            .collect();
25963        for visible_buffer in visible_buffers {
25964            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25965        }
25966    }
25967
25968    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25969        if !self.lsp_data_enabled() {
25970            return;
25971        }
25972
25973        if !self.registered_buffers.contains_key(&buffer_id)
25974            && let Some(project) = self.project.as_ref()
25975        {
25976            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25977                project.update(cx, |project, cx| {
25978                    self.registered_buffers.insert(
25979                        buffer_id,
25980                        project.register_buffer_with_language_servers(&buffer, cx),
25981                    );
25982                });
25983            } else {
25984                self.registered_buffers.remove(&buffer_id);
25985            }
25986        }
25987    }
25988
25989    fn create_style(&self, cx: &App) -> EditorStyle {
25990        let settings = ThemeSettings::get_global(cx);
25991
25992        let mut text_style = match self.mode {
25993            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25994                color: cx.theme().colors().editor_foreground,
25995                font_family: settings.ui_font.family.clone(),
25996                font_features: settings.ui_font.features.clone(),
25997                font_fallbacks: settings.ui_font.fallbacks.clone(),
25998                font_size: rems(0.875).into(),
25999                font_weight: settings.ui_font.weight,
26000                line_height: relative(settings.buffer_line_height.value()),
26001                ..Default::default()
26002            },
26003            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
26004                color: cx.theme().colors().editor_foreground,
26005                font_family: settings.buffer_font.family.clone(),
26006                font_features: settings.buffer_font.features.clone(),
26007                font_fallbacks: settings.buffer_font.fallbacks.clone(),
26008                font_size: settings.buffer_font_size(cx).into(),
26009                font_weight: settings.buffer_font.weight,
26010                line_height: relative(settings.buffer_line_height.value()),
26011                ..Default::default()
26012            },
26013        };
26014        if let Some(text_style_refinement) = &self.text_style_refinement {
26015            text_style.refine(text_style_refinement)
26016        }
26017
26018        let background = match self.mode {
26019            EditorMode::SingleLine => cx.theme().system().transparent,
26020            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
26021            EditorMode::Full { .. } => cx.theme().colors().editor_background,
26022            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
26023        };
26024
26025        EditorStyle {
26026            background,
26027            border: cx.theme().colors().border,
26028            local_player: cx.theme().players().local(),
26029            text: text_style,
26030            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
26031            syntax: cx.theme().syntax().clone(),
26032            status: cx.theme().status().clone(),
26033            inlay_hints_style: make_inlay_hints_style(cx),
26034            edit_prediction_styles: make_suggestion_styles(cx),
26035            unnecessary_code_fade: settings.unnecessary_code_fade,
26036            show_underlines: self.diagnostics_enabled(),
26037        }
26038    }
26039
26040    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
26041        let multibuffer = self.buffer().read(cx);
26042        let is_singleton = multibuffer.is_singleton();
26043        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
26044        let buffer = multibuffer.buffer(*buffer_id)?;
26045
26046        let buffer = buffer.read(cx);
26047        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
26048        let mut breadcrumbs = if is_singleton {
26049            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
26050                buffer
26051                    .snapshot()
26052                    .resolve_file_path(
26053                        self.project
26054                            .as_ref()
26055                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
26056                            .unwrap_or_default(),
26057                        cx,
26058                    )
26059                    .unwrap_or_else(|| {
26060                        if multibuffer.is_singleton() {
26061                            multibuffer.title(cx).to_string()
26062                        } else {
26063                            "untitled".to_string()
26064                        }
26065                    })
26066            });
26067            vec![HighlightedText {
26068                text: text.into(),
26069                highlights: vec![],
26070            }]
26071        } else {
26072            vec![]
26073        };
26074
26075        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
26076            text: symbol.text.clone().into(),
26077            highlights: symbol.highlight_ranges.clone(),
26078        }));
26079        Some(breadcrumbs)
26080    }
26081
26082    fn disable_lsp_data(&mut self) {
26083        self.enable_lsp_data = false;
26084    }
26085
26086    fn disable_runnables(&mut self) {
26087        self.enable_runnables = false;
26088    }
26089
26090    pub fn disable_mouse_wheel_zoom(&mut self) {
26091        self.enable_mouse_wheel_zoom = false;
26092    }
26093
26094    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
26095        self.register_visible_buffers(cx);
26096        self.colorize_brackets(false, cx);
26097        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
26098        if !self.buffer().read(cx).is_singleton() {
26099            self.update_lsp_data(None, window, cx);
26100            self.refresh_runnables(None, window, cx);
26101        }
26102    }
26103}
26104
26105fn edit_for_markdown_paste<'a>(
26106    buffer: &MultiBufferSnapshot,
26107    range: Range<MultiBufferOffset>,
26108    to_insert: &'a str,
26109    url: Option<url::Url>,
26110) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
26111    if url.is_none() {
26112        return (range, Cow::Borrowed(to_insert));
26113    };
26114
26115    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
26116
26117    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
26118        Cow::Borrowed(to_insert)
26119    } else {
26120        Cow::Owned(format!("[{old_text}]({to_insert})"))
26121    };
26122    (range, new_text)
26123}
26124
26125fn process_completion_for_edit(
26126    completion: &Completion,
26127    intent: CompletionIntent,
26128    buffer: &Entity<Buffer>,
26129    cursor_position: &text::Anchor,
26130    cx: &mut Context<Editor>,
26131) -> CompletionEdit {
26132    let buffer = buffer.read(cx);
26133    let buffer_snapshot = buffer.snapshot();
26134    let (snippet, new_text) = if completion.is_snippet() {
26135        let mut snippet_source = completion.new_text.clone();
26136        // Workaround for typescript language server issues so that methods don't expand within
26137        // strings and functions with type expressions. The previous point is used because the query
26138        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
26139        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
26140        let previous_point = if previous_point.column > 0 {
26141            cursor_position.to_previous_offset(&buffer_snapshot)
26142        } else {
26143            cursor_position.to_offset(&buffer_snapshot)
26144        };
26145        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
26146            && scope.prefers_label_for_snippet_in_completion()
26147            && let Some(label) = completion.label()
26148            && matches!(
26149                completion.kind(),
26150                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
26151            )
26152        {
26153            snippet_source = label;
26154        }
26155        match Snippet::parse(&snippet_source).log_err() {
26156            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
26157            None => (None, completion.new_text.clone()),
26158        }
26159    } else {
26160        (None, completion.new_text.clone())
26161    };
26162
26163    let mut range_to_replace = {
26164        let replace_range = &completion.replace_range;
26165        if let CompletionSource::Lsp {
26166            insert_range: Some(insert_range),
26167            ..
26168        } = &completion.source
26169        {
26170            debug_assert_eq!(
26171                insert_range.start, replace_range.start,
26172                "insert_range and replace_range should start at the same position"
26173            );
26174            debug_assert!(
26175                insert_range
26176                    .start
26177                    .cmp(cursor_position, &buffer_snapshot)
26178                    .is_le(),
26179                "insert_range should start before or at cursor position"
26180            );
26181            debug_assert!(
26182                replace_range
26183                    .start
26184                    .cmp(cursor_position, &buffer_snapshot)
26185                    .is_le(),
26186                "replace_range should start before or at cursor position"
26187            );
26188
26189            let should_replace = match intent {
26190                CompletionIntent::CompleteWithInsert => false,
26191                CompletionIntent::CompleteWithReplace => true,
26192                CompletionIntent::Complete | CompletionIntent::Compose => {
26193                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
26194                        .completions
26195                        .lsp_insert_mode;
26196                    match insert_mode {
26197                        LspInsertMode::Insert => false,
26198                        LspInsertMode::Replace => true,
26199                        LspInsertMode::ReplaceSubsequence => {
26200                            let mut text_to_replace = buffer.chars_for_range(
26201                                buffer.anchor_before(replace_range.start)
26202                                    ..buffer.anchor_after(replace_range.end),
26203                            );
26204                            let mut current_needle = text_to_replace.next();
26205                            for haystack_ch in completion.label.text.chars() {
26206                                if let Some(needle_ch) = current_needle
26207                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
26208                                {
26209                                    current_needle = text_to_replace.next();
26210                                }
26211                            }
26212                            current_needle.is_none()
26213                        }
26214                        LspInsertMode::ReplaceSuffix => {
26215                            if replace_range
26216                                .end
26217                                .cmp(cursor_position, &buffer_snapshot)
26218                                .is_gt()
26219                            {
26220                                let range_after_cursor = *cursor_position..replace_range.end;
26221                                let text_after_cursor = buffer
26222                                    .text_for_range(
26223                                        buffer.anchor_before(range_after_cursor.start)
26224                                            ..buffer.anchor_after(range_after_cursor.end),
26225                                    )
26226                                    .collect::<String>()
26227                                    .to_ascii_lowercase();
26228                                completion
26229                                    .label
26230                                    .text
26231                                    .to_ascii_lowercase()
26232                                    .ends_with(&text_after_cursor)
26233                            } else {
26234                                true
26235                            }
26236                        }
26237                    }
26238                }
26239            };
26240
26241            if should_replace {
26242                replace_range.clone()
26243            } else {
26244                insert_range.clone()
26245            }
26246        } else {
26247            replace_range.clone()
26248        }
26249    };
26250
26251    if range_to_replace
26252        .end
26253        .cmp(cursor_position, &buffer_snapshot)
26254        .is_lt()
26255    {
26256        range_to_replace.end = *cursor_position;
26257    }
26258
26259    CompletionEdit {
26260        new_text,
26261        replace_range: range_to_replace,
26262        snippet,
26263    }
26264}
26265
26266struct CompletionEdit {
26267    new_text: String,
26268    replace_range: Range<text::Anchor>,
26269    snippet: Option<Snippet>,
26270}
26271
26272fn comment_delimiter_for_newline(
26273    start_point: &Point,
26274    buffer: &MultiBufferSnapshot,
26275    language: &LanguageScope,
26276) -> Option<Arc<str>> {
26277    let delimiters = language.line_comment_prefixes();
26278    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26279    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26280
26281    let num_of_whitespaces = snapshot
26282        .chars_for_range(range.clone())
26283        .take_while(|c| c.is_whitespace())
26284        .count();
26285    let comment_candidate = snapshot
26286        .chars_for_range(range.clone())
26287        .skip(num_of_whitespaces)
26288        .take(max_len_of_delimiter + 2)
26289        .collect::<String>();
26290    let (delimiter, trimmed_len, is_repl) = delimiters
26291        .iter()
26292        .filter_map(|delimiter| {
26293            let prefix = delimiter.trim_end();
26294            if comment_candidate.starts_with(prefix) {
26295                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26296                {
26297                    stripped_comment.starts_with(" %%")
26298                } else {
26299                    false
26300                };
26301                Some((delimiter, prefix.len(), is_repl))
26302            } else {
26303                None
26304            }
26305        })
26306        .max_by_key(|(_, len, _)| *len)?;
26307
26308    if let Some(BlockCommentConfig {
26309        start: block_start, ..
26310    }) = language.block_comment()
26311    {
26312        let block_start_trimmed = block_start.trim_end();
26313        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26314            let line_content = snapshot
26315                .chars_for_range(range.clone())
26316                .skip(num_of_whitespaces)
26317                .take(block_start_trimmed.len())
26318                .collect::<String>();
26319
26320            if line_content.starts_with(block_start_trimmed) {
26321                return None;
26322            }
26323        }
26324    }
26325
26326    let cursor_is_placed_after_comment_marker =
26327        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26328    if cursor_is_placed_after_comment_marker {
26329        if !is_repl {
26330            return Some(delimiter.clone());
26331        }
26332
26333        let line_content_after_cursor: String = snapshot
26334            .chars_for_range(range)
26335            .skip(start_point.column as usize)
26336            .collect();
26337
26338        if line_content_after_cursor.trim().is_empty() {
26339            return None;
26340        } else {
26341            return Some(delimiter.clone());
26342        }
26343    } else {
26344        None
26345    }
26346}
26347
26348fn documentation_delimiter_for_newline(
26349    start_point: &Point,
26350    buffer: &MultiBufferSnapshot,
26351    language: &LanguageScope,
26352    newline_config: &mut NewlineConfig,
26353) -> Option<Arc<str>> {
26354    let BlockCommentConfig {
26355        start: start_tag,
26356        end: end_tag,
26357        prefix: delimiter,
26358        tab_size: len,
26359    } = language.documentation_comment()?;
26360    let is_within_block_comment = buffer
26361        .language_scope_at(*start_point)
26362        .is_some_and(|scope| scope.override_name() == Some("comment"));
26363    if !is_within_block_comment {
26364        return None;
26365    }
26366
26367    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26368
26369    let num_of_whitespaces = snapshot
26370        .chars_for_range(range.clone())
26371        .take_while(|c| c.is_whitespace())
26372        .count();
26373
26374    // 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.
26375    let column = start_point.column;
26376    let cursor_is_after_start_tag = {
26377        let start_tag_len = start_tag.len();
26378        let start_tag_line = snapshot
26379            .chars_for_range(range.clone())
26380            .skip(num_of_whitespaces)
26381            .take(start_tag_len)
26382            .collect::<String>();
26383        if start_tag_line.starts_with(start_tag.as_ref()) {
26384            num_of_whitespaces + start_tag_len <= column as usize
26385        } else {
26386            false
26387        }
26388    };
26389
26390    let cursor_is_after_delimiter = {
26391        let delimiter_trim = delimiter.trim_end();
26392        let delimiter_line = snapshot
26393            .chars_for_range(range.clone())
26394            .skip(num_of_whitespaces)
26395            .take(delimiter_trim.len())
26396            .collect::<String>();
26397        if delimiter_line.starts_with(delimiter_trim) {
26398            num_of_whitespaces + delimiter_trim.len() <= column as usize
26399        } else {
26400            false
26401        }
26402    };
26403
26404    let mut needs_extra_line = false;
26405    let mut extra_line_additional_indent = IndentSize::spaces(0);
26406
26407    let cursor_is_before_end_tag_if_exists = {
26408        let mut char_position = 0u32;
26409        let mut end_tag_offset = None;
26410
26411        'outer: for chunk in snapshot.text_for_range(range) {
26412            if let Some(byte_pos) = chunk.find(&**end_tag) {
26413                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26414                end_tag_offset = Some(char_position + chars_before_match);
26415                break 'outer;
26416            }
26417            char_position += chunk.chars().count() as u32;
26418        }
26419
26420        if let Some(end_tag_offset) = end_tag_offset {
26421            let cursor_is_before_end_tag = column <= end_tag_offset;
26422            if cursor_is_after_start_tag {
26423                if cursor_is_before_end_tag {
26424                    needs_extra_line = true;
26425                }
26426                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26427                if cursor_is_at_start_of_end_tag {
26428                    extra_line_additional_indent.len = *len;
26429                }
26430            }
26431            cursor_is_before_end_tag
26432        } else {
26433            true
26434        }
26435    };
26436
26437    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26438        && cursor_is_before_end_tag_if_exists
26439    {
26440        let additional_indent = if cursor_is_after_start_tag {
26441            IndentSize::spaces(*len)
26442        } else {
26443            IndentSize::spaces(0)
26444        };
26445
26446        *newline_config = NewlineConfig::Newline {
26447            additional_indent,
26448            extra_line_additional_indent: if needs_extra_line {
26449                Some(extra_line_additional_indent)
26450            } else {
26451                None
26452            },
26453            prevent_auto_indent: true,
26454        };
26455        Some(delimiter.clone())
26456    } else {
26457        None
26458    }
26459}
26460
26461const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26462
26463fn list_delimiter_for_newline(
26464    start_point: &Point,
26465    buffer: &MultiBufferSnapshot,
26466    language: &LanguageScope,
26467    newline_config: &mut NewlineConfig,
26468) -> Option<Arc<str>> {
26469    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26470
26471    let num_of_whitespaces = snapshot
26472        .chars_for_range(range.clone())
26473        .take_while(|c| c.is_whitespace())
26474        .count();
26475
26476    let task_list_entries: Vec<_> = language
26477        .task_list()
26478        .into_iter()
26479        .flat_map(|config| {
26480            config
26481                .prefixes
26482                .iter()
26483                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26484        })
26485        .collect();
26486    let unordered_list_entries: Vec<_> = language
26487        .unordered_list()
26488        .iter()
26489        .map(|marker| (marker.as_ref(), marker.as_ref()))
26490        .collect();
26491
26492    let all_entries: Vec<_> = task_list_entries
26493        .into_iter()
26494        .chain(unordered_list_entries)
26495        .collect();
26496
26497    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26498        let candidate: String = snapshot
26499            .chars_for_range(range.clone())
26500            .skip(num_of_whitespaces)
26501            .take(max_prefix_len)
26502            .collect();
26503
26504        if let Some((prefix, continuation)) = all_entries
26505            .iter()
26506            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26507            .max_by_key(|(prefix, _)| prefix.len())
26508        {
26509            let end_of_prefix = num_of_whitespaces + prefix.len();
26510            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26511            let has_content_after_marker = snapshot
26512                .chars_for_range(range)
26513                .skip(end_of_prefix)
26514                .any(|c| !c.is_whitespace());
26515
26516            if has_content_after_marker && cursor_is_after_prefix {
26517                return Some((*continuation).into());
26518            }
26519
26520            if start_point.column as usize == end_of_prefix {
26521                if num_of_whitespaces == 0 {
26522                    *newline_config = NewlineConfig::ClearCurrentLine;
26523                } else {
26524                    *newline_config = NewlineConfig::UnindentCurrentLine {
26525                        continuation: (*continuation).into(),
26526                    };
26527                }
26528            }
26529
26530            return None;
26531        }
26532    }
26533
26534    let candidate: String = snapshot
26535        .chars_for_range(range.clone())
26536        .skip(num_of_whitespaces)
26537        .take(ORDERED_LIST_MAX_MARKER_LEN)
26538        .collect();
26539
26540    for ordered_config in language.ordered_list() {
26541        let regex = match Regex::new(&ordered_config.pattern) {
26542            Ok(r) => r,
26543            Err(_) => continue,
26544        };
26545
26546        if let Some(captures) = regex.captures(&candidate) {
26547            let full_match = captures.get(0)?;
26548            let marker_len = full_match.len();
26549            let end_of_prefix = num_of_whitespaces + marker_len;
26550            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26551
26552            let has_content_after_marker = snapshot
26553                .chars_for_range(range)
26554                .skip(end_of_prefix)
26555                .any(|c| !c.is_whitespace());
26556
26557            if has_content_after_marker && cursor_is_after_prefix {
26558                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26559                let continuation = ordered_config
26560                    .format
26561                    .replace("{1}", &(number + 1).to_string());
26562                return Some(continuation.into());
26563            }
26564
26565            if start_point.column as usize == end_of_prefix {
26566                let continuation = ordered_config.format.replace("{1}", "1");
26567                if num_of_whitespaces == 0 {
26568                    *newline_config = NewlineConfig::ClearCurrentLine;
26569                } else {
26570                    *newline_config = NewlineConfig::UnindentCurrentLine {
26571                        continuation: continuation.into(),
26572                    };
26573                }
26574            }
26575
26576            return None;
26577        }
26578    }
26579
26580    None
26581}
26582
26583fn is_list_prefix_row(
26584    row: MultiBufferRow,
26585    buffer: &MultiBufferSnapshot,
26586    language: &LanguageScope,
26587) -> bool {
26588    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26589        return false;
26590    };
26591
26592    let num_of_whitespaces = snapshot
26593        .chars_for_range(range.clone())
26594        .take_while(|c| c.is_whitespace())
26595        .count();
26596
26597    let task_list_prefixes: Vec<_> = language
26598        .task_list()
26599        .into_iter()
26600        .flat_map(|config| {
26601            config
26602                .prefixes
26603                .iter()
26604                .map(|p| p.as_ref())
26605                .collect::<Vec<_>>()
26606        })
26607        .collect();
26608    let unordered_list_markers: Vec<_> = language
26609        .unordered_list()
26610        .iter()
26611        .map(|marker| marker.as_ref())
26612        .collect();
26613    let all_prefixes: Vec<_> = task_list_prefixes
26614        .into_iter()
26615        .chain(unordered_list_markers)
26616        .collect();
26617    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26618        let candidate: String = snapshot
26619            .chars_for_range(range.clone())
26620            .skip(num_of_whitespaces)
26621            .take(max_prefix_len)
26622            .collect();
26623        if all_prefixes
26624            .iter()
26625            .any(|prefix| candidate.starts_with(*prefix))
26626        {
26627            return true;
26628        }
26629    }
26630
26631    let ordered_list_candidate: String = snapshot
26632        .chars_for_range(range)
26633        .skip(num_of_whitespaces)
26634        .take(ORDERED_LIST_MAX_MARKER_LEN)
26635        .collect();
26636    for ordered_config in language.ordered_list() {
26637        let regex = match Regex::new(&ordered_config.pattern) {
26638            Ok(r) => r,
26639            Err(_) => continue,
26640        };
26641        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26642            return captures.get(0).is_some();
26643        }
26644    }
26645
26646    false
26647}
26648
26649#[derive(Debug)]
26650enum NewlineConfig {
26651    /// Insert newline with optional additional indent and optional extra blank line
26652    Newline {
26653        additional_indent: IndentSize,
26654        extra_line_additional_indent: Option<IndentSize>,
26655        prevent_auto_indent: bool,
26656    },
26657    /// Clear the current line
26658    ClearCurrentLine,
26659    /// Unindent the current line and add continuation
26660    UnindentCurrentLine { continuation: Arc<str> },
26661}
26662
26663impl NewlineConfig {
26664    fn has_extra_line(&self) -> bool {
26665        matches!(
26666            self,
26667            Self::Newline {
26668                extra_line_additional_indent: Some(_),
26669                ..
26670            }
26671        )
26672    }
26673
26674    fn insert_extra_newline_brackets(
26675        buffer: &MultiBufferSnapshot,
26676        range: Range<MultiBufferOffset>,
26677        language: &language::LanguageScope,
26678    ) -> bool {
26679        let leading_whitespace_len = buffer
26680            .reversed_chars_at(range.start)
26681            .take_while(|c| c.is_whitespace() && *c != '\n')
26682            .map(|c| c.len_utf8())
26683            .sum::<usize>();
26684        let trailing_whitespace_len = buffer
26685            .chars_at(range.end)
26686            .take_while(|c| c.is_whitespace() && *c != '\n')
26687            .map(|c| c.len_utf8())
26688            .sum::<usize>();
26689        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26690
26691        language.brackets().any(|(pair, enabled)| {
26692            let pair_start = pair.start.trim_end();
26693            let pair_end = pair.end.trim_start();
26694
26695            enabled
26696                && pair.newline
26697                && buffer.contains_str_at(range.end, pair_end)
26698                && buffer.contains_str_at(
26699                    range.start.saturating_sub_usize(pair_start.len()),
26700                    pair_start,
26701                )
26702        })
26703    }
26704
26705    fn insert_extra_newline_tree_sitter(
26706        buffer: &MultiBufferSnapshot,
26707        range: Range<MultiBufferOffset>,
26708    ) -> bool {
26709        let (buffer, range) = match buffer
26710            .range_to_buffer_ranges(range.start..range.end)
26711            .as_slice()
26712        {
26713            [(buffer_snapshot, range, _)] => (buffer_snapshot.clone(), range.clone()),
26714            _ => return false,
26715        };
26716        let pair = {
26717            let mut result: Option<BracketMatch<usize>> = None;
26718
26719            for pair in buffer
26720                .all_bracket_ranges(range.start.0..range.end.0)
26721                .filter(move |pair| {
26722                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26723                })
26724            {
26725                let len = pair.close_range.end - pair.open_range.start;
26726
26727                if let Some(existing) = &result {
26728                    let existing_len = existing.close_range.end - existing.open_range.start;
26729                    if len > existing_len {
26730                        continue;
26731                    }
26732                }
26733
26734                result = Some(pair);
26735            }
26736
26737            result
26738        };
26739        let Some(pair) = pair else {
26740            return false;
26741        };
26742        pair.newline_only
26743            && buffer
26744                .chars_for_range(pair.open_range.end..range.start.0)
26745                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26746                .all(|c| c.is_whitespace() && c != '\n')
26747    }
26748}
26749
26750fn update_uncommitted_diff_for_buffer(
26751    editor: Entity<Editor>,
26752    project: &Entity<Project>,
26753    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26754    buffer: Entity<MultiBuffer>,
26755    cx: &mut App,
26756) -> Task<()> {
26757    let mut tasks = Vec::new();
26758    project.update(cx, |project, cx| {
26759        for buffer in buffers {
26760            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26761                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26762            }
26763        }
26764    });
26765    cx.spawn(async move |cx| {
26766        let diffs = future::join_all(tasks).await;
26767        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26768            return;
26769        }
26770
26771        buffer.update(cx, |buffer, cx| {
26772            for diff in diffs.into_iter().flatten() {
26773                buffer.add_diff(diff, cx);
26774            }
26775        });
26776    })
26777}
26778
26779fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26780    let tab_size = tab_size.get() as usize;
26781    let mut width = offset;
26782
26783    for ch in text.chars() {
26784        width += if ch == '\t' {
26785            tab_size - (width % tab_size)
26786        } else {
26787            1
26788        };
26789    }
26790
26791    width - offset
26792}
26793
26794#[cfg(test)]
26795mod tests {
26796    use super::*;
26797
26798    #[test]
26799    fn test_string_size_with_expanded_tabs() {
26800        let nz = |val| NonZeroU32::new(val).unwrap();
26801        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26802        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26803        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26804        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26805        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26806        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26807        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26808        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26809    }
26810}
26811
26812/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26813struct WordBreakingTokenizer<'a> {
26814    input: &'a str,
26815}
26816
26817impl<'a> WordBreakingTokenizer<'a> {
26818    fn new(input: &'a str) -> Self {
26819        Self { input }
26820    }
26821}
26822
26823fn is_char_ideographic(ch: char) -> bool {
26824    use unicode_script::Script::*;
26825    use unicode_script::UnicodeScript;
26826    matches!(ch.script(), Han | Tangut | Yi)
26827}
26828
26829fn is_grapheme_ideographic(text: &str) -> bool {
26830    text.chars().any(is_char_ideographic)
26831}
26832
26833fn is_grapheme_whitespace(text: &str) -> bool {
26834    text.chars().any(|x| x.is_whitespace())
26835}
26836
26837fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26838    text.chars()
26839        .next()
26840        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26841}
26842
26843#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26844enum WordBreakToken<'a> {
26845    Word { token: &'a str, grapheme_len: usize },
26846    InlineWhitespace { token: &'a str, grapheme_len: usize },
26847    Newline,
26848}
26849
26850impl<'a> Iterator for WordBreakingTokenizer<'a> {
26851    /// Yields a span, the count of graphemes in the token, and whether it was
26852    /// whitespace. Note that it also breaks at word boundaries.
26853    type Item = WordBreakToken<'a>;
26854
26855    fn next(&mut self) -> Option<Self::Item> {
26856        use unicode_segmentation::UnicodeSegmentation;
26857        if self.input.is_empty() {
26858            return None;
26859        }
26860
26861        let mut iter = self.input.graphemes(true).peekable();
26862        let mut offset = 0;
26863        let mut grapheme_len = 0;
26864        if let Some(first_grapheme) = iter.next() {
26865            let is_newline = first_grapheme == "\n";
26866            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26867            offset += first_grapheme.len();
26868            grapheme_len += 1;
26869            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26870                if let Some(grapheme) = iter.peek().copied()
26871                    && should_stay_with_preceding_ideograph(grapheme)
26872                {
26873                    offset += grapheme.len();
26874                    grapheme_len += 1;
26875                }
26876            } else {
26877                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26878                let mut next_word_bound = words.peek().copied();
26879                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26880                    next_word_bound = words.next();
26881                }
26882                while let Some(grapheme) = iter.peek().copied() {
26883                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26884                        break;
26885                    };
26886                    if is_grapheme_whitespace(grapheme) != is_whitespace
26887                        || (grapheme == "\n") != is_newline
26888                    {
26889                        break;
26890                    };
26891                    offset += grapheme.len();
26892                    grapheme_len += 1;
26893                    iter.next();
26894                }
26895            }
26896            let token = &self.input[..offset];
26897            self.input = &self.input[offset..];
26898            if token == "\n" {
26899                Some(WordBreakToken::Newline)
26900            } else if is_whitespace {
26901                Some(WordBreakToken::InlineWhitespace {
26902                    token,
26903                    grapheme_len,
26904                })
26905            } else {
26906                Some(WordBreakToken::Word {
26907                    token,
26908                    grapheme_len,
26909                })
26910            }
26911        } else {
26912            None
26913        }
26914    }
26915}
26916
26917#[test]
26918fn test_word_breaking_tokenizer() {
26919    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26920        ("", &[]),
26921        ("  ", &[whitespace("  ", 2)]),
26922        ("Ʒ", &[word("Ʒ", 1)]),
26923        ("Ǽ", &[word("Ǽ", 1)]),
26924        ("", &[word("", 1)]),
26925        ("⋑⋑", &[word("⋑⋑", 2)]),
26926        (
26927            "原理,进而",
26928            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26929        ),
26930        (
26931            "hello world",
26932            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26933        ),
26934        (
26935            "hello, world",
26936            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26937        ),
26938        (
26939            "  hello world",
26940            &[
26941                whitespace("  ", 2),
26942                word("hello", 5),
26943                whitespace(" ", 1),
26944                word("world", 5),
26945            ],
26946        ),
26947        (
26948            "这是什么 \n 钢笔",
26949            &[
26950                word("", 1),
26951                word("", 1),
26952                word("", 1),
26953                word("", 1),
26954                whitespace(" ", 1),
26955                newline(),
26956                whitespace(" ", 1),
26957                word("", 1),
26958                word("", 1),
26959            ],
26960        ),
26961        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26962    ];
26963
26964    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26965        WordBreakToken::Word {
26966            token,
26967            grapheme_len,
26968        }
26969    }
26970
26971    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26972        WordBreakToken::InlineWhitespace {
26973            token,
26974            grapheme_len,
26975        }
26976    }
26977
26978    fn newline() -> WordBreakToken<'static> {
26979        WordBreakToken::Newline
26980    }
26981
26982    for (input, result) in tests {
26983        assert_eq!(
26984            WordBreakingTokenizer::new(input)
26985                .collect::<Vec<_>>()
26986                .as_slice(),
26987            *result,
26988        );
26989    }
26990}
26991
26992fn wrap_with_prefix(
26993    first_line_prefix: String,
26994    subsequent_lines_prefix: String,
26995    unwrapped_text: String,
26996    wrap_column: usize,
26997    tab_size: NonZeroU32,
26998    preserve_existing_whitespace: bool,
26999) -> String {
27000    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
27001    let subsequent_lines_prefix_len =
27002        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
27003    let mut wrapped_text = String::new();
27004    let mut current_line = first_line_prefix;
27005    let mut is_first_line = true;
27006
27007    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
27008    let mut current_line_len = first_line_prefix_len;
27009    let mut in_whitespace = false;
27010    for token in tokenizer {
27011        let have_preceding_whitespace = in_whitespace;
27012        match token {
27013            WordBreakToken::Word {
27014                token,
27015                grapheme_len,
27016            } => {
27017                in_whitespace = false;
27018                let current_prefix_len = if is_first_line {
27019                    first_line_prefix_len
27020                } else {
27021                    subsequent_lines_prefix_len
27022                };
27023                if current_line_len + grapheme_len > wrap_column
27024                    && current_line_len != current_prefix_len
27025                {
27026                    wrapped_text.push_str(current_line.trim_end());
27027                    wrapped_text.push('\n');
27028                    is_first_line = false;
27029                    current_line = subsequent_lines_prefix.clone();
27030                    current_line_len = subsequent_lines_prefix_len;
27031                }
27032                current_line.push_str(token);
27033                current_line_len += grapheme_len;
27034            }
27035            WordBreakToken::InlineWhitespace {
27036                mut token,
27037                mut grapheme_len,
27038            } => {
27039                in_whitespace = true;
27040                if have_preceding_whitespace && !preserve_existing_whitespace {
27041                    continue;
27042                }
27043                if !preserve_existing_whitespace {
27044                    // Keep a single whitespace grapheme as-is
27045                    if let Some(first) =
27046                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
27047                    {
27048                        token = first;
27049                    } else {
27050                        token = " ";
27051                    }
27052                    grapheme_len = 1;
27053                }
27054                let current_prefix_len = if is_first_line {
27055                    first_line_prefix_len
27056                } else {
27057                    subsequent_lines_prefix_len
27058                };
27059                if current_line_len + grapheme_len > wrap_column {
27060                    wrapped_text.push_str(current_line.trim_end());
27061                    wrapped_text.push('\n');
27062                    is_first_line = false;
27063                    current_line = subsequent_lines_prefix.clone();
27064                    current_line_len = subsequent_lines_prefix_len;
27065                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
27066                    current_line.push_str(token);
27067                    current_line_len += grapheme_len;
27068                }
27069            }
27070            WordBreakToken::Newline => {
27071                in_whitespace = true;
27072                let current_prefix_len = if is_first_line {
27073                    first_line_prefix_len
27074                } else {
27075                    subsequent_lines_prefix_len
27076                };
27077                if preserve_existing_whitespace {
27078                    wrapped_text.push_str(current_line.trim_end());
27079                    wrapped_text.push('\n');
27080                    is_first_line = false;
27081                    current_line = subsequent_lines_prefix.clone();
27082                    current_line_len = subsequent_lines_prefix_len;
27083                } else if have_preceding_whitespace {
27084                    continue;
27085                } else if current_line_len + 1 > wrap_column
27086                    && current_line_len != current_prefix_len
27087                {
27088                    wrapped_text.push_str(current_line.trim_end());
27089                    wrapped_text.push('\n');
27090                    is_first_line = false;
27091                    current_line = subsequent_lines_prefix.clone();
27092                    current_line_len = subsequent_lines_prefix_len;
27093                } else if current_line_len != current_prefix_len {
27094                    current_line.push(' ');
27095                    current_line_len += 1;
27096                }
27097            }
27098        }
27099    }
27100
27101    if !current_line.is_empty() {
27102        wrapped_text.push_str(&current_line);
27103    }
27104    wrapped_text
27105}
27106
27107#[test]
27108fn test_wrap_with_prefix() {
27109    assert_eq!(
27110        wrap_with_prefix(
27111            "# ".to_string(),
27112            "# ".to_string(),
27113            "abcdefg".to_string(),
27114            4,
27115            NonZeroU32::new(4).unwrap(),
27116            false,
27117        ),
27118        "# abcdefg"
27119    );
27120    assert_eq!(
27121        wrap_with_prefix(
27122            "".to_string(),
27123            "".to_string(),
27124            "\thello world".to_string(),
27125            8,
27126            NonZeroU32::new(4).unwrap(),
27127            false,
27128        ),
27129        "hello\nworld"
27130    );
27131    assert_eq!(
27132        wrap_with_prefix(
27133            "// ".to_string(),
27134            "// ".to_string(),
27135            "xx \nyy zz aa bb cc".to_string(),
27136            12,
27137            NonZeroU32::new(4).unwrap(),
27138            false,
27139        ),
27140        "// xx yy zz\n// aa bb cc"
27141    );
27142    assert_eq!(
27143        wrap_with_prefix(
27144            String::new(),
27145            String::new(),
27146            "这是什么 \n 钢笔".to_string(),
27147            3,
27148            NonZeroU32::new(4).unwrap(),
27149            false,
27150        ),
27151        "这是什\n么 钢\n"
27152    );
27153    assert_eq!(
27154        wrap_with_prefix(
27155            String::new(),
27156            String::new(),
27157            format!("foo{}bar", '\u{2009}'), // thin space
27158            80,
27159            NonZeroU32::new(4).unwrap(),
27160            false,
27161        ),
27162        format!("foo{}bar", '\u{2009}')
27163    );
27164}
27165
27166pub trait CollaborationHub {
27167    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
27168    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
27169    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
27170}
27171
27172impl CollaborationHub for Entity<Project> {
27173    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
27174        self.read(cx).collaborators()
27175    }
27176
27177    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
27178        self.read(cx).user_store().read(cx).participant_indices()
27179    }
27180
27181    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
27182        let this = self.read(cx);
27183        let user_ids = this.collaborators().values().map(|c| c.user_id);
27184        this.user_store().read(cx).participant_names(user_ids, cx)
27185    }
27186}
27187
27188pub trait SemanticsProvider {
27189    fn hover(
27190        &self,
27191        buffer: &Entity<Buffer>,
27192        position: text::Anchor,
27193        cx: &mut App,
27194    ) -> Option<Task<Option<Vec<project::Hover>>>>;
27195
27196    fn inline_values(
27197        &self,
27198        buffer_handle: Entity<Buffer>,
27199        range: Range<text::Anchor>,
27200        cx: &mut App,
27201    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
27202
27203    fn applicable_inlay_chunks(
27204        &self,
27205        buffer: &Entity<Buffer>,
27206        ranges: &[Range<text::Anchor>],
27207        cx: &mut App,
27208    ) -> Vec<Range<BufferRow>>;
27209
27210    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
27211
27212    fn inlay_hints(
27213        &self,
27214        invalidate: InvalidationStrategy,
27215        buffer: Entity<Buffer>,
27216        ranges: Vec<Range<text::Anchor>>,
27217        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27218        cx: &mut App,
27219    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27220
27221    fn semantic_tokens(
27222        &self,
27223        buffer: Entity<Buffer>,
27224        refresh: Option<RefreshForServer>,
27225        cx: &mut App,
27226    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27227
27228    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27229
27230    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27231
27232    fn document_highlights(
27233        &self,
27234        buffer: &Entity<Buffer>,
27235        position: text::Anchor,
27236        cx: &mut App,
27237    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27238
27239    fn definitions(
27240        &self,
27241        buffer: &Entity<Buffer>,
27242        position: text::Anchor,
27243        kind: GotoDefinitionKind,
27244        cx: &mut App,
27245    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27246
27247    fn range_for_rename(
27248        &self,
27249        buffer: &Entity<Buffer>,
27250        position: text::Anchor,
27251        cx: &mut App,
27252    ) -> Task<Result<Option<Range<text::Anchor>>>>;
27253
27254    fn perform_rename(
27255        &self,
27256        buffer: &Entity<Buffer>,
27257        position: text::Anchor,
27258        new_name: String,
27259        cx: &mut App,
27260    ) -> Option<Task<Result<ProjectTransaction>>>;
27261}
27262
27263pub trait CompletionProvider {
27264    fn completions(
27265        &self,
27266        buffer: &Entity<Buffer>,
27267        buffer_position: text::Anchor,
27268        trigger: CompletionContext,
27269        window: &mut Window,
27270        cx: &mut Context<Editor>,
27271    ) -> Task<Result<Vec<CompletionResponse>>>;
27272
27273    fn resolve_completions(
27274        &self,
27275        _buffer: Entity<Buffer>,
27276        _completion_indices: Vec<usize>,
27277        _completions: Rc<RefCell<Box<[Completion]>>>,
27278        _cx: &mut Context<Editor>,
27279    ) -> Task<Result<bool>> {
27280        Task::ready(Ok(false))
27281    }
27282
27283    fn apply_additional_edits_for_completion(
27284        &self,
27285        _buffer: Entity<Buffer>,
27286        _completions: Rc<RefCell<Box<[Completion]>>>,
27287        _completion_index: usize,
27288        _push_to_history: bool,
27289        _all_commit_ranges: Vec<Range<language::Anchor>>,
27290        _cx: &mut Context<Editor>,
27291    ) -> Task<Result<Option<language::Transaction>>> {
27292        Task::ready(Ok(None))
27293    }
27294
27295    fn is_completion_trigger(
27296        &self,
27297        buffer: &Entity<Buffer>,
27298        position: language::Anchor,
27299        text: &str,
27300        trigger_in_words: bool,
27301        cx: &mut Context<Editor>,
27302    ) -> bool;
27303
27304    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27305
27306    fn sort_completions(&self) -> bool {
27307        true
27308    }
27309
27310    fn filter_completions(&self) -> bool {
27311        true
27312    }
27313
27314    fn show_snippets(&self) -> bool {
27315        false
27316    }
27317}
27318
27319pub trait CodeActionProvider {
27320    fn id(&self) -> Arc<str>;
27321
27322    fn code_actions(
27323        &self,
27324        buffer: &Entity<Buffer>,
27325        range: Range<text::Anchor>,
27326        window: &mut Window,
27327        cx: &mut App,
27328    ) -> Task<Result<Vec<CodeAction>>>;
27329
27330    fn apply_code_action(
27331        &self,
27332        buffer_handle: Entity<Buffer>,
27333        action: CodeAction,
27334        push_to_history: bool,
27335        window: &mut Window,
27336        cx: &mut App,
27337    ) -> Task<Result<ProjectTransaction>>;
27338}
27339
27340impl CodeActionProvider for Entity<Project> {
27341    fn id(&self) -> Arc<str> {
27342        "project".into()
27343    }
27344
27345    fn code_actions(
27346        &self,
27347        buffer: &Entity<Buffer>,
27348        range: Range<text::Anchor>,
27349        _window: &mut Window,
27350        cx: &mut App,
27351    ) -> Task<Result<Vec<CodeAction>>> {
27352        self.update(cx, |project, cx| {
27353            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27354            let code_actions = project.code_actions(buffer, range, None, cx);
27355            cx.background_spawn(async move {
27356                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27357                Ok(code_lens_actions
27358                    .context("code lens fetch")?
27359                    .into_iter()
27360                    .flatten()
27361                    .chain(
27362                        code_actions
27363                            .context("code action fetch")?
27364                            .into_iter()
27365                            .flatten(),
27366                    )
27367                    .collect())
27368            })
27369        })
27370    }
27371
27372    fn apply_code_action(
27373        &self,
27374        buffer_handle: Entity<Buffer>,
27375        action: CodeAction,
27376        push_to_history: bool,
27377        _window: &mut Window,
27378        cx: &mut App,
27379    ) -> Task<Result<ProjectTransaction>> {
27380        self.update(cx, |project, cx| {
27381            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27382        })
27383    }
27384}
27385
27386fn snippet_completions(
27387    project: &Project,
27388    buffer: &Entity<Buffer>,
27389    buffer_anchor: text::Anchor,
27390    classifier: CharClassifier,
27391    cx: &mut App,
27392) -> Task<Result<CompletionResponse>> {
27393    let languages = buffer.read(cx).languages_at(buffer_anchor);
27394    let snippet_store = project.snippets().read(cx);
27395
27396    let scopes: Vec<_> = languages
27397        .iter()
27398        .filter_map(|language| {
27399            let language_name = language.lsp_id();
27400            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27401
27402            if snippets.is_empty() {
27403                None
27404            } else {
27405                Some((language.default_scope(), snippets))
27406            }
27407        })
27408        .collect();
27409
27410    if scopes.is_empty() {
27411        return Task::ready(Ok(CompletionResponse {
27412            completions: vec![],
27413            display_options: CompletionDisplayOptions::default(),
27414            is_incomplete: false,
27415        }));
27416    }
27417
27418    let snapshot = buffer.read(cx).text_snapshot();
27419    let executor = cx.background_executor().clone();
27420
27421    cx.background_spawn(async move {
27422        let is_word_char = |c| classifier.is_word(c);
27423
27424        let mut is_incomplete = false;
27425        let mut completions: Vec<Completion> = Vec::new();
27426
27427        const MAX_PREFIX_LEN: usize = 128;
27428        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27429        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27430        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27431
27432        let max_buffer_window: String = snapshot
27433            .text_for_range(window_start..buffer_offset)
27434            .collect();
27435
27436        if max_buffer_window.is_empty() {
27437            return Ok(CompletionResponse {
27438                completions: vec![],
27439                display_options: CompletionDisplayOptions::default(),
27440                is_incomplete: true,
27441            });
27442        }
27443
27444        for (_scope, snippets) in scopes.into_iter() {
27445            // Sort snippets by word count to match longer snippet prefixes first.
27446            let mut sorted_snippet_candidates = snippets
27447                .iter()
27448                .enumerate()
27449                .flat_map(|(snippet_ix, snippet)| {
27450                    snippet
27451                        .prefix
27452                        .iter()
27453                        .enumerate()
27454                        .map(move |(prefix_ix, prefix)| {
27455                            let word_count =
27456                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27457                            ((snippet_ix, prefix_ix), prefix, word_count)
27458                        })
27459                })
27460                .collect_vec();
27461            sorted_snippet_candidates
27462                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27463
27464            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27465
27466            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27467                .take(
27468                    sorted_snippet_candidates
27469                        .first()
27470                        .map(|(_, _, word_count)| *word_count)
27471                        .unwrap_or_default(),
27472                )
27473                .collect_vec();
27474
27475            const MAX_RESULTS: usize = 100;
27476            // Each match also remembers how many characters from the buffer it consumed
27477            let mut matches: Vec<(StringMatch, usize)> = vec![];
27478
27479            let mut snippet_list_cutoff_index = 0;
27480            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27481                let word_count = buffer_index + 1;
27482                // Increase `snippet_list_cutoff_index` until we have all of the
27483                // snippets with sufficiently many words.
27484                while sorted_snippet_candidates
27485                    .get(snippet_list_cutoff_index)
27486                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27487                        *snippet_word_count >= word_count
27488                    })
27489                {
27490                    snippet_list_cutoff_index += 1;
27491                }
27492
27493                // Take only the candidates with at least `word_count` many words
27494                let snippet_candidates_at_word_len =
27495                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27496
27497                let candidates = snippet_candidates_at_word_len
27498                    .iter()
27499                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27500                    .enumerate() // index in `sorted_snippet_candidates`
27501                    // First char must match
27502                    .filter(|(_ix, prefix)| {
27503                        itertools::equal(
27504                            prefix
27505                                .chars()
27506                                .next()
27507                                .into_iter()
27508                                .flat_map(|c| c.to_lowercase()),
27509                            buffer_window
27510                                .chars()
27511                                .next()
27512                                .into_iter()
27513                                .flat_map(|c| c.to_lowercase()),
27514                        )
27515                    })
27516                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27517                    .collect::<Vec<StringMatchCandidate>>();
27518
27519                matches.extend(
27520                    fuzzy::match_strings(
27521                        &candidates,
27522                        &buffer_window,
27523                        buffer_window.chars().any(|c| c.is_uppercase()),
27524                        true,
27525                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27526                        &Default::default(),
27527                        executor.clone(),
27528                    )
27529                    .await
27530                    .into_iter()
27531                    .map(|string_match| (string_match, buffer_window.len())),
27532                );
27533
27534                if matches.len() >= MAX_RESULTS {
27535                    break;
27536                }
27537            }
27538
27539            let to_lsp = |point: &text::Anchor| {
27540                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27541                point_to_lsp(end)
27542            };
27543            let lsp_end = to_lsp(&buffer_anchor);
27544
27545            if matches.len() >= MAX_RESULTS {
27546                is_incomplete = true;
27547            }
27548
27549            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27550                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27551                    sorted_snippet_candidates[string_match.candidate_id];
27552                let snippet = &snippets[snippet_index];
27553                let start = buffer_offset - buffer_window_len;
27554                let start = snapshot.anchor_before(start);
27555                let range = start..buffer_anchor;
27556                let lsp_start = to_lsp(&start);
27557                let lsp_range = lsp::Range {
27558                    start: lsp_start,
27559                    end: lsp_end,
27560                };
27561                Completion {
27562                    replace_range: range,
27563                    new_text: snippet.body.clone(),
27564                    source: CompletionSource::Lsp {
27565                        insert_range: None,
27566                        server_id: LanguageServerId(usize::MAX),
27567                        resolved: true,
27568                        lsp_completion: Box::new(lsp::CompletionItem {
27569                            label: snippet.prefix.first().unwrap().clone(),
27570                            kind: Some(CompletionItemKind::SNIPPET),
27571                            label_details: snippet.description.as_ref().map(|description| {
27572                                lsp::CompletionItemLabelDetails {
27573                                    detail: Some(description.clone()),
27574                                    description: None,
27575                                }
27576                            }),
27577                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27578                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27579                                lsp::InsertReplaceEdit {
27580                                    new_text: snippet.body.clone(),
27581                                    insert: lsp_range,
27582                                    replace: lsp_range,
27583                                },
27584                            )),
27585                            filter_text: Some(snippet.body.clone()),
27586                            sort_text: Some(char::MAX.to_string()),
27587                            ..lsp::CompletionItem::default()
27588                        }),
27589                        lsp_defaults: None,
27590                    },
27591                    label: CodeLabel {
27592                        text: matching_prefix.clone(),
27593                        runs: Vec::new(),
27594                        filter_range: 0..matching_prefix.len(),
27595                    },
27596                    icon_path: None,
27597                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27598                        single_line: snippet.name.clone().into(),
27599                        plain_text: snippet
27600                            .description
27601                            .clone()
27602                            .map(|description| description.into()),
27603                    }),
27604                    insert_text_mode: None,
27605                    confirm: None,
27606                    match_start: Some(start),
27607                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27608                }
27609            }));
27610        }
27611
27612        Ok(CompletionResponse {
27613            completions,
27614            display_options: CompletionDisplayOptions::default(),
27615            is_incomplete,
27616        })
27617    })
27618}
27619
27620impl CompletionProvider for Entity<Project> {
27621    fn completions(
27622        &self,
27623        buffer: &Entity<Buffer>,
27624        buffer_position: text::Anchor,
27625        options: CompletionContext,
27626        _window: &mut Window,
27627        cx: &mut Context<Editor>,
27628    ) -> Task<Result<Vec<CompletionResponse>>> {
27629        self.update(cx, |project, cx| {
27630            let task = project.completions(buffer, buffer_position, options, cx);
27631            cx.background_spawn(task)
27632        })
27633    }
27634
27635    fn resolve_completions(
27636        &self,
27637        buffer: Entity<Buffer>,
27638        completion_indices: Vec<usize>,
27639        completions: Rc<RefCell<Box<[Completion]>>>,
27640        cx: &mut Context<Editor>,
27641    ) -> Task<Result<bool>> {
27642        self.update(cx, |project, cx| {
27643            project.lsp_store().update(cx, |lsp_store, cx| {
27644                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27645            })
27646        })
27647    }
27648
27649    fn apply_additional_edits_for_completion(
27650        &self,
27651        buffer: Entity<Buffer>,
27652        completions: Rc<RefCell<Box<[Completion]>>>,
27653        completion_index: usize,
27654        push_to_history: bool,
27655        all_commit_ranges: Vec<Range<language::Anchor>>,
27656        cx: &mut Context<Editor>,
27657    ) -> Task<Result<Option<language::Transaction>>> {
27658        self.update(cx, |project, cx| {
27659            project.lsp_store().update(cx, |lsp_store, cx| {
27660                lsp_store.apply_additional_edits_for_completion(
27661                    buffer,
27662                    completions,
27663                    completion_index,
27664                    push_to_history,
27665                    all_commit_ranges,
27666                    cx,
27667                )
27668            })
27669        })
27670    }
27671
27672    fn is_completion_trigger(
27673        &self,
27674        buffer: &Entity<Buffer>,
27675        position: language::Anchor,
27676        text: &str,
27677        trigger_in_words: bool,
27678        cx: &mut Context<Editor>,
27679    ) -> bool {
27680        let mut chars = text.chars();
27681        let char = if let Some(char) = chars.next() {
27682            char
27683        } else {
27684            return false;
27685        };
27686        if chars.next().is_some() {
27687            return false;
27688        }
27689
27690        let buffer = buffer.read(cx);
27691        let snapshot = buffer.snapshot();
27692        let classifier = snapshot
27693            .char_classifier_at(position)
27694            .scope_context(Some(CharScopeContext::Completion));
27695        if trigger_in_words && classifier.is_word(char) {
27696            return true;
27697        }
27698
27699        buffer.completion_triggers().contains(text)
27700    }
27701
27702    fn show_snippets(&self) -> bool {
27703        true
27704    }
27705}
27706
27707impl SemanticsProvider for WeakEntity<Project> {
27708    fn hover(
27709        &self,
27710        buffer: &Entity<Buffer>,
27711        position: text::Anchor,
27712        cx: &mut App,
27713    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27714        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27715            .ok()
27716    }
27717
27718    fn document_highlights(
27719        &self,
27720        buffer: &Entity<Buffer>,
27721        position: text::Anchor,
27722        cx: &mut App,
27723    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27724        self.update(cx, |project, cx| {
27725            project.document_highlights(buffer, position, cx)
27726        })
27727        .ok()
27728    }
27729
27730    fn definitions(
27731        &self,
27732        buffer: &Entity<Buffer>,
27733        position: text::Anchor,
27734        kind: GotoDefinitionKind,
27735        cx: &mut App,
27736    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27737        self.update(cx, |project, cx| match kind {
27738            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27739            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27740            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27741            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27742        })
27743        .ok()
27744    }
27745
27746    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27747        self.update(cx, |project, cx| {
27748            if project
27749                .active_debug_session(cx)
27750                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27751            {
27752                return true;
27753            }
27754
27755            buffer.update(cx, |buffer, cx| {
27756                project.any_language_server_supports_inlay_hints(buffer, cx)
27757            })
27758        })
27759        .unwrap_or(false)
27760    }
27761
27762    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27763        self.update(cx, |project, cx| {
27764            buffer.update(cx, |buffer, cx| {
27765                project.any_language_server_supports_semantic_tokens(buffer, cx)
27766            })
27767        })
27768        .unwrap_or(false)
27769    }
27770
27771    fn inline_values(
27772        &self,
27773        buffer_handle: Entity<Buffer>,
27774        range: Range<text::Anchor>,
27775        cx: &mut App,
27776    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27777        self.update(cx, |project, cx| {
27778            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27779
27780            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27781        })
27782        .ok()
27783        .flatten()
27784    }
27785
27786    fn applicable_inlay_chunks(
27787        &self,
27788        buffer: &Entity<Buffer>,
27789        ranges: &[Range<text::Anchor>],
27790        cx: &mut App,
27791    ) -> Vec<Range<BufferRow>> {
27792        self.update(cx, |project, cx| {
27793            project.lsp_store().update(cx, |lsp_store, cx| {
27794                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27795            })
27796        })
27797        .unwrap_or_default()
27798    }
27799
27800    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27801        self.update(cx, |project, cx| {
27802            project.lsp_store().update(cx, |lsp_store, _| {
27803                lsp_store.invalidate_inlay_hints(for_buffers)
27804            })
27805        })
27806        .ok();
27807    }
27808
27809    fn inlay_hints(
27810        &self,
27811        invalidate: InvalidationStrategy,
27812        buffer: Entity<Buffer>,
27813        ranges: Vec<Range<text::Anchor>>,
27814        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27815        cx: &mut App,
27816    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27817        self.update(cx, |project, cx| {
27818            project.lsp_store().update(cx, |lsp_store, cx| {
27819                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27820            })
27821        })
27822        .ok()
27823    }
27824
27825    fn semantic_tokens(
27826        &self,
27827        buffer: Entity<Buffer>,
27828        refresh: Option<RefreshForServer>,
27829        cx: &mut App,
27830    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27831        self.update(cx, |this, cx| {
27832            this.lsp_store().update(cx, |lsp_store, cx| {
27833                lsp_store.semantic_tokens(buffer, refresh, cx)
27834            })
27835        })
27836        .ok()
27837    }
27838
27839    fn range_for_rename(
27840        &self,
27841        buffer: &Entity<Buffer>,
27842        position: text::Anchor,
27843        cx: &mut App,
27844    ) -> Task<Result<Option<Range<text::Anchor>>>> {
27845        let Some(this) = self.upgrade() else {
27846            return Task::ready(Ok(None));
27847        };
27848
27849        this.update(cx, |project, cx| {
27850            let buffer = buffer.clone();
27851            let task = project.prepare_rename(buffer.clone(), position, cx);
27852            cx.spawn(async move |_, cx| {
27853                Ok(match task.await? {
27854                    PrepareRenameResponse::Success(range) => Some(range),
27855                    PrepareRenameResponse::InvalidPosition => None,
27856                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27857                        // Fallback on using TreeSitter info to determine identifier range
27858                        buffer.read_with(cx, |buffer, _| {
27859                            let snapshot = buffer.snapshot();
27860                            let (range, kind) = snapshot.surrounding_word(position, None);
27861                            if kind != Some(CharKind::Word) {
27862                                return None;
27863                            }
27864                            Some(
27865                                snapshot.anchor_before(range.start)
27866                                    ..snapshot.anchor_after(range.end),
27867                            )
27868                        })
27869                    }
27870                })
27871            })
27872        })
27873    }
27874
27875    fn perform_rename(
27876        &self,
27877        buffer: &Entity<Buffer>,
27878        position: text::Anchor,
27879        new_name: String,
27880        cx: &mut App,
27881    ) -> Option<Task<Result<ProjectTransaction>>> {
27882        self.update(cx, |project, cx| {
27883            project.perform_rename(buffer.clone(), position, new_name, cx)
27884        })
27885        .ok()
27886    }
27887}
27888
27889fn consume_contiguous_rows(
27890    contiguous_row_selections: &mut Vec<Selection<Point>>,
27891    selection: &Selection<Point>,
27892    display_map: &DisplaySnapshot,
27893    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27894) -> (MultiBufferRow, MultiBufferRow) {
27895    contiguous_row_selections.push(selection.clone());
27896    let start_row = starting_row(selection, display_map);
27897    let mut end_row = ending_row(selection, display_map);
27898
27899    while let Some(next_selection) = selections.peek() {
27900        if next_selection.start.row <= end_row.0 {
27901            end_row = ending_row(next_selection, display_map);
27902            contiguous_row_selections.push(selections.next().unwrap().clone());
27903        } else {
27904            break;
27905        }
27906    }
27907    (start_row, end_row)
27908}
27909
27910fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27911    if selection.start.column > 0 {
27912        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27913    } else {
27914        MultiBufferRow(selection.start.row)
27915    }
27916}
27917
27918fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27919    if next_selection.end.column > 0 || next_selection.is_empty() {
27920        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27921    } else {
27922        MultiBufferRow(next_selection.end.row)
27923    }
27924}
27925
27926impl EditorSnapshot {
27927    pub fn remote_selections_in_range<'a>(
27928        &'a self,
27929        range: &'a Range<Anchor>,
27930        collaboration_hub: &dyn CollaborationHub,
27931        cx: &'a App,
27932    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27933        let participant_names = collaboration_hub.user_names(cx);
27934        let participant_indices = collaboration_hub.user_participant_indices(cx);
27935        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27936        let collaborators_by_replica_id = collaborators_by_peer_id
27937            .values()
27938            .map(|collaborator| (collaborator.replica_id, collaborator))
27939            .collect::<HashMap<_, _>>();
27940        self.buffer_snapshot()
27941            .selections_in_range(range, false)
27942            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27943                if replica_id == ReplicaId::AGENT {
27944                    Some(RemoteSelection {
27945                        replica_id,
27946                        selection,
27947                        cursor_shape,
27948                        line_mode,
27949                        collaborator_id: CollaboratorId::Agent,
27950                        user_name: Some("Agent".into()),
27951                        color: cx.theme().players().agent(),
27952                    })
27953                } else {
27954                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27955                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27956                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27957                    Some(RemoteSelection {
27958                        replica_id,
27959                        selection,
27960                        cursor_shape,
27961                        line_mode,
27962                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27963                        user_name,
27964                        color: if let Some(index) = participant_index {
27965                            cx.theme().players().color_for_participant(index.0)
27966                        } else {
27967                            cx.theme().players().absent()
27968                        },
27969                    })
27970                }
27971            })
27972    }
27973
27974    pub fn hunks_for_ranges(
27975        &self,
27976        ranges: impl IntoIterator<Item = Range<Point>>,
27977    ) -> Vec<MultiBufferDiffHunk> {
27978        let mut hunks = Vec::new();
27979        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27980            HashMap::default();
27981        for query_range in ranges {
27982            let query_rows =
27983                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27984            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27985                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27986            ) {
27987                // Include deleted hunks that are adjacent to the query range, because
27988                // otherwise they would be missed.
27989                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27990                if hunk.status().is_deleted() {
27991                    intersects_range |= hunk.row_range.start == query_rows.end;
27992                    intersects_range |= hunk.row_range.end == query_rows.start;
27993                }
27994                if intersects_range {
27995                    if !processed_buffer_rows
27996                        .entry(hunk.buffer_id)
27997                        .or_default()
27998                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27999                    {
28000                        continue;
28001                    }
28002                    hunks.push(hunk);
28003                }
28004            }
28005        }
28006
28007        hunks
28008    }
28009
28010    fn display_diff_hunks_for_rows<'a>(
28011        &'a self,
28012        display_rows: Range<DisplayRow>,
28013        folded_buffers: &'a HashSet<BufferId>,
28014    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
28015        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
28016        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
28017
28018        self.buffer_snapshot()
28019            .diff_hunks_in_range(buffer_start..buffer_end)
28020            .filter_map(|hunk| {
28021                if folded_buffers.contains(&hunk.buffer_id)
28022                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
28023                {
28024                    return None;
28025                }
28026
28027                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
28028                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
28029                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
28030                    let line_len = self.buffer_snapshot().line_len(last_row);
28031                    Point::new(last_row.0, line_len)
28032                } else {
28033                    Point::new(hunk.row_range.end.0, 0)
28034                };
28035
28036                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
28037                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
28038
28039                let display_hunk = if hunk_display_start.column() != 0 {
28040                    DisplayDiffHunk::Folded {
28041                        display_row: hunk_display_start.row(),
28042                    }
28043                } else {
28044                    let mut end_row = hunk_display_end.row();
28045                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
28046                        end_row.0 += 1;
28047                    }
28048                    let is_created_file = hunk.is_created_file();
28049                    let multi_buffer_range = hunk.multi_buffer_range.clone();
28050
28051                    DisplayDiffHunk::Unfolded {
28052                        status: hunk.status(),
28053                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
28054                            ..hunk.diff_base_byte_range.end.0,
28055                        word_diffs: hunk.word_diffs,
28056                        display_row_range: hunk_display_start.row()..end_row,
28057                        multi_buffer_range,
28058                        is_created_file,
28059                    }
28060                };
28061
28062                Some(display_hunk)
28063            })
28064    }
28065
28066    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
28067        self.display_snapshot
28068            .buffer_snapshot()
28069            .language_at(position)
28070    }
28071
28072    pub fn is_focused(&self) -> bool {
28073        self.is_focused
28074    }
28075
28076    pub fn placeholder_text(&self) -> Option<String> {
28077        self.placeholder_display_snapshot
28078            .as_ref()
28079            .map(|display_map| display_map.text())
28080    }
28081
28082    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
28083        self.scroll_anchor.scroll_position(&self.display_snapshot)
28084    }
28085
28086    pub fn gutter_dimensions(
28087        &self,
28088        font_id: FontId,
28089        font_size: Pixels,
28090        style: &EditorStyle,
28091        window: &mut Window,
28092        cx: &App,
28093    ) -> GutterDimensions {
28094        if self.show_gutter
28095            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
28096            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
28097        {
28098            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
28099                matches!(
28100                    ProjectSettings::get_global(cx).git.git_gutter,
28101                    GitGutterSetting::TrackedFiles
28102                )
28103            });
28104            let gutter_settings = EditorSettings::get_global(cx).gutter;
28105            let show_line_numbers = self
28106                .show_line_numbers
28107                .unwrap_or(gutter_settings.line_numbers);
28108            let line_gutter_width = if show_line_numbers {
28109                // Avoid flicker-like gutter resizes when the line number gains another digit by
28110                // only resizing the gutter on files with > 10**min_line_number_digits lines.
28111                let min_width_for_number_on_gutter =
28112                    ch_advance * gutter_settings.min_line_number_digits as f32;
28113                self.max_line_number_width(style, window)
28114                    .max(min_width_for_number_on_gutter)
28115            } else {
28116                0.0.into()
28117            };
28118
28119            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
28120            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
28121
28122            let git_blame_entries_width =
28123                self.git_blame_gutter_max_author_length
28124                    .map(|max_author_length| {
28125                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
28126                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
28127
28128                        /// The number of characters to dedicate to gaps and margins.
28129                        const SPACING_WIDTH: usize = 4;
28130
28131                        let max_char_count = max_author_length.min(renderer.max_author_length())
28132                            + ::git::SHORT_SHA_LENGTH
28133                            + MAX_RELATIVE_TIMESTAMP.len()
28134                            + SPACING_WIDTH;
28135
28136                        ch_advance * max_char_count
28137                    });
28138
28139            let is_singleton = self.buffer_snapshot().is_singleton();
28140
28141            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
28142            left_padding += if !is_singleton {
28143                ch_width * 4.0
28144            } else if show_runnables || show_breakpoints {
28145                ch_width * 3.0
28146            } else if show_git_gutter && show_line_numbers {
28147                ch_width * 2.0
28148            } else if show_git_gutter || show_line_numbers {
28149                ch_width
28150            } else {
28151                px(0.)
28152            };
28153
28154            let shows_folds = is_singleton && gutter_settings.folds;
28155
28156            let right_padding = if shows_folds && show_line_numbers {
28157                ch_width * 4.0
28158            } else if shows_folds || (!is_singleton && show_line_numbers) {
28159                ch_width * 3.0
28160            } else if show_line_numbers {
28161                ch_width
28162            } else {
28163                px(0.)
28164            };
28165
28166            GutterDimensions {
28167                left_padding,
28168                right_padding,
28169                width: line_gutter_width + left_padding + right_padding,
28170                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
28171                git_blame_entries_width,
28172            }
28173        } else if self.offset_content {
28174            GutterDimensions::default_with_margin(font_id, font_size, cx)
28175        } else {
28176            GutterDimensions::default()
28177        }
28178    }
28179
28180    pub fn render_crease_toggle(
28181        &self,
28182        buffer_row: MultiBufferRow,
28183        row_contains_cursor: bool,
28184        editor: Entity<Editor>,
28185        window: &mut Window,
28186        cx: &mut App,
28187    ) -> Option<AnyElement> {
28188        let folded = self.is_line_folded(buffer_row);
28189        let mut is_foldable = false;
28190
28191        if let Some(crease) = self
28192            .crease_snapshot
28193            .query_row(buffer_row, self.buffer_snapshot())
28194        {
28195            is_foldable = true;
28196            match crease {
28197                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
28198                    if let Some(render_toggle) = render_toggle {
28199                        let toggle_callback =
28200                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
28201                                if folded {
28202                                    editor.update(cx, |editor, cx| {
28203                                        editor.fold_at(buffer_row, window, cx)
28204                                    });
28205                                } else {
28206                                    editor.update(cx, |editor, cx| {
28207                                        editor.unfold_at(buffer_row, window, cx)
28208                                    });
28209                                }
28210                            });
28211                        return Some((render_toggle)(
28212                            buffer_row,
28213                            folded,
28214                            toggle_callback,
28215                            window,
28216                            cx,
28217                        ));
28218                    }
28219                }
28220            }
28221        }
28222
28223        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28224
28225        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28226            Some(
28227                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28228                    .toggle_state(folded)
28229                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28230                        if folded {
28231                            this.unfold_at(buffer_row, window, cx);
28232                        } else {
28233                            this.fold_at(buffer_row, window, cx);
28234                        }
28235                    }))
28236                    .into_any_element(),
28237            )
28238        } else {
28239            None
28240        }
28241    }
28242
28243    pub fn render_crease_trailer(
28244        &self,
28245        buffer_row: MultiBufferRow,
28246        window: &mut Window,
28247        cx: &mut App,
28248    ) -> Option<AnyElement> {
28249        let folded = self.is_line_folded(buffer_row);
28250        if let Crease::Inline { render_trailer, .. } = self
28251            .crease_snapshot
28252            .query_row(buffer_row, self.buffer_snapshot())?
28253        {
28254            let render_trailer = render_trailer.as_ref()?;
28255            Some(render_trailer(buffer_row, folded, window, cx))
28256        } else {
28257            None
28258        }
28259    }
28260
28261    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28262        let digit_count = self.widest_line_number().ilog10() + 1;
28263        column_pixels(style, digit_count as usize, window)
28264    }
28265
28266    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28267    ///
28268    /// This is positive if `base` is before `line`.
28269    fn relative_line_delta(
28270        &self,
28271        current_selection_head: DisplayRow,
28272        first_visible_row: DisplayRow,
28273        consider_wrapped_lines: bool,
28274    ) -> i64 {
28275        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28276        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28277
28278        if consider_wrapped_lines {
28279            let wrap_snapshot = self.wrap_snapshot();
28280            let base_wrap_row = wrap_snapshot
28281                .make_wrap_point(current_selection_head, Bias::Left)
28282                .row();
28283            let wrap_row = wrap_snapshot
28284                .make_wrap_point(first_visible_row, Bias::Left)
28285                .row();
28286
28287            wrap_row.0 as i64 - base_wrap_row.0 as i64
28288        } else {
28289            let fold_snapshot = self.fold_snapshot();
28290            let base_fold_row = fold_snapshot
28291                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28292                .row();
28293            let fold_row = fold_snapshot
28294                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28295                .row();
28296
28297            fold_row as i64 - base_fold_row as i64
28298        }
28299    }
28300
28301    /// Returns the unsigned relative line number to display for each row in `rows`.
28302    ///
28303    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28304    pub fn calculate_relative_line_numbers(
28305        &self,
28306        rows: &Range<DisplayRow>,
28307        current_selection_head: DisplayRow,
28308        count_wrapped_lines: bool,
28309    ) -> HashMap<DisplayRow, u32> {
28310        let initial_offset =
28311            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28312
28313        self.row_infos(rows.start)
28314            .take(rows.len())
28315            .enumerate()
28316            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28317            .filter(|(_row, row_info)| {
28318                row_info.buffer_row.is_some()
28319                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28320            })
28321            .enumerate()
28322            .filter_map(|(i, (row, row_info))| {
28323                // We want to ensure here that the current line has absolute
28324                // numbering, even if we are in a soft-wrapped line. With the
28325                // exception that if we are in a deleted line, we should number this
28326                // relative with 0, as otherwise it would have no line number at all
28327                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28328
28329                (relative_line_number != 0
28330                    || row_info
28331                        .diff_status
28332                        .is_some_and(|status| status.is_deleted()))
28333                .then_some((row, relative_line_number))
28334            })
28335            .collect()
28336    }
28337}
28338
28339pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28340    let font_size = style.text.font_size.to_pixels(window.rem_size());
28341    let layout = window.text_system().shape_line(
28342        SharedString::from(" ".repeat(column)),
28343        font_size,
28344        &[TextRun {
28345            len: column,
28346            font: style.text.font(),
28347            color: Hsla::default(),
28348            ..Default::default()
28349        }],
28350        None,
28351    );
28352
28353    layout.width
28354}
28355
28356impl Deref for EditorSnapshot {
28357    type Target = DisplaySnapshot;
28358
28359    fn deref(&self) -> &Self::Target {
28360        &self.display_snapshot
28361    }
28362}
28363
28364#[derive(Clone, Debug, PartialEq, Eq)]
28365pub enum EditorEvent {
28366    /// Emitted when the stored review comments change (added, removed, or updated).
28367    ReviewCommentsChanged {
28368        /// The new total count of review comments.
28369        total_count: usize,
28370    },
28371    InputIgnored {
28372        text: Arc<str>,
28373    },
28374    InputHandled {
28375        utf16_range_to_replace: Option<Range<isize>>,
28376        text: Arc<str>,
28377    },
28378    BufferRangesUpdated {
28379        buffer: Entity<Buffer>,
28380        path_key: PathKey,
28381        ranges: Vec<ExcerptRange<text::Anchor>>,
28382    },
28383    BuffersRemoved {
28384        removed_buffer_ids: Vec<BufferId>,
28385    },
28386    BuffersEdited {
28387        buffer_ids: Vec<BufferId>,
28388    },
28389    BufferFoldToggled {
28390        ids: Vec<BufferId>,
28391        folded: bool,
28392    },
28393    ExpandExcerptsRequested {
28394        excerpt_anchors: Vec<Anchor>,
28395        lines: u32,
28396        direction: ExpandExcerptDirection,
28397    },
28398    StageOrUnstageRequested {
28399        stage: bool,
28400        hunks: Vec<MultiBufferDiffHunk>,
28401    },
28402    OpenExcerptsRequested {
28403        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28404        split: bool,
28405    },
28406    RestoreRequested {
28407        hunks: Vec<MultiBufferDiffHunk>,
28408    },
28409    BufferEdited,
28410    Edited {
28411        transaction_id: clock::Lamport,
28412    },
28413    Reparsed(BufferId),
28414    Focused,
28415    FocusedIn,
28416    Blurred,
28417    DirtyChanged,
28418    Saved,
28419    TitleChanged,
28420    SelectionsChanged {
28421        local: bool,
28422    },
28423    ScrollPositionChanged {
28424        local: bool,
28425        autoscroll: bool,
28426    },
28427    TransactionUndone {
28428        transaction_id: clock::Lamport,
28429    },
28430    TransactionBegun {
28431        transaction_id: clock::Lamport,
28432    },
28433    CursorShapeChanged,
28434    BreadcrumbsChanged,
28435    OutlineSymbolsChanged,
28436    PushedToNavHistory {
28437        anchor: Anchor,
28438        is_deactivate: bool,
28439    },
28440}
28441
28442impl EventEmitter<EditorEvent> for Editor {}
28443
28444impl Focusable for Editor {
28445    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28446        self.focus_handle.clone()
28447    }
28448}
28449
28450impl Render for Editor {
28451    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28452        EditorElement::new(&cx.entity(), self.create_style(cx))
28453    }
28454}
28455
28456impl EntityInputHandler for Editor {
28457    fn text_for_range(
28458        &mut self,
28459        range_utf16: Range<usize>,
28460        adjusted_range: &mut Option<Range<usize>>,
28461        _: &mut Window,
28462        cx: &mut Context<Self>,
28463    ) -> Option<String> {
28464        let snapshot = self.buffer.read(cx).read(cx);
28465        let start = snapshot.clip_offset_utf16(
28466            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28467            Bias::Left,
28468        );
28469        let end = snapshot.clip_offset_utf16(
28470            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28471            Bias::Right,
28472        );
28473        if (start.0.0..end.0.0) != range_utf16 {
28474            adjusted_range.replace(start.0.0..end.0.0);
28475        }
28476        Some(snapshot.text_for_range(start..end).collect())
28477    }
28478
28479    fn selected_text_range(
28480        &mut self,
28481        ignore_disabled_input: bool,
28482        _: &mut Window,
28483        cx: &mut Context<Self>,
28484    ) -> Option<UTF16Selection> {
28485        // Prevent the IME menu from appearing when holding down an alphabetic key
28486        // while input is disabled.
28487        if !ignore_disabled_input && !self.input_enabled {
28488            return None;
28489        }
28490
28491        let selection = self
28492            .selections
28493            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28494        let range = selection.range();
28495
28496        Some(UTF16Selection {
28497            range: range.start.0.0..range.end.0.0,
28498            reversed: selection.reversed,
28499        })
28500    }
28501
28502    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28503        let snapshot = self.buffer.read(cx).read(cx);
28504        let range = self
28505            .text_highlights(HighlightKey::InputComposition, cx)?
28506            .1
28507            .first()?;
28508        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28509    }
28510
28511    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28512        self.clear_highlights(HighlightKey::InputComposition, cx);
28513        self.ime_transaction.take();
28514    }
28515
28516    fn replace_text_in_range(
28517        &mut self,
28518        range_utf16: Option<Range<usize>>,
28519        text: &str,
28520        window: &mut Window,
28521        cx: &mut Context<Self>,
28522    ) {
28523        if !self.input_enabled {
28524            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28525            return;
28526        }
28527
28528        self.transact(window, cx, |this, window, cx| {
28529            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28530                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28531                    // During IME composition, macOS reports the replacement range
28532                    // relative to the first marked region (the only one visible via
28533                    // marked_text_range). The correct targets for replacement are the
28534                    // marked ranges themselves — one per cursor — so use them directly.
28535                    Some(marked_ranges)
28536                } else if range_utf16.start == range_utf16.end {
28537                    // An empty replacement range means "insert at cursor" with no text
28538                    // to replace. macOS reports the cursor position from its own
28539                    // (single-cursor) view of the buffer, which diverges from our actual
28540                    // cursor positions after multi-cursor edits have shifted offsets.
28541                    // Treating this as range_utf16=None lets each cursor insert in place.
28542                    None
28543                } else {
28544                    // Outside of IME composition (e.g. Accessibility Keyboard word
28545                    // completion), the range is an absolute document offset for the
28546                    // newest cursor. Fan it out to all cursors via
28547                    // selection_replacement_ranges, which applies the delta relative
28548                    // to the newest selection to every cursor.
28549                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28550                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28551                    Some(this.selection_replacement_ranges(range_utf16, cx))
28552                }
28553            } else {
28554                this.marked_text_ranges(cx)
28555            };
28556
28557            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28558                let newest_selection_id = this.selections.newest_anchor().id;
28559                this.selections
28560                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28561                    .iter()
28562                    .zip(ranges_to_replace.iter())
28563                    .find_map(|(selection, range)| {
28564                        if selection.id == newest_selection_id {
28565                            Some(
28566                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28567                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28568                            )
28569                        } else {
28570                            None
28571                        }
28572                    })
28573            });
28574
28575            cx.emit(EditorEvent::InputHandled {
28576                utf16_range_to_replace: range_to_replace,
28577                text: text.into(),
28578            });
28579
28580            if let Some(new_selected_ranges) = new_selected_ranges {
28581                // Only backspace if at least one range covers actual text. When all
28582                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28583                // Keyboard sends replacementRange=cursor..cursor), backspace would
28584                // incorrectly delete the character just before the cursor.
28585                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28586                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28587                    selections.select_ranges(new_selected_ranges)
28588                });
28589                if should_backspace {
28590                    this.backspace(&Default::default(), window, cx);
28591                }
28592            }
28593
28594            this.handle_input(text, window, cx);
28595        });
28596
28597        if let Some(transaction) = self.ime_transaction {
28598            self.buffer.update(cx, |buffer, cx| {
28599                buffer.group_until_transaction(transaction, cx);
28600            });
28601        }
28602
28603        self.unmark_text(window, cx);
28604    }
28605
28606    fn replace_and_mark_text_in_range(
28607        &mut self,
28608        range_utf16: Option<Range<usize>>,
28609        text: &str,
28610        new_selected_range_utf16: Option<Range<usize>>,
28611        window: &mut Window,
28612        cx: &mut Context<Self>,
28613    ) {
28614        if !self.input_enabled {
28615            return;
28616        }
28617
28618        let transaction = self.transact(window, cx, |this, window, cx| {
28619            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28620                let snapshot = this.buffer.read(cx).read(cx);
28621                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28622                    for marked_range in &mut marked_ranges {
28623                        marked_range.end = marked_range.start + relative_range_utf16.end;
28624                        marked_range.start += relative_range_utf16.start;
28625                        marked_range.start =
28626                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28627                        marked_range.end =
28628                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28629                    }
28630                }
28631                Some(marked_ranges)
28632            } else if let Some(range_utf16) = range_utf16 {
28633                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28634                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28635                Some(this.selection_replacement_ranges(range_utf16, cx))
28636            } else {
28637                None
28638            };
28639
28640            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28641                let newest_selection_id = this.selections.newest_anchor().id;
28642                this.selections
28643                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28644                    .iter()
28645                    .zip(ranges_to_replace.iter())
28646                    .find_map(|(selection, range)| {
28647                        if selection.id == newest_selection_id {
28648                            Some(
28649                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28650                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28651                            )
28652                        } else {
28653                            None
28654                        }
28655                    })
28656            });
28657
28658            cx.emit(EditorEvent::InputHandled {
28659                utf16_range_to_replace: range_to_replace,
28660                text: text.into(),
28661            });
28662
28663            if let Some(ranges) = ranges_to_replace {
28664                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28665                    s.select_ranges(ranges)
28666                });
28667            }
28668
28669            let marked_ranges = {
28670                let snapshot = this.buffer.read(cx).read(cx);
28671                this.selections
28672                    .disjoint_anchors_arc()
28673                    .iter()
28674                    .map(|selection| {
28675                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28676                    })
28677                    .collect::<Vec<_>>()
28678            };
28679
28680            if text.is_empty() {
28681                this.unmark_text(window, cx);
28682            } else {
28683                this.highlight_text(
28684                    HighlightKey::InputComposition,
28685                    marked_ranges.clone(),
28686                    HighlightStyle {
28687                        underline: Some(UnderlineStyle {
28688                            thickness: px(1.),
28689                            color: None,
28690                            wavy: false,
28691                        }),
28692                        ..Default::default()
28693                    },
28694                    cx,
28695                );
28696            }
28697
28698            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28699            let use_autoclose = this.use_autoclose;
28700            let use_auto_surround = this.use_auto_surround;
28701            this.set_use_autoclose(false);
28702            this.set_use_auto_surround(false);
28703            this.handle_input(text, window, cx);
28704            this.set_use_autoclose(use_autoclose);
28705            this.set_use_auto_surround(use_auto_surround);
28706
28707            if let Some(new_selected_range) = new_selected_range_utf16 {
28708                let snapshot = this.buffer.read(cx).read(cx);
28709                let new_selected_ranges = marked_ranges
28710                    .into_iter()
28711                    .map(|marked_range| {
28712                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28713                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28714                            insertion_start.0 + new_selected_range.start,
28715                        ));
28716                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28717                            insertion_start.0 + new_selected_range.end,
28718                        ));
28719                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28720                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28721                    })
28722                    .collect::<Vec<_>>();
28723
28724                drop(snapshot);
28725                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28726                    selections.select_ranges(new_selected_ranges)
28727                });
28728            }
28729        });
28730
28731        self.ime_transaction = self.ime_transaction.or(transaction);
28732        if let Some(transaction) = self.ime_transaction {
28733            self.buffer.update(cx, |buffer, cx| {
28734                buffer.group_until_transaction(transaction, cx);
28735            });
28736        }
28737
28738        if self
28739            .text_highlights(HighlightKey::InputComposition, cx)
28740            .is_none()
28741        {
28742            self.ime_transaction.take();
28743        }
28744    }
28745
28746    fn bounds_for_range(
28747        &mut self,
28748        range_utf16: Range<usize>,
28749        element_bounds: gpui::Bounds<Pixels>,
28750        window: &mut Window,
28751        cx: &mut Context<Self>,
28752    ) -> Option<gpui::Bounds<Pixels>> {
28753        let text_layout_details = self.text_layout_details(window, cx);
28754        let CharacterDimensions {
28755            em_width,
28756            em_advance,
28757            line_height,
28758        } = self.character_dimensions(window, cx);
28759
28760        let snapshot = self.snapshot(window, cx);
28761        let scroll_position = snapshot.scroll_position();
28762        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28763
28764        let start =
28765            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28766        let x = Pixels::from(
28767            ScrollOffset::from(
28768                snapshot.x_for_display_point(start, &text_layout_details)
28769                    + self.gutter_dimensions.full_width(),
28770            ) - scroll_left,
28771        );
28772        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28773
28774        Some(Bounds {
28775            origin: element_bounds.origin + point(x, y),
28776            size: size(em_width, line_height),
28777        })
28778    }
28779
28780    fn character_index_for_point(
28781        &mut self,
28782        point: gpui::Point<Pixels>,
28783        _window: &mut Window,
28784        _cx: &mut Context<Self>,
28785    ) -> Option<usize> {
28786        let position_map = self.last_position_map.as_ref()?;
28787        if !position_map.text_hitbox.contains(&point) {
28788            return None;
28789        }
28790        let display_point = position_map.point_for_position(point).previous_valid;
28791        let anchor = position_map
28792            .snapshot
28793            .display_point_to_anchor(display_point, Bias::Left);
28794        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28795        Some(utf16_offset.0.0)
28796    }
28797
28798    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28799        self.expects_character_input
28800    }
28801}
28802
28803trait SelectionExt {
28804    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28805    fn spanned_rows(
28806        &self,
28807        include_end_if_at_line_start: bool,
28808        map: &DisplaySnapshot,
28809    ) -> Range<MultiBufferRow>;
28810}
28811
28812impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28813    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28814        let start = self
28815            .start
28816            .to_point(map.buffer_snapshot())
28817            .to_display_point(map);
28818        let end = self
28819            .end
28820            .to_point(map.buffer_snapshot())
28821            .to_display_point(map);
28822        if self.reversed {
28823            end..start
28824        } else {
28825            start..end
28826        }
28827    }
28828
28829    fn spanned_rows(
28830        &self,
28831        include_end_if_at_line_start: bool,
28832        map: &DisplaySnapshot,
28833    ) -> Range<MultiBufferRow> {
28834        let start = self.start.to_point(map.buffer_snapshot());
28835        let mut end = self.end.to_point(map.buffer_snapshot());
28836        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28837            end.row -= 1;
28838        }
28839
28840        let buffer_start = map.prev_line_boundary(start).0;
28841        let buffer_end = map.next_line_boundary(end).0;
28842        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28843    }
28844}
28845
28846impl<T: InvalidationRegion> InvalidationStack<T> {
28847    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28848    where
28849        S: Clone + ToOffset,
28850    {
28851        while let Some(region) = self.last() {
28852            let all_selections_inside_invalidation_ranges =
28853                if selections.len() == region.ranges().len() {
28854                    selections
28855                        .iter()
28856                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28857                        .all(|(selection, invalidation_range)| {
28858                            let head = selection.head().to_offset(buffer);
28859                            invalidation_range.start <= head && invalidation_range.end >= head
28860                        })
28861                } else {
28862                    false
28863                };
28864
28865            if all_selections_inside_invalidation_ranges {
28866                break;
28867            } else {
28868                self.pop();
28869            }
28870        }
28871    }
28872}
28873
28874#[derive(Clone)]
28875struct ErasedEditorImpl(Entity<Editor>);
28876
28877impl ui_input::ErasedEditor for ErasedEditorImpl {
28878    fn text(&self, cx: &App) -> String {
28879        self.0.read(cx).text(cx)
28880    }
28881
28882    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28883        self.0.update(cx, |this, cx| {
28884            this.set_text(text, window, cx);
28885        })
28886    }
28887
28888    fn clear(&self, window: &mut Window, cx: &mut App) {
28889        self.0.update(cx, |this, cx| this.clear(window, cx));
28890    }
28891
28892    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28893        self.0.update(cx, |this, cx| {
28894            this.set_placeholder_text(text, window, cx);
28895        });
28896    }
28897
28898    fn focus_handle(&self, cx: &App) -> FocusHandle {
28899        self.0.read(cx).focus_handle(cx)
28900    }
28901
28902    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28903        let settings = ThemeSettings::get_global(cx);
28904        let theme_color = cx.theme().colors();
28905
28906        let text_style = TextStyle {
28907            font_family: settings.ui_font.family.clone(),
28908            font_features: settings.ui_font.features.clone(),
28909            font_size: rems(0.875).into(),
28910            font_weight: settings.ui_font.weight,
28911            font_style: FontStyle::Normal,
28912            line_height: relative(1.2),
28913            color: theme_color.text,
28914            ..Default::default()
28915        };
28916        let editor_style = EditorStyle {
28917            background: theme_color.ghost_element_background,
28918            local_player: cx.theme().players().local(),
28919            syntax: cx.theme().syntax().clone(),
28920            text: text_style,
28921            ..Default::default()
28922        };
28923        EditorElement::new(&self.0, editor_style).into_any()
28924    }
28925
28926    fn as_any(&self) -> &dyn Any {
28927        &self.0
28928    }
28929
28930    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28931        self.0.update(cx, |editor, cx| {
28932            let editor_offset = editor.buffer().read(cx).len(cx);
28933            editor.change_selections(
28934                SelectionEffects::scroll(Autoscroll::Next),
28935                window,
28936                cx,
28937                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28938            );
28939        });
28940    }
28941
28942    fn subscribe(
28943        &self,
28944        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28945        window: &mut Window,
28946        cx: &mut App,
28947    ) -> Subscription {
28948        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28949            let event = match event {
28950                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28951                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28952                _ => return,
28953            };
28954            (callback)(event, window, cx);
28955        })
28956    }
28957
28958    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28959        self.0.update(cx, |editor, cx| {
28960            editor.set_masked(masked, cx);
28961        });
28962    }
28963}
28964impl<T> Default for InvalidationStack<T> {
28965    fn default() -> Self {
28966        Self(Default::default())
28967    }
28968}
28969
28970impl<T> Deref for InvalidationStack<T> {
28971    type Target = Vec<T>;
28972
28973    fn deref(&self) -> &Self::Target {
28974        &self.0
28975    }
28976}
28977
28978impl<T> DerefMut for InvalidationStack<T> {
28979    fn deref_mut(&mut self) -> &mut Self::Target {
28980        &mut self.0
28981    }
28982}
28983
28984impl InvalidationRegion for SnippetState {
28985    fn ranges(&self) -> &[Range<Anchor>] {
28986        &self.ranges[self.active_index]
28987    }
28988}
28989
28990fn edit_prediction_edit_text(
28991    current_snapshot: &BufferSnapshot,
28992    edits: &[(Range<Anchor>, impl AsRef<str>)],
28993    edit_preview: &EditPreview,
28994    include_deletions: bool,
28995    multibuffer_snapshot: &MultiBufferSnapshot,
28996    cx: &App,
28997) -> HighlightedText {
28998    let edits = edits
28999        .iter()
29000        .filter_map(|(anchor, text)| {
29001            Some((
29002                multibuffer_snapshot
29003                    .anchor_range_to_buffer_anchor_range(anchor.clone())?
29004                    .1,
29005                text,
29006            ))
29007        })
29008        .collect::<Vec<_>>();
29009
29010    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
29011}
29012
29013fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
29014    // Fallback for providers that don't provide edit_preview (like Copilot)
29015    // Just show the raw edit text with basic styling
29016    let mut text = String::new();
29017    let mut highlights = Vec::new();
29018
29019    let insertion_highlight_style = HighlightStyle {
29020        color: Some(cx.theme().colors().text),
29021        ..Default::default()
29022    };
29023
29024    for (_, edit_text) in edits {
29025        let start_offset = text.len();
29026        text.push_str(edit_text);
29027        let end_offset = text.len();
29028
29029        if start_offset < end_offset {
29030            highlights.push((start_offset..end_offset, insertion_highlight_style));
29031        }
29032    }
29033
29034    HighlightedText {
29035        text: text.into(),
29036        highlights,
29037    }
29038}
29039
29040pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
29041    match severity {
29042        lsp::DiagnosticSeverity::ERROR => colors.error,
29043        lsp::DiagnosticSeverity::WARNING => colors.warning,
29044        lsp::DiagnosticSeverity::INFORMATION => colors.info,
29045        lsp::DiagnosticSeverity::HINT => colors.info,
29046        _ => colors.ignored,
29047    }
29048}
29049
29050pub fn styled_runs_for_code_label<'a>(
29051    label: &'a CodeLabel,
29052    syntax_theme: &'a theme::SyntaxTheme,
29053    local_player: &'a theme::PlayerColor,
29054) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
29055    let fade_out = HighlightStyle {
29056        fade_out: Some(0.35),
29057        ..Default::default()
29058    };
29059
29060    if label.runs.is_empty() {
29061        let desc_start = label.filter_range.end;
29062        let fade_run =
29063            (desc_start < label.text.len()).then(|| (desc_start..label.text.len(), fade_out));
29064        return Either::Left(fade_run.into_iter());
29065    }
29066
29067    let mut prev_end = label.filter_range.end;
29068    Either::Right(
29069        label
29070            .runs
29071            .iter()
29072            .enumerate()
29073            .flat_map(move |(ix, (range, highlight_id))| {
29074                let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
29075                    HighlightStyle {
29076                        color: Some(local_player.cursor),
29077                        ..Default::default()
29078                    }
29079                } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
29080                    HighlightStyle {
29081                        background_color: Some(local_player.selection),
29082                        ..Default::default()
29083                    }
29084                } else if let Some(style) = syntax_theme.get(*highlight_id).cloned() {
29085                    style
29086                } else {
29087                    return Default::default();
29088                };
29089
29090                let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
29091                let muted_style = style.highlight(fade_out);
29092                if range.start >= label.filter_range.end {
29093                    if range.start > prev_end {
29094                        runs.push((prev_end..range.start, fade_out));
29095                    }
29096                    runs.push((range.clone(), muted_style));
29097                } else if range.end <= label.filter_range.end {
29098                    runs.push((range.clone(), style));
29099                } else {
29100                    runs.push((range.start..label.filter_range.end, style));
29101                    runs.push((label.filter_range.end..range.end, muted_style));
29102                }
29103                prev_end = cmp::max(prev_end, range.end);
29104
29105                if ix + 1 == label.runs.len() && label.text.len() > prev_end {
29106                    runs.push((prev_end..label.text.len(), fade_out));
29107                }
29108
29109                runs
29110            }),
29111    )
29112}
29113
29114pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
29115    let mut prev_index = 0;
29116    let mut prev_codepoint: Option<char> = None;
29117    text.char_indices()
29118        .chain([(text.len(), '\0')])
29119        .filter_map(move |(index, codepoint)| {
29120            let prev_codepoint = prev_codepoint.replace(codepoint)?;
29121            let is_boundary = index == text.len()
29122                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
29123                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
29124            if is_boundary {
29125                let chunk = &text[prev_index..index];
29126                prev_index = index;
29127                Some(chunk)
29128            } else {
29129                None
29130            }
29131        })
29132}
29133
29134/// Given a string of text immediately before the cursor, iterates over possible
29135/// strings a snippet could match to. More precisely: returns an iterator over
29136/// suffixes of `text` created by splitting at word boundaries (before & after
29137/// every non-word character).
29138///
29139/// Shorter suffixes are returned first.
29140pub(crate) fn snippet_candidate_suffixes<'a>(
29141    text: &'a str,
29142    is_word_char: &'a dyn Fn(char) -> bool,
29143) -> impl std::iter::Iterator<Item = &'a str> + 'a {
29144    let mut prev_index = text.len();
29145    let mut prev_codepoint = None;
29146    text.char_indices()
29147        .rev()
29148        .chain([(0, '\0')])
29149        .filter_map(move |(index, codepoint)| {
29150            let prev_index = std::mem::replace(&mut prev_index, index);
29151            let prev_codepoint = prev_codepoint.replace(codepoint)?;
29152            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
29153                None
29154            } else {
29155                let chunk = &text[prev_index..]; // go to end of string
29156                Some(chunk)
29157            }
29158        })
29159}
29160
29161pub trait RangeToAnchorExt: Sized {
29162    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
29163
29164    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
29165        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
29166        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
29167    }
29168}
29169
29170impl<T: ToOffset> RangeToAnchorExt for Range<T> {
29171    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
29172        let start_offset = self.start.to_offset(snapshot);
29173        let end_offset = self.end.to_offset(snapshot);
29174        if start_offset == end_offset {
29175            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
29176        } else {
29177            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
29178        }
29179    }
29180}
29181
29182pub trait RowExt {
29183    fn as_f64(&self) -> f64;
29184
29185    fn next_row(&self) -> Self;
29186
29187    fn previous_row(&self) -> Self;
29188
29189    fn minus(&self, other: Self) -> u32;
29190}
29191
29192impl RowExt for DisplayRow {
29193    fn as_f64(&self) -> f64 {
29194        self.0 as _
29195    }
29196
29197    fn next_row(&self) -> Self {
29198        Self(self.0 + 1)
29199    }
29200
29201    fn previous_row(&self) -> Self {
29202        Self(self.0.saturating_sub(1))
29203    }
29204
29205    fn minus(&self, other: Self) -> u32 {
29206        self.0 - other.0
29207    }
29208}
29209
29210impl RowExt for MultiBufferRow {
29211    fn as_f64(&self) -> f64 {
29212        self.0 as _
29213    }
29214
29215    fn next_row(&self) -> Self {
29216        Self(self.0 + 1)
29217    }
29218
29219    fn previous_row(&self) -> Self {
29220        Self(self.0.saturating_sub(1))
29221    }
29222
29223    fn minus(&self, other: Self) -> u32 {
29224        self.0 - other.0
29225    }
29226}
29227
29228trait RowRangeExt {
29229    type Row;
29230
29231    fn len(&self) -> usize;
29232
29233    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29234}
29235
29236impl RowRangeExt for Range<MultiBufferRow> {
29237    type Row = MultiBufferRow;
29238
29239    fn len(&self) -> usize {
29240        (self.end.0 - self.start.0) as usize
29241    }
29242
29243    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29244        (self.start.0..self.end.0).map(MultiBufferRow)
29245    }
29246}
29247
29248impl RowRangeExt for Range<DisplayRow> {
29249    type Row = DisplayRow;
29250
29251    fn len(&self) -> usize {
29252        (self.end.0 - self.start.0) as usize
29253    }
29254
29255    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29256        (self.start.0..self.end.0).map(DisplayRow)
29257    }
29258}
29259
29260/// If select range has more than one line, we
29261/// just point the cursor to range.start.
29262fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29263    if range.start.row == range.end.row {
29264        range
29265    } else {
29266        range.start..range.start
29267    }
29268}
29269pub struct KillRing(ClipboardItem);
29270impl Global for KillRing {}
29271
29272const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29273
29274enum BreakpointPromptEditAction {
29275    Log,
29276    Condition,
29277    HitCondition,
29278}
29279
29280struct BreakpointPromptEditor {
29281    pub(crate) prompt: Entity<Editor>,
29282    editor: WeakEntity<Editor>,
29283    breakpoint_anchor: Anchor,
29284    breakpoint: Breakpoint,
29285    edit_action: BreakpointPromptEditAction,
29286    block_ids: HashSet<CustomBlockId>,
29287    editor_margins: Arc<Mutex<EditorMargins>>,
29288    _subscriptions: Vec<Subscription>,
29289}
29290
29291impl BreakpointPromptEditor {
29292    const MAX_LINES: u8 = 4;
29293
29294    fn new(
29295        editor: WeakEntity<Editor>,
29296        breakpoint_anchor: Anchor,
29297        breakpoint: Breakpoint,
29298        edit_action: BreakpointPromptEditAction,
29299        window: &mut Window,
29300        cx: &mut Context<Self>,
29301    ) -> Self {
29302        let base_text = match edit_action {
29303            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29304            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29305            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29306        }
29307        .map(|msg| msg.to_string())
29308        .unwrap_or_default();
29309
29310        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29311        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29312
29313        let prompt = cx.new(|cx| {
29314            let mut prompt = Editor::new(
29315                EditorMode::AutoHeight {
29316                    min_lines: 1,
29317                    max_lines: Some(Self::MAX_LINES as usize),
29318                },
29319                buffer,
29320                None,
29321                window,
29322                cx,
29323            );
29324            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29325            prompt.set_show_cursor_when_unfocused(false, cx);
29326            prompt.set_placeholder_text(
29327                match edit_action {
29328                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29329                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29330                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29331                },
29332                window,
29333                cx,
29334            );
29335
29336            prompt
29337        });
29338
29339        Self {
29340            prompt,
29341            editor,
29342            breakpoint_anchor,
29343            breakpoint,
29344            edit_action,
29345            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29346            block_ids: Default::default(),
29347            _subscriptions: vec![],
29348        }
29349    }
29350
29351    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29352        self.block_ids.extend(block_ids)
29353    }
29354
29355    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29356        if let Some(editor) = self.editor.upgrade() {
29357            let message = self
29358                .prompt
29359                .read(cx)
29360                .buffer
29361                .read(cx)
29362                .as_singleton()
29363                .expect("A multi buffer in breakpoint prompt isn't possible")
29364                .read(cx)
29365                .as_rope()
29366                .to_string();
29367
29368            editor.update(cx, |editor, cx| {
29369                editor.edit_breakpoint_at_anchor(
29370                    self.breakpoint_anchor,
29371                    self.breakpoint.clone(),
29372                    match self.edit_action {
29373                        BreakpointPromptEditAction::Log => {
29374                            BreakpointEditAction::EditLogMessage(message.into())
29375                        }
29376                        BreakpointPromptEditAction::Condition => {
29377                            BreakpointEditAction::EditCondition(message.into())
29378                        }
29379                        BreakpointPromptEditAction::HitCondition => {
29380                            BreakpointEditAction::EditHitCondition(message.into())
29381                        }
29382                    },
29383                    cx,
29384                );
29385
29386                editor.remove_blocks(self.block_ids.clone(), None, cx);
29387                cx.focus_self(window);
29388            });
29389        }
29390    }
29391
29392    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29393        self.editor
29394            .update(cx, |editor, cx| {
29395                editor.remove_blocks(self.block_ids.clone(), None, cx);
29396                window.focus(&editor.focus_handle, cx);
29397            })
29398            .log_err();
29399    }
29400
29401    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29402        let settings = ThemeSettings::get_global(cx);
29403        let text_style = TextStyle {
29404            color: if self.prompt.read(cx).read_only(cx) {
29405                cx.theme().colors().text_disabled
29406            } else {
29407                cx.theme().colors().text
29408            },
29409            font_family: settings.buffer_font.family.clone(),
29410            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29411            font_size: settings.buffer_font_size(cx).into(),
29412            font_weight: settings.buffer_font.weight,
29413            line_height: relative(settings.buffer_line_height.value()),
29414            ..Default::default()
29415        };
29416        EditorElement::new(
29417            &self.prompt,
29418            EditorStyle {
29419                background: cx.theme().colors().editor_background,
29420                local_player: cx.theme().players().local(),
29421                text: text_style,
29422                ..Default::default()
29423            },
29424        )
29425    }
29426
29427    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29428        let focus_handle = self.prompt.focus_handle(cx);
29429        IconButton::new("cancel", IconName::Close)
29430            .icon_color(Color::Muted)
29431            .shape(IconButtonShape::Square)
29432            .tooltip(move |_window, cx| {
29433                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29434            })
29435            .on_click(cx.listener(|this, _, window, cx| {
29436                this.cancel(&menu::Cancel, window, cx);
29437            }))
29438    }
29439
29440    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29441        let focus_handle = self.prompt.focus_handle(cx);
29442        IconButton::new("confirm", IconName::Return)
29443            .icon_color(Color::Muted)
29444            .shape(IconButtonShape::Square)
29445            .tooltip(move |_window, cx| {
29446                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29447            })
29448            .on_click(cx.listener(|this, _, window, cx| {
29449                this.confirm(&menu::Confirm, window, cx);
29450            }))
29451    }
29452}
29453
29454impl Render for BreakpointPromptEditor {
29455    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29456        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29457        let editor_margins = *self.editor_margins.lock();
29458        let gutter_dimensions = editor_margins.gutter;
29459        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29460        let right_padding = editor_margins.right + px(9.);
29461        h_flex()
29462            .key_context("Editor")
29463            .bg(cx.theme().colors().editor_background)
29464            .border_y_1()
29465            .border_color(cx.theme().status().info_border)
29466            .size_full()
29467            .py(window.line_height() / 2.5)
29468            .pr(right_padding)
29469            .on_action(cx.listener(Self::confirm))
29470            .on_action(cx.listener(Self::cancel))
29471            .child(
29472                WithRemSize::new(ui_font_size)
29473                    .h_full()
29474                    .w(left_gutter_width)
29475                    .flex()
29476                    .flex_row()
29477                    .flex_shrink_0()
29478                    .items_center()
29479                    .justify_center()
29480                    .gap_1()
29481                    .child(self.render_close_button(cx)),
29482            )
29483            .child(
29484                h_flex()
29485                    .w_full()
29486                    .justify_between()
29487                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29488                    .child(
29489                        WithRemSize::new(ui_font_size)
29490                            .flex()
29491                            .flex_row()
29492                            .items_center()
29493                            .child(self.render_confirm_button(cx)),
29494                    ),
29495            )
29496    }
29497}
29498
29499impl Focusable for BreakpointPromptEditor {
29500    fn focus_handle(&self, cx: &App) -> FocusHandle {
29501        self.prompt.focus_handle(cx)
29502    }
29503}
29504
29505fn all_edits_insertions_or_deletions(
29506    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29507    snapshot: &MultiBufferSnapshot,
29508) -> bool {
29509    let mut all_insertions = true;
29510    let mut all_deletions = true;
29511
29512    for (range, new_text) in edits.iter() {
29513        let range_is_empty = range.to_offset(snapshot).is_empty();
29514        let text_is_empty = new_text.is_empty();
29515
29516        if range_is_empty != text_is_empty {
29517            if range_is_empty {
29518                all_deletions = false;
29519            } else {
29520                all_insertions = false;
29521            }
29522        } else {
29523            return false;
29524        }
29525
29526        if !all_insertions && !all_deletions {
29527            return false;
29528        }
29529    }
29530    all_insertions || all_deletions
29531}
29532
29533struct MissingEditPredictionKeybindingTooltip;
29534
29535impl Render for MissingEditPredictionKeybindingTooltip {
29536    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29537        ui::tooltip_container(cx, |container, cx| {
29538            container
29539                .flex_shrink_0()
29540                .max_w_80()
29541                .min_h(rems_from_px(124.))
29542                .justify_between()
29543                .child(
29544                    v_flex()
29545                        .flex_1()
29546                        .text_ui_sm(cx)
29547                        .child(Label::new("Conflict with Accept Keybinding"))
29548                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29549                )
29550                .child(
29551                    h_flex()
29552                        .pb_1()
29553                        .gap_1()
29554                        .items_end()
29555                        .w_full()
29556                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29557                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29558                        }))
29559                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29560                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29561                        })),
29562                )
29563        })
29564    }
29565}
29566
29567#[derive(Debug, Clone, Copy, PartialEq)]
29568pub struct LineHighlight {
29569    pub background: Background,
29570    pub border: Option<gpui::Hsla>,
29571    pub include_gutter: bool,
29572    pub type_id: Option<TypeId>,
29573}
29574
29575struct LineManipulationResult {
29576    pub new_text: String,
29577    pub line_count_before: usize,
29578    pub line_count_after: usize,
29579}
29580
29581fn render_diff_hunk_controls(
29582    row: u32,
29583    status: &DiffHunkStatus,
29584    hunk_range: Range<Anchor>,
29585    is_created_file: bool,
29586    line_height: Pixels,
29587    editor: &Entity<Editor>,
29588    _window: &mut Window,
29589    cx: &mut App,
29590) -> AnyElement {
29591    h_flex()
29592        .h(line_height)
29593        .mr_1()
29594        .gap_1()
29595        .px_0p5()
29596        .pb_1()
29597        .border_x_1()
29598        .border_b_1()
29599        .border_color(cx.theme().colors().border_variant)
29600        .rounded_b_lg()
29601        .bg(cx.theme().colors().editor_background)
29602        .gap_1()
29603        .block_mouse_except_scroll()
29604        .shadow_md()
29605        .child(if status.has_secondary_hunk() {
29606            Button::new(("stage", row as u64), "Stage")
29607                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29608                .tooltip({
29609                    let focus_handle = editor.focus_handle(cx);
29610                    move |_window, cx| {
29611                        Tooltip::for_action_in(
29612                            "Stage Hunk",
29613                            &::git::ToggleStaged,
29614                            &focus_handle,
29615                            cx,
29616                        )
29617                    }
29618                })
29619                .on_click({
29620                    let editor = editor.clone();
29621                    move |_event, _window, cx| {
29622                        editor.update(cx, |editor, cx| {
29623                            editor.stage_or_unstage_diff_hunks(
29624                                true,
29625                                vec![hunk_range.start..hunk_range.start],
29626                                cx,
29627                            );
29628                        });
29629                    }
29630                })
29631        } else {
29632            Button::new(("unstage", row as u64), "Unstage")
29633                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29634                .tooltip({
29635                    let focus_handle = editor.focus_handle(cx);
29636                    move |_window, cx| {
29637                        Tooltip::for_action_in(
29638                            "Unstage Hunk",
29639                            &::git::ToggleStaged,
29640                            &focus_handle,
29641                            cx,
29642                        )
29643                    }
29644                })
29645                .on_click({
29646                    let editor = editor.clone();
29647                    move |_event, _window, cx| {
29648                        editor.update(cx, |editor, cx| {
29649                            editor.stage_or_unstage_diff_hunks(
29650                                false,
29651                                vec![hunk_range.start..hunk_range.start],
29652                                cx,
29653                            );
29654                        });
29655                    }
29656                })
29657        })
29658        .child(
29659            Button::new(("restore", row as u64), "Restore")
29660                .tooltip({
29661                    let focus_handle = editor.focus_handle(cx);
29662                    move |_window, cx| {
29663                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29664                    }
29665                })
29666                .on_click({
29667                    let editor = editor.clone();
29668                    move |_event, window, cx| {
29669                        editor.update(cx, |editor, cx| {
29670                            let snapshot = editor.snapshot(window, cx);
29671                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29672                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29673                        });
29674                    }
29675                })
29676                .disabled(is_created_file),
29677        )
29678        .when(
29679            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29680            |el| {
29681                el.child(
29682                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29683                        .shape(IconButtonShape::Square)
29684                        .icon_size(IconSize::Small)
29685                        // .disabled(!has_multiple_hunks)
29686                        .tooltip({
29687                            let focus_handle = editor.focus_handle(cx);
29688                            move |_window, cx| {
29689                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29690                            }
29691                        })
29692                        .on_click({
29693                            let editor = editor.clone();
29694                            move |_event, window, cx| {
29695                                editor.update(cx, |editor, cx| {
29696                                    let snapshot = editor.snapshot(window, cx);
29697                                    let position =
29698                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29699                                    editor.go_to_hunk_before_or_after_position(
29700                                        &snapshot,
29701                                        position,
29702                                        Direction::Next,
29703                                        true,
29704                                        window,
29705                                        cx,
29706                                    );
29707                                    editor.expand_selected_diff_hunks(cx);
29708                                });
29709                            }
29710                        }),
29711                )
29712                .child(
29713                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29714                        .shape(IconButtonShape::Square)
29715                        .icon_size(IconSize::Small)
29716                        // .disabled(!has_multiple_hunks)
29717                        .tooltip({
29718                            let focus_handle = editor.focus_handle(cx);
29719                            move |_window, cx| {
29720                                Tooltip::for_action_in(
29721                                    "Previous Hunk",
29722                                    &GoToPreviousHunk,
29723                                    &focus_handle,
29724                                    cx,
29725                                )
29726                            }
29727                        })
29728                        .on_click({
29729                            let editor = editor.clone();
29730                            move |_event, window, cx| {
29731                                editor.update(cx, |editor, cx| {
29732                                    let snapshot = editor.snapshot(window, cx);
29733                                    let point =
29734                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29735                                    editor.go_to_hunk_before_or_after_position(
29736                                        &snapshot,
29737                                        point,
29738                                        Direction::Prev,
29739                                        true,
29740                                        window,
29741                                        cx,
29742                                    );
29743                                    editor.expand_selected_diff_hunks(cx);
29744                                });
29745                            }
29746                        }),
29747                )
29748            },
29749        )
29750        .into_any_element()
29751}
29752
29753pub fn multibuffer_context_lines(cx: &App) -> u32 {
29754    EditorSettings::try_get(cx)
29755        .map(|settings| settings.excerpt_context_lines)
29756        .unwrap_or(2)
29757        .min(32)
29758}