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    show_line_numbers: Option<bool>,
 1187    use_relative_line_numbers: Option<bool>,
 1188    show_git_diff_gutter: Option<bool>,
 1189    show_code_actions: Option<bool>,
 1190    show_runnables: Option<bool>,
 1191    show_breakpoints: Option<bool>,
 1192    show_diff_review_button: bool,
 1193    show_wrap_guides: Option<bool>,
 1194    show_indent_guides: Option<bool>,
 1195    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1196    highlight_order: usize,
 1197    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1198    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1199    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1200    scrollbar_marker_state: ScrollbarMarkerState,
 1201    active_indent_guides_state: ActiveIndentGuidesState,
 1202    nav_history: Option<ItemNavHistory>,
 1203    context_menu: RefCell<Option<CodeContextMenu>>,
 1204    context_menu_options: Option<ContextMenuOptions>,
 1205    mouse_context_menu: Option<MouseContextMenu>,
 1206    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1207    inline_blame_popover: Option<InlineBlamePopover>,
 1208    inline_blame_popover_show_task: Option<Task<()>>,
 1209    signature_help_state: SignatureHelpState,
 1210    auto_signature_help: Option<bool>,
 1211    find_all_references_task_sources: Vec<Anchor>,
 1212    next_completion_id: CompletionId,
 1213    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1214    code_actions_task: Option<Task<Result<()>>>,
 1215    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1216    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1217    debounced_selection_highlight_complete: bool,
 1218    document_highlights_task: Option<Task<()>>,
 1219    linked_editing_range_task: Option<Task<Option<()>>>,
 1220    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1221    pending_rename: Option<RenameState>,
 1222    searchable: bool,
 1223    cursor_shape: CursorShape,
 1224    /// Whether the cursor is offset one character to the left when something is
 1225    /// selected (needed for vim visual mode)
 1226    cursor_offset_on_selection: bool,
 1227    current_line_highlight: Option<CurrentLineHighlight>,
 1228    /// Whether to collapse search match ranges to just their start position.
 1229    /// When true, navigating to a match positions the cursor at the match
 1230    /// without selecting the matched text.
 1231    collapse_matches: bool,
 1232    autoindent_mode: Option<AutoindentMode>,
 1233    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1234    input_enabled: bool,
 1235    expects_character_input: bool,
 1236    use_modal_editing: bool,
 1237    read_only: bool,
 1238    leader_id: Option<CollaboratorId>,
 1239    remote_id: Option<ViewId>,
 1240    pub hover_state: HoverState,
 1241    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1242    prev_pressure_stage: Option<PressureStage>,
 1243    gutter_hovered: bool,
 1244    hovered_link_state: Option<HoveredLinkState>,
 1245    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1246    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1247    active_edit_prediction: Option<EditPredictionState>,
 1248    /// Used to prevent flickering as the user types while the menu is open
 1249    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1250    edit_prediction_settings: EditPredictionSettings,
 1251    edit_predictions_hidden_for_vim_mode: bool,
 1252    show_edit_predictions_override: Option<bool>,
 1253    show_completions_on_input_override: Option<bool>,
 1254    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1255    edit_prediction_preview: EditPredictionPreview,
 1256    in_leading_whitespace: bool,
 1257    next_inlay_id: usize,
 1258    next_color_inlay_id: usize,
 1259    _subscriptions: Vec<Subscription>,
 1260    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1261    gutter_dimensions: GutterDimensions,
 1262    style: Option<EditorStyle>,
 1263    text_style_refinement: Option<TextStyleRefinement>,
 1264    next_editor_action_id: EditorActionId,
 1265    editor_actions: Rc<
 1266        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1267    >,
 1268    use_autoclose: bool,
 1269    use_auto_surround: bool,
 1270    use_selection_highlight: bool,
 1271    auto_replace_emoji_shortcode: bool,
 1272    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1273    show_git_blame_gutter: bool,
 1274    show_git_blame_inline: bool,
 1275    show_git_blame_inline_delay_task: Option<Task<()>>,
 1276    git_blame_inline_enabled: bool,
 1277    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1278    buffer_serialization: Option<BufferSerialization>,
 1279    show_selection_menu: Option<bool>,
 1280    blame: Option<Entity<GitBlame>>,
 1281    blame_subscription: Option<Subscription>,
 1282    custom_context_menu: Option<
 1283        Box<
 1284            dyn 'static
 1285                + Fn(
 1286                    &mut Self,
 1287                    DisplayPoint,
 1288                    &mut Window,
 1289                    &mut Context<Self>,
 1290                ) -> Option<Entity<ui::ContextMenu>>,
 1291        >,
 1292    >,
 1293    last_bounds: Option<Bounds<Pixels>>,
 1294    last_position_map: Option<Rc<PositionMap>>,
 1295    expect_bounds_change: Option<Bounds<Pixels>>,
 1296    runnables: RunnableData,
 1297    breakpoint_store: Option<Entity<BreakpointStore>>,
 1298    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1299    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1300    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1301    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1302    /// when hunks have comments stored.
 1303    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1304    /// Stored review comments grouped by hunk.
 1305    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1306    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1307    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1308    /// Counter for generating unique comment IDs.
 1309    next_review_comment_id: usize,
 1310    hovered_diff_hunk_row: Option<DisplayRow>,
 1311    pull_diagnostics_task: Task<()>,
 1312    in_project_search: bool,
 1313    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1314    breadcrumb_header: Option<String>,
 1315    focused_block: Option<FocusedBlock>,
 1316    next_scroll_position: NextScrollCursorCenterTopBottom,
 1317    addons: HashMap<TypeId, Box<dyn Addon>>,
 1318    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1319    load_diff_task: Option<Shared<Task<()>>>,
 1320    /// Whether we are temporarily displaying a diff other than git's
 1321    temporary_diff_override: bool,
 1322    selection_mark_mode: bool,
 1323    toggle_fold_multiple_buffers: Task<()>,
 1324    _scroll_cursor_center_top_bottom_task: Task<()>,
 1325    serialize_selections: Task<()>,
 1326    serialize_folds: Task<()>,
 1327    mouse_cursor_hidden: bool,
 1328    minimap: Option<Entity<Self>>,
 1329    hide_mouse_mode: HideMouseMode,
 1330    pub change_list: ChangeList,
 1331    inline_value_cache: InlineValueCache,
 1332    number_deleted_lines: bool,
 1333
 1334    selection_drag_state: SelectionDragState,
 1335    colors: Option<LspColorData>,
 1336    post_scroll_update: Task<()>,
 1337    refresh_colors_task: Task<()>,
 1338    use_document_folding_ranges: bool,
 1339    refresh_folding_ranges_task: Task<()>,
 1340    inlay_hints: Option<LspInlayHintData>,
 1341    folding_newlines: Task<()>,
 1342    select_next_is_case_sensitive: Option<bool>,
 1343    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1344    on_local_selections_changed:
 1345        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1346    suppress_selection_callback: bool,
 1347    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1348    accent_data: Option<AccentData>,
 1349    bracket_fetched_tree_sitter_chunks: HashMap<Range<text::Anchor>, HashSet<Range<BufferRow>>>,
 1350    semantic_token_state: SemanticTokenState,
 1351    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1352    refresh_document_symbols_task: Shared<Task<()>>,
 1353    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1354    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1355    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1356    sticky_headers_task: Task<()>,
 1357    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1358    pub(crate) colorize_brackets_task: Task<()>,
 1359}
 1360
 1361#[derive(Debug, PartialEq)]
 1362struct AccentData {
 1363    colors: AccentColors,
 1364    overrides: Vec<SharedString>,
 1365}
 1366
 1367fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1368    if debounce_ms > 0 {
 1369        Some(Duration::from_millis(debounce_ms))
 1370    } else {
 1371        None
 1372    }
 1373}
 1374
 1375#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1376enum NextScrollCursorCenterTopBottom {
 1377    #[default]
 1378    Center,
 1379    Top,
 1380    Bottom,
 1381}
 1382
 1383impl NextScrollCursorCenterTopBottom {
 1384    fn next(&self) -> Self {
 1385        match self {
 1386            Self::Center => Self::Top,
 1387            Self::Top => Self::Bottom,
 1388            Self::Bottom => Self::Center,
 1389        }
 1390    }
 1391}
 1392
 1393#[derive(Clone)]
 1394pub struct EditorSnapshot {
 1395    pub mode: EditorMode,
 1396    show_gutter: bool,
 1397    offset_content: bool,
 1398    show_line_numbers: Option<bool>,
 1399    number_deleted_lines: bool,
 1400    show_git_diff_gutter: Option<bool>,
 1401    show_code_actions: Option<bool>,
 1402    show_runnables: Option<bool>,
 1403    show_breakpoints: Option<bool>,
 1404    git_blame_gutter_max_author_length: Option<usize>,
 1405    pub display_snapshot: DisplaySnapshot,
 1406    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1407    is_focused: bool,
 1408    scroll_anchor: SharedScrollAnchor,
 1409    ongoing_scroll: OngoingScroll,
 1410    current_line_highlight: CurrentLineHighlight,
 1411    gutter_hovered: bool,
 1412    semantic_tokens_enabled: bool,
 1413}
 1414
 1415#[derive(Default, Debug, Clone, Copy)]
 1416pub struct GutterDimensions {
 1417    pub left_padding: Pixels,
 1418    pub right_padding: Pixels,
 1419    pub width: Pixels,
 1420    pub margin: Pixels,
 1421    pub git_blame_entries_width: Option<Pixels>,
 1422}
 1423
 1424impl GutterDimensions {
 1425    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1426        Self {
 1427            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1428            ..Default::default()
 1429        }
 1430    }
 1431
 1432    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1433        -cx.text_system().descent(font_id, font_size)
 1434    }
 1435    /// The full width of the space taken up by the gutter.
 1436    pub fn full_width(&self) -> Pixels {
 1437        self.margin + self.width
 1438    }
 1439
 1440    /// The width of the space reserved for the fold indicators,
 1441    /// use alongside 'justify_end' and `gutter_width` to
 1442    /// right align content with the line numbers
 1443    pub fn fold_area_width(&self) -> Pixels {
 1444        self.margin + self.right_padding
 1445    }
 1446}
 1447
 1448struct CharacterDimensions {
 1449    em_width: Pixels,
 1450    em_advance: Pixels,
 1451    line_height: Pixels,
 1452}
 1453
 1454#[derive(Debug)]
 1455pub struct RemoteSelection {
 1456    pub replica_id: ReplicaId,
 1457    pub selection: Selection<Anchor>,
 1458    pub cursor_shape: CursorShape,
 1459    pub collaborator_id: CollaboratorId,
 1460    pub line_mode: bool,
 1461    pub user_name: Option<SharedString>,
 1462    pub color: PlayerColor,
 1463}
 1464
 1465#[derive(Clone, Debug)]
 1466struct SelectionHistoryEntry {
 1467    selections: Arc<[Selection<Anchor>]>,
 1468    select_next_state: Option<SelectNextState>,
 1469    select_prev_state: Option<SelectNextState>,
 1470    add_selections_state: Option<AddSelectionsState>,
 1471}
 1472
 1473#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1474enum SelectionHistoryMode {
 1475    #[default]
 1476    Normal,
 1477    Undoing,
 1478    Redoing,
 1479    Skipping,
 1480}
 1481
 1482#[derive(Clone, PartialEq, Eq, Hash)]
 1483struct HoveredCursor {
 1484    replica_id: ReplicaId,
 1485    selection_id: usize,
 1486}
 1487
 1488#[derive(Debug)]
 1489/// SelectionEffects controls the side-effects of updating the selection.
 1490///
 1491/// The default behaviour does "what you mostly want":
 1492/// - it pushes to the nav history if the cursor moved by >10 lines
 1493/// - it re-triggers completion requests
 1494/// - it scrolls to fit
 1495///
 1496/// You might want to modify these behaviours. For example when doing a "jump"
 1497/// like go to definition, we always want to add to nav history; but when scrolling
 1498/// in vim mode we never do.
 1499///
 1500/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1501/// move.
 1502#[derive(Clone)]
 1503pub struct SelectionEffects {
 1504    nav_history: Option<bool>,
 1505    completions: bool,
 1506    scroll: Option<Autoscroll>,
 1507}
 1508
 1509impl Default for SelectionEffects {
 1510    fn default() -> Self {
 1511        Self {
 1512            nav_history: None,
 1513            completions: true,
 1514            scroll: Some(Autoscroll::fit()),
 1515        }
 1516    }
 1517}
 1518impl SelectionEffects {
 1519    pub fn scroll(scroll: Autoscroll) -> Self {
 1520        Self {
 1521            scroll: Some(scroll),
 1522            ..Default::default()
 1523        }
 1524    }
 1525
 1526    pub fn no_scroll() -> Self {
 1527        Self {
 1528            scroll: None,
 1529            ..Default::default()
 1530        }
 1531    }
 1532
 1533    pub fn completions(self, completions: bool) -> Self {
 1534        Self {
 1535            completions,
 1536            ..self
 1537        }
 1538    }
 1539
 1540    pub fn nav_history(self, nav_history: bool) -> Self {
 1541        Self {
 1542            nav_history: Some(nav_history),
 1543            ..self
 1544        }
 1545    }
 1546}
 1547
 1548struct DeferredSelectionEffectsState {
 1549    changed: bool,
 1550    effects: SelectionEffects,
 1551    old_cursor_position: Anchor,
 1552    history_entry: SelectionHistoryEntry,
 1553}
 1554
 1555#[derive(Default)]
 1556struct SelectionHistory {
 1557    #[allow(clippy::type_complexity)]
 1558    selections_by_transaction:
 1559        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1560    mode: SelectionHistoryMode,
 1561    undo_stack: VecDeque<SelectionHistoryEntry>,
 1562    redo_stack: VecDeque<SelectionHistoryEntry>,
 1563}
 1564
 1565impl SelectionHistory {
 1566    #[track_caller]
 1567    fn insert_transaction(
 1568        &mut self,
 1569        transaction_id: TransactionId,
 1570        selections: Arc<[Selection<Anchor>]>,
 1571    ) {
 1572        if selections.is_empty() {
 1573            log::error!(
 1574                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1575                std::panic::Location::caller()
 1576            );
 1577            return;
 1578        }
 1579        self.selections_by_transaction
 1580            .insert(transaction_id, (selections, None));
 1581    }
 1582
 1583    #[allow(clippy::type_complexity)]
 1584    fn transaction(
 1585        &self,
 1586        transaction_id: TransactionId,
 1587    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1588        self.selections_by_transaction.get(&transaction_id)
 1589    }
 1590
 1591    #[allow(clippy::type_complexity)]
 1592    fn transaction_mut(
 1593        &mut self,
 1594        transaction_id: TransactionId,
 1595    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1596        self.selections_by_transaction.get_mut(&transaction_id)
 1597    }
 1598
 1599    fn push(&mut self, entry: SelectionHistoryEntry) {
 1600        if !entry.selections.is_empty() {
 1601            match self.mode {
 1602                SelectionHistoryMode::Normal => {
 1603                    self.push_undo(entry);
 1604                    self.redo_stack.clear();
 1605                }
 1606                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1607                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1608                SelectionHistoryMode::Skipping => {}
 1609            }
 1610        }
 1611    }
 1612
 1613    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1614        if self
 1615            .undo_stack
 1616            .back()
 1617            .is_none_or(|e| e.selections != entry.selections)
 1618        {
 1619            self.undo_stack.push_back(entry);
 1620            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1621                self.undo_stack.pop_front();
 1622            }
 1623        }
 1624    }
 1625
 1626    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1627        if self
 1628            .redo_stack
 1629            .back()
 1630            .is_none_or(|e| e.selections != entry.selections)
 1631        {
 1632            self.redo_stack.push_back(entry);
 1633            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1634                self.redo_stack.pop_front();
 1635            }
 1636        }
 1637    }
 1638}
 1639
 1640#[derive(Clone, Copy)]
 1641pub struct RowHighlightOptions {
 1642    pub autoscroll: bool,
 1643    pub include_gutter: bool,
 1644}
 1645
 1646impl Default for RowHighlightOptions {
 1647    fn default() -> Self {
 1648        Self {
 1649            autoscroll: Default::default(),
 1650            include_gutter: true,
 1651        }
 1652    }
 1653}
 1654
 1655struct RowHighlight {
 1656    index: usize,
 1657    range: Range<Anchor>,
 1658    color: Hsla,
 1659    options: RowHighlightOptions,
 1660    type_id: TypeId,
 1661}
 1662
 1663#[derive(Clone, Debug)]
 1664struct AddSelectionsState {
 1665    groups: Vec<AddSelectionsGroup>,
 1666}
 1667
 1668#[derive(Clone, Debug)]
 1669struct AddSelectionsGroup {
 1670    above: bool,
 1671    stack: Vec<usize>,
 1672}
 1673
 1674#[derive(Clone)]
 1675struct SelectNextState {
 1676    query: AhoCorasick,
 1677    wordwise: bool,
 1678    done: bool,
 1679}
 1680
 1681impl std::fmt::Debug for SelectNextState {
 1682    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1683        f.debug_struct(std::any::type_name::<Self>())
 1684            .field("wordwise", &self.wordwise)
 1685            .field("done", &self.done)
 1686            .finish()
 1687    }
 1688}
 1689
 1690#[derive(Debug)]
 1691struct AutocloseRegion {
 1692    selection_id: usize,
 1693    range: Range<Anchor>,
 1694    pair: BracketPair,
 1695}
 1696
 1697#[derive(Debug)]
 1698struct SnippetState {
 1699    ranges: Vec<Vec<Range<Anchor>>>,
 1700    active_index: usize,
 1701    choices: Vec<Option<Vec<String>>>,
 1702}
 1703
 1704#[doc(hidden)]
 1705pub struct RenameState {
 1706    pub range: Range<Anchor>,
 1707    pub old_name: Arc<str>,
 1708    pub editor: Entity<Editor>,
 1709    block_id: CustomBlockId,
 1710}
 1711
 1712struct InvalidationStack<T>(Vec<T>);
 1713
 1714struct RegisteredEditPredictionDelegate {
 1715    provider: Arc<dyn EditPredictionDelegateHandle>,
 1716    _subscription: Subscription,
 1717}
 1718
 1719#[derive(Debug, PartialEq, Eq)]
 1720pub struct ActiveDiagnosticGroup {
 1721    pub active_range: Range<Anchor>,
 1722    pub active_message: String,
 1723    pub group_id: usize,
 1724    pub blocks: HashSet<CustomBlockId>,
 1725}
 1726
 1727#[derive(Debug, PartialEq, Eq)]
 1728
 1729pub(crate) enum ActiveDiagnostic {
 1730    None,
 1731    All,
 1732    Group(ActiveDiagnosticGroup),
 1733}
 1734
 1735#[derive(Serialize, Deserialize, Clone, Debug)]
 1736pub struct ClipboardSelection {
 1737    /// The number of bytes in this selection.
 1738    pub len: usize,
 1739    /// Whether this was a full-line selection.
 1740    pub is_entire_line: bool,
 1741    /// The indentation of the first line when this content was originally copied.
 1742    pub first_line_indent: u32,
 1743    #[serde(default)]
 1744    pub file_path: Option<PathBuf>,
 1745    #[serde(default)]
 1746    pub line_range: Option<RangeInclusive<u32>>,
 1747}
 1748
 1749impl ClipboardSelection {
 1750    pub fn for_buffer(
 1751        len: usize,
 1752        is_entire_line: bool,
 1753        range: Range<Point>,
 1754        buffer: &MultiBufferSnapshot,
 1755        project: Option<&Entity<Project>>,
 1756        cx: &App,
 1757    ) -> Self {
 1758        let first_line_indent = buffer
 1759            .indent_size_for_line(MultiBufferRow(range.start.row))
 1760            .len;
 1761
 1762        let file_path = util::maybe!({
 1763            let project = project?.read(cx);
 1764            let file = buffer.file_at(range.start)?;
 1765            let project_path = ProjectPath {
 1766                worktree_id: file.worktree_id(cx),
 1767                path: file.path().clone(),
 1768            };
 1769            project.absolute_path(&project_path, cx)
 1770        });
 1771
 1772        let line_range = if file_path.is_some() {
 1773            buffer
 1774                .range_to_buffer_range(range)
 1775                .map(|(_, buffer_range)| buffer_range.start.row..=buffer_range.end.row)
 1776        } else {
 1777            None
 1778        };
 1779
 1780        Self {
 1781            len,
 1782            is_entire_line,
 1783            first_line_indent,
 1784            file_path,
 1785            line_range,
 1786        }
 1787    }
 1788}
 1789
 1790// selections, scroll behavior, was newest selection reversed
 1791type SelectSyntaxNodeHistoryState = (
 1792    Box<[Selection<Anchor>]>,
 1793    SelectSyntaxNodeScrollBehavior,
 1794    bool,
 1795);
 1796
 1797#[derive(Default)]
 1798struct SelectSyntaxNodeHistory {
 1799    stack: Vec<SelectSyntaxNodeHistoryState>,
 1800    // disable temporarily to allow changing selections without losing the stack
 1801    pub disable_clearing: bool,
 1802}
 1803
 1804impl SelectSyntaxNodeHistory {
 1805    pub fn try_clear(&mut self) {
 1806        if !self.disable_clearing {
 1807            self.stack.clear();
 1808        }
 1809    }
 1810
 1811    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1812        self.stack.push(selection);
 1813    }
 1814
 1815    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1816        self.stack.pop()
 1817    }
 1818}
 1819
 1820enum SelectSyntaxNodeScrollBehavior {
 1821    CursorTop,
 1822    FitSelection,
 1823    CursorBottom,
 1824}
 1825
 1826#[derive(Debug, Clone, Copy)]
 1827pub(crate) struct NavigationData {
 1828    cursor_anchor: Anchor,
 1829    cursor_position: Point,
 1830    scroll_anchor: ScrollAnchor,
 1831    scroll_top_row: u32,
 1832}
 1833
 1834#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1835pub enum GotoDefinitionKind {
 1836    Symbol,
 1837    Declaration,
 1838    Type,
 1839    Implementation,
 1840}
 1841
 1842pub enum FormatTarget {
 1843    Buffers(HashSet<Entity<Buffer>>),
 1844    Ranges(Vec<Range<MultiBufferPoint>>),
 1845}
 1846
 1847pub(crate) struct FocusedBlock {
 1848    id: BlockId,
 1849    focus_handle: WeakFocusHandle,
 1850}
 1851
 1852#[derive(Clone, Debug)]
 1853pub enum JumpData {
 1854    MultiBufferRow {
 1855        row: MultiBufferRow,
 1856        line_offset_from_top: u32,
 1857    },
 1858    MultiBufferPoint {
 1859        anchor: language::Anchor,
 1860        position: Point,
 1861        line_offset_from_top: u32,
 1862    },
 1863}
 1864
 1865pub enum MultibufferSelectionMode {
 1866    First,
 1867    All,
 1868}
 1869
 1870#[derive(Clone, Copy, Debug, Default)]
 1871pub struct RewrapOptions {
 1872    pub override_language_settings: bool,
 1873    pub preserve_existing_whitespace: bool,
 1874    pub line_length: Option<usize>,
 1875}
 1876
 1877impl Editor {
 1878    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1879        let buffer = cx.new(|cx| Buffer::local("", cx));
 1880        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1881        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1882    }
 1883
 1884    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1885        let buffer = cx.new(|cx| Buffer::local("", cx));
 1886        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1887        Self::new(EditorMode::full(), buffer, None, window, cx)
 1888    }
 1889
 1890    pub fn auto_height(
 1891        min_lines: usize,
 1892        max_lines: usize,
 1893        window: &mut Window,
 1894        cx: &mut Context<Self>,
 1895    ) -> Self {
 1896        let buffer = cx.new(|cx| Buffer::local("", cx));
 1897        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1898        Self::new(
 1899            EditorMode::AutoHeight {
 1900                min_lines,
 1901                max_lines: Some(max_lines),
 1902            },
 1903            buffer,
 1904            None,
 1905            window,
 1906            cx,
 1907        )
 1908    }
 1909
 1910    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1911    /// The editor grows as tall as needed to fit its content.
 1912    pub fn auto_height_unbounded(
 1913        min_lines: usize,
 1914        window: &mut Window,
 1915        cx: &mut Context<Self>,
 1916    ) -> Self {
 1917        let buffer = cx.new(|cx| Buffer::local("", cx));
 1918        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1919        Self::new(
 1920            EditorMode::AutoHeight {
 1921                min_lines,
 1922                max_lines: None,
 1923            },
 1924            buffer,
 1925            None,
 1926            window,
 1927            cx,
 1928        )
 1929    }
 1930
 1931    pub fn for_buffer(
 1932        buffer: Entity<Buffer>,
 1933        project: Option<Entity<Project>>,
 1934        window: &mut Window,
 1935        cx: &mut Context<Self>,
 1936    ) -> Self {
 1937        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1938        Self::new(EditorMode::full(), buffer, project, window, cx)
 1939    }
 1940
 1941    pub fn for_multibuffer(
 1942        buffer: Entity<MultiBuffer>,
 1943        project: Option<Entity<Project>>,
 1944        window: &mut Window,
 1945        cx: &mut Context<Self>,
 1946    ) -> Self {
 1947        Self::new(EditorMode::full(), buffer, project, window, cx)
 1948    }
 1949
 1950    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1951        let mut clone = Self::new(
 1952            self.mode.clone(),
 1953            self.buffer.clone(),
 1954            self.project.clone(),
 1955            window,
 1956            cx,
 1957        );
 1958        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1959            let snapshot = display_map.snapshot(cx);
 1960            clone.display_map.update(cx, |display_map, cx| {
 1961                display_map.set_state(&snapshot, cx);
 1962            });
 1963            snapshot
 1964        });
 1965        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1966        clone.folds_did_change(cx);
 1967        clone.selections.clone_state(&self.selections);
 1968        clone
 1969            .scroll_manager
 1970            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1971        clone.searchable = self.searchable;
 1972        clone.read_only = self.read_only;
 1973        clone.buffers_with_disabled_indent_guides =
 1974            self.buffers_with_disabled_indent_guides.clone();
 1975        clone
 1976    }
 1977
 1978    pub fn new(
 1979        mode: EditorMode,
 1980        buffer: Entity<MultiBuffer>,
 1981        project: Option<Entity<Project>>,
 1982        window: &mut Window,
 1983        cx: &mut Context<Self>,
 1984    ) -> Self {
 1985        Editor::new_internal(mode, buffer, project, None, window, cx)
 1986    }
 1987
 1988    pub fn refresh_sticky_headers(
 1989        &mut self,
 1990        display_snapshot: &DisplaySnapshot,
 1991        cx: &mut Context<Editor>,
 1992    ) {
 1993        if !self.mode.is_full() {
 1994            return;
 1995        }
 1996        let multi_buffer = display_snapshot.buffer_snapshot().clone();
 1997        let scroll_anchor = self
 1998            .scroll_manager
 1999            .native_anchor(display_snapshot, cx)
 2000            .anchor;
 2001        let Some(buffer_snapshot) = multi_buffer.as_singleton() else {
 2002            return;
 2003        };
 2004
 2005        let buffer = buffer_snapshot.clone();
 2006        let Some((buffer_visible_start, _)) = multi_buffer.anchor_to_buffer_anchor(scroll_anchor)
 2007        else {
 2008            return;
 2009        };
 2010        let buffer_visible_start = buffer_visible_start.to_point(&buffer);
 2011        let max_row = buffer.max_point().row;
 2012        let start_row = buffer_visible_start.row.min(max_row);
 2013        let end_row = (buffer_visible_start.row + 10).min(max_row);
 2014
 2015        let syntax = self.style(cx).syntax.clone();
 2016        let background_task = cx.background_spawn(async move {
 2017            buffer
 2018                .outline_items_containing(
 2019                    Point::new(start_row, 0)..Point::new(end_row, 0),
 2020                    true,
 2021                    Some(syntax.as_ref()),
 2022                )
 2023                .into_iter()
 2024                .filter_map(|outline_item| {
 2025                    Some(OutlineItem {
 2026                        depth: outline_item.depth,
 2027                        range: multi_buffer
 2028                            .buffer_anchor_range_to_anchor_range(outline_item.range)?,
 2029                        source_range_for_text: multi_buffer.buffer_anchor_range_to_anchor_range(
 2030                            outline_item.source_range_for_text,
 2031                        )?,
 2032                        text: outline_item.text,
 2033                        highlight_ranges: outline_item.highlight_ranges,
 2034                        name_ranges: outline_item.name_ranges,
 2035                        body_range: outline_item.body_range.and_then(|range| {
 2036                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2037                        }),
 2038                        annotation_range: outline_item.annotation_range.and_then(|range| {
 2039                            multi_buffer.buffer_anchor_range_to_anchor_range(range)
 2040                        }),
 2041                    })
 2042                })
 2043                .collect()
 2044        });
 2045        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2046            let sticky_headers = background_task.await;
 2047            this.update(cx, |this, cx| {
 2048                this.sticky_headers = Some(sticky_headers);
 2049                cx.notify();
 2050            })
 2051            .ok();
 2052        });
 2053    }
 2054
 2055    fn new_internal(
 2056        mode: EditorMode,
 2057        multi_buffer: Entity<MultiBuffer>,
 2058        project: Option<Entity<Project>>,
 2059        display_map: Option<Entity<DisplayMap>>,
 2060        window: &mut Window,
 2061        cx: &mut Context<Self>,
 2062    ) -> Self {
 2063        debug_assert!(
 2064            display_map.is_none() || mode.is_minimap(),
 2065            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2066        );
 2067
 2068        let full_mode = mode.is_full();
 2069        let is_minimap = mode.is_minimap();
 2070        let diagnostics_max_severity = if full_mode {
 2071            EditorSettings::get_global(cx)
 2072                .diagnostics_max_severity
 2073                .unwrap_or(DiagnosticSeverity::Hint)
 2074        } else {
 2075            DiagnosticSeverity::Off
 2076        };
 2077        let style = window.text_style();
 2078        let font_size = style.font_size.to_pixels(window.rem_size());
 2079        let editor = cx.entity().downgrade();
 2080        let fold_placeholder = FoldPlaceholder {
 2081            constrain_width: false,
 2082            render: Arc::new(move |fold_id, fold_range, cx| {
 2083                let editor = editor.clone();
 2084                FoldPlaceholder::fold_element(fold_id, cx)
 2085                    .cursor_pointer()
 2086                    .child("")
 2087                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2088                    .on_click(move |_, _window, cx| {
 2089                        editor
 2090                            .update(cx, |editor, cx| {
 2091                                editor.unfold_ranges(
 2092                                    &[fold_range.start..fold_range.end],
 2093                                    true,
 2094                                    false,
 2095                                    cx,
 2096                                );
 2097                                cx.stop_propagation();
 2098                            })
 2099                            .ok();
 2100                    })
 2101                    .into_any()
 2102            }),
 2103            merge_adjacent: true,
 2104            ..FoldPlaceholder::default()
 2105        };
 2106        let display_map = display_map.unwrap_or_else(|| {
 2107            cx.new(|cx| {
 2108                DisplayMap::new(
 2109                    multi_buffer.clone(),
 2110                    style.font(),
 2111                    font_size,
 2112                    None,
 2113                    FILE_HEADER_HEIGHT,
 2114                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2115                    fold_placeholder,
 2116                    diagnostics_max_severity,
 2117                    cx,
 2118                )
 2119            })
 2120        });
 2121
 2122        let selections = SelectionsCollection::new();
 2123
 2124        let blink_manager = cx.new(|cx| {
 2125            let mut blink_manager = BlinkManager::new(
 2126                CURSOR_BLINK_INTERVAL,
 2127                |cx| EditorSettings::get_global(cx).cursor_blink,
 2128                cx,
 2129            );
 2130            if is_minimap {
 2131                blink_manager.disable(cx);
 2132            }
 2133            blink_manager
 2134        });
 2135
 2136        let soft_wrap_mode_override =
 2137            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2138
 2139        let mut project_subscriptions = Vec::new();
 2140        if full_mode && let Some(project) = project.as_ref() {
 2141            project_subscriptions.push(cx.subscribe_in(
 2142                project,
 2143                window,
 2144                |editor, _, event, window, cx| match event {
 2145                    project::Event::RefreshCodeLens => {
 2146                        // we always query lens with actions, without storing them, always refreshing them
 2147                    }
 2148                    project::Event::RefreshInlayHints {
 2149                        server_id,
 2150                        request_id,
 2151                    } => {
 2152                        editor.refresh_inlay_hints(
 2153                            InlayHintRefreshReason::RefreshRequested {
 2154                                server_id: *server_id,
 2155                                request_id: *request_id,
 2156                            },
 2157                            cx,
 2158                        );
 2159                    }
 2160                    project::Event::RefreshSemanticTokens {
 2161                        server_id,
 2162                        request_id,
 2163                    } => {
 2164                        editor.refresh_semantic_tokens(
 2165                            None,
 2166                            Some(RefreshForServer {
 2167                                server_id: *server_id,
 2168                                request_id: *request_id,
 2169                            }),
 2170                            cx,
 2171                        );
 2172                    }
 2173                    project::Event::LanguageServerRemoved(_) => {
 2174                        editor.registered_buffers.clear();
 2175                        editor.register_visible_buffers(cx);
 2176                        editor.invalidate_semantic_tokens(None);
 2177                        editor.refresh_runnables(None, window, cx);
 2178                        editor.update_lsp_data(None, window, cx);
 2179                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2180                    }
 2181                    project::Event::SnippetEdit(id, snippet_edits) => {
 2182                        // todo(lw): Non singletons
 2183                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2184                            let snapshot = buffer.read(cx).snapshot();
 2185                            let focus_handle = editor.focus_handle(cx);
 2186                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2187                                for (range, snippet) in snippet_edits {
 2188                                    let buffer_range =
 2189                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2190                                    editor
 2191                                        .insert_snippet(
 2192                                            &[MultiBufferOffset(buffer_range.start)
 2193                                                ..MultiBufferOffset(buffer_range.end)],
 2194                                            snippet.clone(),
 2195                                            window,
 2196                                            cx,
 2197                                        )
 2198                                        .ok();
 2199                                }
 2200                            }
 2201                        }
 2202                    }
 2203                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2204                        let buffer_id = *buffer_id;
 2205                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2206                            editor.register_buffer(buffer_id, cx);
 2207                            editor.refresh_runnables(Some(buffer_id), window, cx);
 2208                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2209                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2210                            refresh_linked_ranges(editor, window, cx);
 2211                            editor.refresh_code_actions(window, cx);
 2212                            editor.refresh_document_highlights(cx);
 2213                        }
 2214                    }
 2215
 2216                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2217                        let Some(workspace) = editor.workspace() else {
 2218                            return;
 2219                        };
 2220                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2221                        else {
 2222                            return;
 2223                        };
 2224
 2225                        if active_editor.entity_id() == cx.entity_id() {
 2226                            let entity_id = cx.entity_id();
 2227                            workspace.update(cx, |this, cx| {
 2228                                this.panes_mut()
 2229                                    .iter_mut()
 2230                                    .filter(|pane| pane.entity_id() != entity_id)
 2231                                    .for_each(|p| {
 2232                                        p.update(cx, |pane, _| {
 2233                                            pane.nav_history_mut().rename_item(
 2234                                                entity_id,
 2235                                                project_path.clone(),
 2236                                                abs_path.clone().into(),
 2237                                            );
 2238                                        })
 2239                                    });
 2240                            });
 2241
 2242                            Self::open_transaction_for_hidden_buffers(
 2243                                workspace,
 2244                                transaction.clone(),
 2245                                "Rename".to_string(),
 2246                                window,
 2247                                cx,
 2248                            );
 2249                        }
 2250                    }
 2251
 2252                    project::Event::WorkspaceEditApplied(transaction) => {
 2253                        let Some(workspace) = editor.workspace() else {
 2254                            return;
 2255                        };
 2256                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2257                        else {
 2258                            return;
 2259                        };
 2260
 2261                        if active_editor.entity_id() == cx.entity_id() {
 2262                            Self::open_transaction_for_hidden_buffers(
 2263                                workspace,
 2264                                transaction.clone(),
 2265                                "LSP Edit".to_string(),
 2266                                window,
 2267                                cx,
 2268                            );
 2269                        }
 2270                    }
 2271
 2272                    _ => {}
 2273                },
 2274            ));
 2275            if let Some(task_inventory) = project
 2276                .read(cx)
 2277                .task_store()
 2278                .read(cx)
 2279                .task_inventory()
 2280                .cloned()
 2281            {
 2282                project_subscriptions.push(cx.observe_in(
 2283                    &task_inventory,
 2284                    window,
 2285                    |editor, _, window, cx| {
 2286                        editor.refresh_runnables(None, window, cx);
 2287                    },
 2288                ));
 2289            };
 2290
 2291            project_subscriptions.push(cx.subscribe_in(
 2292                &project.read(cx).breakpoint_store(),
 2293                window,
 2294                |editor, _, event, window, cx| match event {
 2295                    BreakpointStoreEvent::ClearDebugLines => {
 2296                        editor.clear_row_highlights::<ActiveDebugLine>();
 2297                        editor.refresh_inline_values(cx);
 2298                    }
 2299                    BreakpointStoreEvent::SetDebugLine => {
 2300                        if editor.go_to_active_debug_line(window, cx) {
 2301                            cx.stop_propagation();
 2302                        }
 2303
 2304                        editor.refresh_inline_values(cx);
 2305                    }
 2306                    _ => {}
 2307                },
 2308            ));
 2309            let git_store = project.read(cx).git_store().clone();
 2310            let project = project.clone();
 2311            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2312                if let GitStoreEvent::RepositoryAdded = event {
 2313                    this.load_diff_task = Some(
 2314                        update_uncommitted_diff_for_buffer(
 2315                            cx.entity(),
 2316                            &project,
 2317                            this.buffer.read(cx).all_buffers(),
 2318                            this.buffer.clone(),
 2319                            cx,
 2320                        )
 2321                        .shared(),
 2322                    );
 2323                }
 2324            }));
 2325        }
 2326
 2327        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2328
 2329        let inlay_hint_settings =
 2330            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2331        let focus_handle = cx.focus_handle();
 2332        if !is_minimap {
 2333            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2334                .detach();
 2335            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2336                .detach();
 2337            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2338                .detach();
 2339            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2340                .detach();
 2341            cx.observe_pending_input(window, Self::observe_pending_input)
 2342                .detach();
 2343        }
 2344
 2345        let show_indent_guides =
 2346            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2347                Some(false)
 2348            } else {
 2349                None
 2350            };
 2351
 2352        let breakpoint_store = match (&mode, project.as_ref()) {
 2353            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2354            _ => None,
 2355        };
 2356
 2357        let mut code_action_providers = Vec::new();
 2358        let mut load_uncommitted_diff = None;
 2359        if let Some(project) = project.clone() {
 2360            load_uncommitted_diff = Some(
 2361                update_uncommitted_diff_for_buffer(
 2362                    cx.entity(),
 2363                    &project,
 2364                    multi_buffer.read(cx).all_buffers(),
 2365                    multi_buffer.clone(),
 2366                    cx,
 2367                )
 2368                .shared(),
 2369            );
 2370            code_action_providers.push(Rc::new(project) as Rc<_>);
 2371        }
 2372
 2373        let mut editor = Self {
 2374            focus_handle,
 2375            show_cursor_when_unfocused: false,
 2376            last_focused_descendant: None,
 2377            buffer: multi_buffer.clone(),
 2378            display_map: display_map.clone(),
 2379            placeholder_display_map: None,
 2380            selections,
 2381            scroll_manager: ScrollManager::new(cx),
 2382            columnar_selection_state: None,
 2383            add_selections_state: None,
 2384            select_next_state: None,
 2385            select_prev_state: None,
 2386            selection_history: SelectionHistory::default(),
 2387            defer_selection_effects: false,
 2388            deferred_selection_effects_state: None,
 2389            autoclose_regions: Vec::new(),
 2390            snippet_stack: InvalidationStack::default(),
 2391            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2392            ime_transaction: None,
 2393            active_diagnostics: ActiveDiagnostic::None,
 2394            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2395            inline_diagnostics_update: Task::ready(()),
 2396            inline_diagnostics: Vec::new(),
 2397            soft_wrap_mode_override,
 2398            diagnostics_max_severity,
 2399            hard_wrap: None,
 2400            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2401            semantics_provider: project
 2402                .as_ref()
 2403                .map(|project| Rc::new(project.downgrade()) as _),
 2404            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2405            project,
 2406            blink_manager: blink_manager.clone(),
 2407            show_local_selections: true,
 2408            show_scrollbars: ScrollbarAxes {
 2409                horizontal: full_mode,
 2410                vertical: full_mode,
 2411            },
 2412            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2413            offset_content: !matches!(mode, EditorMode::SingleLine),
 2414            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2415            show_gutter: full_mode,
 2416            show_line_numbers: (!full_mode).then_some(false),
 2417            use_relative_line_numbers: None,
 2418            disable_expand_excerpt_buttons: !full_mode,
 2419            delegate_expand_excerpts: false,
 2420            delegate_stage_and_restore: false,
 2421            delegate_open_excerpts: false,
 2422            enable_lsp_data: true,
 2423            enable_runnables: true,
 2424            show_git_diff_gutter: None,
 2425            show_code_actions: None,
 2426            show_runnables: None,
 2427            show_breakpoints: None,
 2428            show_diff_review_button: false,
 2429            show_wrap_guides: None,
 2430            show_indent_guides,
 2431            buffers_with_disabled_indent_guides: HashSet::default(),
 2432            highlight_order: 0,
 2433            highlighted_rows: HashMap::default(),
 2434            background_highlights: HashMap::default(),
 2435            gutter_highlights: HashMap::default(),
 2436            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2437            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2438            nav_history: None,
 2439            context_menu: RefCell::new(None),
 2440            context_menu_options: None,
 2441            mouse_context_menu: None,
 2442            completion_tasks: Vec::new(),
 2443            inline_blame_popover: None,
 2444            inline_blame_popover_show_task: None,
 2445            signature_help_state: SignatureHelpState::default(),
 2446            auto_signature_help: None,
 2447            find_all_references_task_sources: Vec::new(),
 2448            next_completion_id: 0,
 2449            next_inlay_id: 0,
 2450            code_action_providers,
 2451            available_code_actions: None,
 2452            code_actions_task: None,
 2453            quick_selection_highlight_task: None,
 2454            debounced_selection_highlight_task: None,
 2455            debounced_selection_highlight_complete: false,
 2456            document_highlights_task: None,
 2457            linked_editing_range_task: None,
 2458            pending_rename: None,
 2459            searchable: !is_minimap,
 2460            cursor_shape: EditorSettings::get_global(cx)
 2461                .cursor_shape
 2462                .unwrap_or_default(),
 2463            cursor_offset_on_selection: false,
 2464            current_line_highlight: None,
 2465            autoindent_mode: Some(AutoindentMode::EachLine),
 2466            collapse_matches: false,
 2467            workspace: None,
 2468            input_enabled: !is_minimap,
 2469            expects_character_input: !is_minimap,
 2470            use_modal_editing: full_mode,
 2471            read_only: is_minimap,
 2472            use_autoclose: true,
 2473            use_auto_surround: true,
 2474            use_selection_highlight: true,
 2475            auto_replace_emoji_shortcode: false,
 2476            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2477            leader_id: None,
 2478            remote_id: None,
 2479            hover_state: HoverState::default(),
 2480            pending_mouse_down: None,
 2481            prev_pressure_stage: None,
 2482            hovered_link_state: None,
 2483            edit_prediction_provider: None,
 2484            active_edit_prediction: None,
 2485            stale_edit_prediction_in_menu: None,
 2486            edit_prediction_preview: EditPredictionPreview::Inactive {
 2487                released_too_fast: false,
 2488            },
 2489            inline_diagnostics_enabled: full_mode,
 2490            diagnostics_enabled: full_mode,
 2491            word_completions_enabled: full_mode,
 2492            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2493            gutter_hovered: false,
 2494            pixel_position_of_newest_cursor: None,
 2495            last_bounds: None,
 2496            last_position_map: None,
 2497            expect_bounds_change: None,
 2498            gutter_dimensions: GutterDimensions::default(),
 2499            style: None,
 2500            show_cursor_names: false,
 2501            hovered_cursors: HashMap::default(),
 2502            next_editor_action_id: EditorActionId::default(),
 2503            editor_actions: Rc::default(),
 2504            edit_predictions_hidden_for_vim_mode: false,
 2505            show_edit_predictions_override: None,
 2506            show_completions_on_input_override: None,
 2507            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2508            edit_prediction_settings: EditPredictionSettings::Disabled,
 2509            in_leading_whitespace: false,
 2510            custom_context_menu: None,
 2511            show_git_blame_gutter: false,
 2512            show_git_blame_inline: false,
 2513            show_selection_menu: None,
 2514            show_git_blame_inline_delay_task: None,
 2515            git_blame_inline_enabled: full_mode
 2516                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2517            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2518            buffer_serialization: is_minimap.not().then(|| {
 2519                BufferSerialization::new(
 2520                    ProjectSettings::get_global(cx)
 2521                        .session
 2522                        .restore_unsaved_buffers,
 2523                )
 2524            }),
 2525            blame: None,
 2526            blame_subscription: None,
 2527
 2528            breakpoint_store,
 2529            gutter_breakpoint_indicator: (None, None),
 2530            gutter_diff_review_indicator: (None, None),
 2531            diff_review_drag_state: None,
 2532            diff_review_overlays: Vec::new(),
 2533            stored_review_comments: Vec::new(),
 2534            next_review_comment_id: 0,
 2535            hovered_diff_hunk_row: None,
 2536            _subscriptions: (!is_minimap)
 2537                .then(|| {
 2538                    vec![
 2539                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2540                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2541                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2542                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2543                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2544                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2545                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2546                        cx.observe_window_activation(window, |editor, window, cx| {
 2547                            let active = window.is_window_active();
 2548                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2549                                if active {
 2550                                    blink_manager.enable(cx);
 2551                                } else {
 2552                                    blink_manager.disable(cx);
 2553                                }
 2554                            });
 2555                            if active {
 2556                                editor.show_mouse_cursor(cx);
 2557                            }
 2558                        }),
 2559                    ]
 2560                })
 2561                .unwrap_or_default(),
 2562            runnables: RunnableData::new(),
 2563            pull_diagnostics_task: Task::ready(()),
 2564            colors: None,
 2565            refresh_colors_task: Task::ready(()),
 2566            use_document_folding_ranges: false,
 2567            refresh_folding_ranges_task: Task::ready(()),
 2568            inlay_hints: None,
 2569            next_color_inlay_id: 0,
 2570            post_scroll_update: Task::ready(()),
 2571            linked_edit_ranges: Default::default(),
 2572            in_project_search: false,
 2573            previous_search_ranges: None,
 2574            breadcrumb_header: None,
 2575            focused_block: None,
 2576            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2577            addons: HashMap::default(),
 2578            registered_buffers: HashMap::default(),
 2579            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2580            selection_mark_mode: false,
 2581            toggle_fold_multiple_buffers: Task::ready(()),
 2582            serialize_selections: Task::ready(()),
 2583            serialize_folds: Task::ready(()),
 2584            text_style_refinement: None,
 2585            load_diff_task: load_uncommitted_diff,
 2586            temporary_diff_override: false,
 2587            mouse_cursor_hidden: false,
 2588            minimap: None,
 2589            hide_mouse_mode: EditorSettings::get_global(cx)
 2590                .hide_mouse
 2591                .unwrap_or_default(),
 2592            change_list: ChangeList::new(),
 2593            mode,
 2594            selection_drag_state: SelectionDragState::None,
 2595            folding_newlines: Task::ready(()),
 2596            lookup_key: None,
 2597            select_next_is_case_sensitive: None,
 2598            on_local_selections_changed: None,
 2599            suppress_selection_callback: false,
 2600            applicable_language_settings: HashMap::default(),
 2601            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2602            accent_data: None,
 2603            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2604            number_deleted_lines: false,
 2605            refresh_matching_bracket_highlights_task: Task::ready(()),
 2606            refresh_document_symbols_task: Task::ready(()).shared(),
 2607            lsp_document_symbols: HashMap::default(),
 2608            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2609            outline_symbols_at_cursor: None,
 2610            sticky_headers_task: Task::ready(()),
 2611            sticky_headers: None,
 2612            colorize_brackets_task: Task::ready(()),
 2613        };
 2614
 2615        if is_minimap {
 2616            return editor;
 2617        }
 2618
 2619        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2620        editor.accent_data = editor.fetch_accent_data(cx);
 2621
 2622        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2623            editor
 2624                ._subscriptions
 2625                .push(cx.observe(breakpoints, |_, _, cx| {
 2626                    cx.notify();
 2627                }));
 2628        }
 2629        editor._subscriptions.extend(project_subscriptions);
 2630
 2631        editor._subscriptions.push(cx.subscribe_in(
 2632            &cx.entity(),
 2633            window,
 2634            |editor, _, e: &EditorEvent, window, cx| match e {
 2635                EditorEvent::ScrollPositionChanged { local, .. } => {
 2636                    if *local {
 2637                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2638                        editor.inline_blame_popover.take();
 2639                        let snapshot = editor.snapshot(window, cx);
 2640                        let new_anchor = editor
 2641                            .scroll_manager
 2642                            .native_anchor(&snapshot.display_snapshot, cx);
 2643                        editor.update_restoration_data(cx, move |data| {
 2644                            data.scroll_position = (
 2645                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2646                                new_anchor.offset,
 2647                            );
 2648                        });
 2649
 2650                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2651                            cx.background_executor()
 2652                                .timer(Duration::from_millis(50))
 2653                                .await;
 2654                            editor
 2655                                .update_in(cx, |editor, window, cx| {
 2656                                    editor.update_data_on_scroll(window, cx)
 2657                                })
 2658                                .ok();
 2659                        });
 2660                    }
 2661                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2662                }
 2663                EditorEvent::Edited { .. } => {
 2664                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2665                        .map(|vim_mode| vim_mode.0)
 2666                        .unwrap_or(false);
 2667                    if !vim_mode {
 2668                        let display_map = editor.display_snapshot(cx);
 2669                        let selections = editor.selections.all_adjusted_display(&display_map);
 2670                        let pop_state = editor
 2671                            .change_list
 2672                            .last()
 2673                            .map(|previous| {
 2674                                previous.len() == selections.len()
 2675                                    && previous.iter().enumerate().all(|(ix, p)| {
 2676                                        p.to_display_point(&display_map).row()
 2677                                            == selections[ix].head().row()
 2678                                    })
 2679                            })
 2680                            .unwrap_or(false);
 2681                        let new_positions = selections
 2682                            .into_iter()
 2683                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2684                            .collect();
 2685                        editor
 2686                            .change_list
 2687                            .push_to_change_list(pop_state, new_positions);
 2688                    }
 2689                }
 2690                _ => (),
 2691            },
 2692        ));
 2693
 2694        if let Some(dap_store) = editor
 2695            .project
 2696            .as_ref()
 2697            .map(|project| project.read(cx).dap_store())
 2698        {
 2699            let weak_editor = cx.weak_entity();
 2700
 2701            editor
 2702                ._subscriptions
 2703                .push(
 2704                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2705                        let session_entity = cx.entity();
 2706                        weak_editor
 2707                            .update(cx, |editor, cx| {
 2708                                editor._subscriptions.push(
 2709                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2710                                );
 2711                            })
 2712                            .ok();
 2713                    }),
 2714                );
 2715
 2716            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2717                editor
 2718                    ._subscriptions
 2719                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2720            }
 2721        }
 2722
 2723        // skip adding the initial selection to selection history
 2724        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2725        editor.end_selection(window, cx);
 2726        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2727
 2728        editor.scroll_manager.show_scrollbars(window, cx);
 2729        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2730
 2731        if full_mode {
 2732            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2733            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2734
 2735            if editor.git_blame_inline_enabled {
 2736                editor.start_git_blame_inline(false, window, cx);
 2737            }
 2738
 2739            editor.go_to_active_debug_line(window, cx);
 2740
 2741            editor.minimap =
 2742                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2743            editor.colors = Some(LspColorData::new(cx));
 2744            editor.use_document_folding_ranges = true;
 2745            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2746
 2747            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2748                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2749            }
 2750            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2751        }
 2752
 2753        editor
 2754    }
 2755
 2756    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2757        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2758    }
 2759
 2760    pub fn deploy_mouse_context_menu(
 2761        &mut self,
 2762        position: gpui::Point<Pixels>,
 2763        context_menu: Entity<ContextMenu>,
 2764        window: &mut Window,
 2765        cx: &mut Context<Self>,
 2766    ) {
 2767        self.mouse_context_menu = Some(MouseContextMenu::new(
 2768            self,
 2769            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2770            context_menu,
 2771            window,
 2772            cx,
 2773        ));
 2774    }
 2775
 2776    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2777        self.mouse_context_menu
 2778            .as_ref()
 2779            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2780    }
 2781
 2782    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2783        if self
 2784            .selections
 2785            .pending_anchor()
 2786            .is_some_and(|pending_selection| {
 2787                let snapshot = self.buffer().read(cx).snapshot(cx);
 2788                pending_selection.range().includes(range, &snapshot)
 2789            })
 2790        {
 2791            return true;
 2792        }
 2793
 2794        self.selections
 2795            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2796            .into_iter()
 2797            .any(|selection| {
 2798                // This is needed to cover a corner case, if we just check for an existing
 2799                // selection in the fold range, having a cursor at the start of the fold
 2800                // marks it as selected. Non-empty selections don't cause this.
 2801                let length = selection.end - selection.start;
 2802                length > 0
 2803            })
 2804    }
 2805
 2806    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2807        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2808    }
 2809
 2810    fn key_context_internal(
 2811        &self,
 2812        has_active_edit_prediction: bool,
 2813        window: &mut Window,
 2814        cx: &mut App,
 2815    ) -> KeyContext {
 2816        let mut key_context = KeyContext::new_with_defaults();
 2817        key_context.add("Editor");
 2818        let mode = match self.mode {
 2819            EditorMode::SingleLine => "single_line",
 2820            EditorMode::AutoHeight { .. } => "auto_height",
 2821            EditorMode::Minimap { .. } => "minimap",
 2822            EditorMode::Full { .. } => "full",
 2823        };
 2824
 2825        if EditorSettings::jupyter_enabled(cx) {
 2826            key_context.add("jupyter");
 2827        }
 2828
 2829        key_context.set("mode", mode);
 2830        if self.pending_rename.is_some() {
 2831            key_context.add("renaming");
 2832        }
 2833
 2834        if let Some(snippet_stack) = self.snippet_stack.last() {
 2835            key_context.add("in_snippet");
 2836
 2837            if snippet_stack.active_index > 0 {
 2838                key_context.add("has_previous_tabstop");
 2839            }
 2840
 2841            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2842                key_context.add("has_next_tabstop");
 2843            }
 2844        }
 2845
 2846        match self.context_menu.borrow().as_ref() {
 2847            Some(CodeContextMenu::Completions(menu)) => {
 2848                if menu.visible() {
 2849                    key_context.add("menu");
 2850                    key_context.add("showing_completions");
 2851                }
 2852            }
 2853            Some(CodeContextMenu::CodeActions(menu)) => {
 2854                if menu.visible() {
 2855                    key_context.add("menu");
 2856                    key_context.add("showing_code_actions")
 2857                }
 2858            }
 2859            None => {}
 2860        }
 2861
 2862        if self.signature_help_state.has_multiple_signatures() {
 2863            key_context.add("showing_signature_help");
 2864        }
 2865
 2866        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2867        if !self.focus_handle(cx).contains_focused(window, cx)
 2868            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2869        {
 2870            for addon in self.addons.values() {
 2871                addon.extend_key_context(&mut key_context, cx)
 2872            }
 2873        }
 2874
 2875        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2876            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2877                Some(
 2878                    file.full_path(cx)
 2879                        .extension()?
 2880                        .to_string_lossy()
 2881                        .to_lowercase(),
 2882                )
 2883            }) {
 2884                key_context.set("extension", extension);
 2885            }
 2886        } else {
 2887            key_context.add("multibuffer");
 2888        }
 2889
 2890        if has_active_edit_prediction {
 2891            key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2892            key_context.add("copilot_suggestion");
 2893        }
 2894
 2895        if self.in_leading_whitespace {
 2896            key_context.add("in_leading_whitespace");
 2897        }
 2898        if self.edit_prediction_requires_modifier() {
 2899            key_context.set("edit_prediction_mode", "subtle")
 2900        } else {
 2901            key_context.set("edit_prediction_mode", "eager");
 2902        }
 2903
 2904        if self.selection_mark_mode {
 2905            key_context.add("selection_mode");
 2906        }
 2907
 2908        let disjoint = self.selections.disjoint_anchors();
 2909        if matches!(
 2910            &self.mode,
 2911            EditorMode::SingleLine | EditorMode::AutoHeight { .. }
 2912        ) && let [selection] = disjoint
 2913            && selection.start == selection.end
 2914        {
 2915            let snapshot = self.snapshot(window, cx);
 2916            let snapshot = snapshot.buffer_snapshot();
 2917            let caret_offset = selection.end.to_offset(snapshot);
 2918
 2919            if caret_offset == MultiBufferOffset(0) {
 2920                key_context.add("start_of_input");
 2921            }
 2922
 2923            if caret_offset == snapshot.len() {
 2924                key_context.add("end_of_input");
 2925            }
 2926        }
 2927
 2928        if self.has_any_expanded_diff_hunks(cx) {
 2929            key_context.add("diffs_expanded");
 2930        }
 2931
 2932        key_context
 2933    }
 2934
 2935    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2936        self.last_bounds.as_ref()
 2937    }
 2938
 2939    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2940        if self.mouse_cursor_hidden {
 2941            self.mouse_cursor_hidden = false;
 2942            cx.notify();
 2943        }
 2944    }
 2945
 2946    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2947        let hide_mouse_cursor = match origin {
 2948            HideMouseCursorOrigin::TypingAction => {
 2949                matches!(
 2950                    self.hide_mouse_mode,
 2951                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2952                )
 2953            }
 2954            HideMouseCursorOrigin::MovementAction => {
 2955                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2956            }
 2957        };
 2958        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2959            self.mouse_cursor_hidden = hide_mouse_cursor;
 2960            cx.notify();
 2961        }
 2962    }
 2963
 2964    fn accept_edit_prediction_keystroke(
 2965        &self,
 2966        granularity: EditPredictionGranularity,
 2967        window: &mut Window,
 2968        cx: &mut App,
 2969    ) -> Option<gpui::KeybindingKeystroke> {
 2970        let key_context = self.key_context_internal(true, window, cx);
 2971
 2972        let bindings =
 2973            match granularity {
 2974                EditPredictionGranularity::Word => window
 2975                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2976                EditPredictionGranularity::Line => window
 2977                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2978                EditPredictionGranularity::Full => {
 2979                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2980                }
 2981            };
 2982
 2983        bindings
 2984            .into_iter()
 2985            .rev()
 2986            .find_map(|binding| match binding.keystrokes() {
 2987                [keystroke, ..] => Some(keystroke.clone()),
 2988                _ => None,
 2989            })
 2990    }
 2991
 2992    fn preview_edit_prediction_keystroke(
 2993        &self,
 2994        window: &mut Window,
 2995        cx: &mut App,
 2996    ) -> Option<gpui::KeybindingKeystroke> {
 2997        let key_context = self.key_context_internal(true, window, cx);
 2998        let bindings = window.bindings_for_action_in_context(&AcceptEditPrediction, key_context);
 2999        bindings
 3000            .into_iter()
 3001            .rev()
 3002            .find_map(|binding| match binding.keystrokes() {
 3003                [keystroke, ..] if keystroke.modifiers().modified() => Some(keystroke.clone()),
 3004                _ => None,
 3005            })
 3006    }
 3007
 3008    fn edit_prediction_preview_modifiers_held(
 3009        &self,
 3010        modifiers: &Modifiers,
 3011        window: &mut Window,
 3012        cx: &mut App,
 3013    ) -> bool {
 3014        let key_context = self.key_context_internal(true, window, cx);
 3015        let actions: [&dyn Action; 3] = [
 3016            &AcceptEditPrediction,
 3017            &AcceptNextWordEditPrediction,
 3018            &AcceptNextLineEditPrediction,
 3019        ];
 3020
 3021        actions.into_iter().any(|action| {
 3022            window
 3023                .bindings_for_action_in_context(action, key_context.clone())
 3024                .into_iter()
 3025                .rev()
 3026                .any(|binding| {
 3027                    binding.keystrokes().first().is_some_and(|keystroke| {
 3028                        keystroke.modifiers().modified() && keystroke.modifiers() == modifiers
 3029                    })
 3030                })
 3031        })
 3032    }
 3033
 3034    fn edit_prediction_cursor_popover_prefers_preview(
 3035        &self,
 3036        completion: &EditPredictionState,
 3037        cx: &App,
 3038    ) -> bool {
 3039        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 3040
 3041        match &completion.completion {
 3042            EditPrediction::Edit {
 3043                edits, snapshot, ..
 3044            } => {
 3045                let mut start_row: Option<u32> = None;
 3046                let mut end_row: Option<u32> = None;
 3047
 3048                for (range, text) in edits {
 3049                    let Some((_, range)) =
 3050                        multibuffer_snapshot.anchor_range_to_buffer_anchor_range(range.clone())
 3051                    else {
 3052                        continue;
 3053                    };
 3054                    let edit_start_row = range.start.to_point(snapshot).row;
 3055                    let old_end_row = range.end.to_point(snapshot).row;
 3056                    let inserted_newline_count = text
 3057                        .as_ref()
 3058                        .chars()
 3059                        .filter(|character| *character == '\n')
 3060                        .count() as u32;
 3061                    let deleted_newline_count = old_end_row - edit_start_row;
 3062                    let preview_end_row = edit_start_row + inserted_newline_count;
 3063
 3064                    start_row =
 3065                        Some(start_row.map_or(edit_start_row, |row| row.min(edit_start_row)));
 3066                    end_row = Some(end_row.map_or(preview_end_row, |row| row.max(preview_end_row)));
 3067
 3068                    if deleted_newline_count > 1 {
 3069                        end_row = Some(end_row.map_or(old_end_row, |row| row.max(old_end_row)));
 3070                    }
 3071                }
 3072
 3073                start_row
 3074                    .zip(end_row)
 3075                    .is_some_and(|(start_row, end_row)| end_row > start_row)
 3076            }
 3077            EditPrediction::MoveWithin { .. } | EditPrediction::MoveOutside { .. } => false,
 3078        }
 3079    }
 3080
 3081    fn edit_prediction_keybind_display(
 3082        &self,
 3083        surface: EditPredictionKeybindSurface,
 3084        window: &mut Window,
 3085        cx: &mut App,
 3086    ) -> EditPredictionKeybindDisplay {
 3087        let accept_keystroke =
 3088            self.accept_edit_prediction_keystroke(EditPredictionGranularity::Full, window, cx);
 3089        let preview_keystroke = self.preview_edit_prediction_keystroke(window, cx);
 3090
 3091        let action = match surface {
 3092            EditPredictionKeybindSurface::Inline
 3093            | EditPredictionKeybindSurface::CursorPopoverCompact => {
 3094                if self.edit_prediction_requires_modifier() {
 3095                    EditPredictionKeybindAction::Preview
 3096                } else {
 3097                    EditPredictionKeybindAction::Accept
 3098                }
 3099            }
 3100            EditPredictionKeybindSurface::CursorPopoverExpanded => self
 3101                .active_edit_prediction
 3102                .as_ref()
 3103                .filter(|completion| {
 3104                    self.edit_prediction_cursor_popover_prefers_preview(completion, cx)
 3105                })
 3106                .map_or(EditPredictionKeybindAction::Accept, |_| {
 3107                    EditPredictionKeybindAction::Preview
 3108                }),
 3109        };
 3110        #[cfg(test)]
 3111        let preview_copy = preview_keystroke.clone();
 3112        #[cfg(test)]
 3113        let accept_copy = accept_keystroke.clone();
 3114
 3115        let displayed_keystroke = match surface {
 3116            EditPredictionKeybindSurface::Inline => match action {
 3117                EditPredictionKeybindAction::Accept => accept_keystroke,
 3118                EditPredictionKeybindAction::Preview => preview_keystroke,
 3119            },
 3120            EditPredictionKeybindSurface::CursorPopoverCompact
 3121            | EditPredictionKeybindSurface::CursorPopoverExpanded => match action {
 3122                EditPredictionKeybindAction::Accept => accept_keystroke,
 3123                EditPredictionKeybindAction::Preview => {
 3124                    preview_keystroke.or_else(|| accept_keystroke.clone())
 3125                }
 3126            },
 3127        };
 3128
 3129        let missing_accept_keystroke = displayed_keystroke.is_none();
 3130
 3131        EditPredictionKeybindDisplay {
 3132            #[cfg(test)]
 3133            accept_keystroke: accept_copy,
 3134            #[cfg(test)]
 3135            preview_keystroke: preview_copy,
 3136            displayed_keystroke,
 3137            action,
 3138            missing_accept_keystroke,
 3139            show_hold_label: matches!(surface, EditPredictionKeybindSurface::CursorPopoverCompact)
 3140                && self.edit_prediction_preview.released_too_fast(),
 3141        }
 3142    }
 3143
 3144    pub fn new_file(
 3145        workspace: &mut Workspace,
 3146        _: &workspace::NewFile,
 3147        window: &mut Window,
 3148        cx: &mut Context<Workspace>,
 3149    ) {
 3150        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 3151            "Failed to create buffer",
 3152            window,
 3153            cx,
 3154            |e, _, _| match e.error_code() {
 3155                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3156                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3157                e.error_tag("required").unwrap_or("the latest version")
 3158            )),
 3159                _ => None,
 3160            },
 3161        );
 3162    }
 3163
 3164    pub fn new_in_workspace(
 3165        workspace: &mut Workspace,
 3166        window: &mut Window,
 3167        cx: &mut Context<Workspace>,
 3168    ) -> Task<Result<Entity<Editor>>> {
 3169        let project = workspace.project().clone();
 3170        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3171
 3172        cx.spawn_in(window, async move |workspace, cx| {
 3173            let buffer = create.await?;
 3174            workspace.update_in(cx, |workspace, window, cx| {
 3175                let editor =
 3176                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 3177                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 3178                editor
 3179            })
 3180        })
 3181    }
 3182
 3183    fn new_file_vertical(
 3184        workspace: &mut Workspace,
 3185        _: &workspace::NewFileSplitVertical,
 3186        window: &mut Window,
 3187        cx: &mut Context<Workspace>,
 3188    ) {
 3189        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3190    }
 3191
 3192    fn new_file_horizontal(
 3193        workspace: &mut Workspace,
 3194        _: &workspace::NewFileSplitHorizontal,
 3195        window: &mut Window,
 3196        cx: &mut Context<Workspace>,
 3197    ) {
 3198        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3199    }
 3200
 3201    fn new_file_split(
 3202        workspace: &mut Workspace,
 3203        action: &workspace::NewFileSplit,
 3204        window: &mut Window,
 3205        cx: &mut Context<Workspace>,
 3206    ) {
 3207        Self::new_file_in_direction(workspace, action.0, window, cx)
 3208    }
 3209
 3210    fn new_file_in_direction(
 3211        workspace: &mut Workspace,
 3212        direction: SplitDirection,
 3213        window: &mut Window,
 3214        cx: &mut Context<Workspace>,
 3215    ) {
 3216        let project = workspace.project().clone();
 3217        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3218
 3219        cx.spawn_in(window, async move |workspace, cx| {
 3220            let buffer = create.await?;
 3221            workspace.update_in(cx, move |workspace, window, cx| {
 3222                workspace.split_item(
 3223                    direction,
 3224                    Box::new(
 3225                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3226                    ),
 3227                    window,
 3228                    cx,
 3229                )
 3230            })?;
 3231            anyhow::Ok(())
 3232        })
 3233        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3234            match e.error_code() {
 3235                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3236                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3237                e.error_tag("required").unwrap_or("the latest version")
 3238            )),
 3239                _ => None,
 3240            }
 3241        });
 3242    }
 3243
 3244    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3245        self.leader_id
 3246    }
 3247
 3248    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3249        &self.buffer
 3250    }
 3251
 3252    pub fn project(&self) -> Option<&Entity<Project>> {
 3253        self.project.as_ref()
 3254    }
 3255
 3256    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3257        self.workspace.as_ref()?.0.upgrade()
 3258    }
 3259
 3260    /// Detaches a task and shows an error notification in the workspace if available,
 3261    /// otherwise just logs the error.
 3262    pub fn detach_and_notify_err<R, E>(
 3263        &self,
 3264        task: Task<Result<R, E>>,
 3265        window: &mut Window,
 3266        cx: &mut App,
 3267    ) where
 3268        E: std::fmt::Debug + std::fmt::Display + 'static,
 3269        R: 'static,
 3270    {
 3271        if let Some(workspace) = self.workspace() {
 3272            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3273        } else {
 3274            task.detach_and_log_err(cx);
 3275        }
 3276    }
 3277
 3278    /// Returns the workspace serialization ID if this editor should be serialized.
 3279    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3280        self.workspace
 3281            .as_ref()
 3282            .filter(|_| self.should_serialize_buffer())
 3283            .and_then(|workspace| workspace.1)
 3284    }
 3285
 3286    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3287        self.buffer().read(cx).title(cx)
 3288    }
 3289
 3290    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3291        let git_blame_gutter_max_author_length = self
 3292            .render_git_blame_gutter(cx)
 3293            .then(|| {
 3294                if let Some(blame) = self.blame.as_ref() {
 3295                    let max_author_length =
 3296                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3297                    Some(max_author_length)
 3298                } else {
 3299                    None
 3300                }
 3301            })
 3302            .flatten();
 3303
 3304        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3305
 3306        EditorSnapshot {
 3307            mode: self.mode.clone(),
 3308            show_gutter: self.show_gutter,
 3309            offset_content: self.offset_content,
 3310            show_line_numbers: self.show_line_numbers,
 3311            number_deleted_lines: self.number_deleted_lines,
 3312            show_git_diff_gutter: self.show_git_diff_gutter,
 3313            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3314            show_code_actions: self.show_code_actions,
 3315            show_runnables: self.show_runnables,
 3316            show_breakpoints: self.show_breakpoints,
 3317            git_blame_gutter_max_author_length,
 3318            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3319            display_snapshot,
 3320            placeholder_display_snapshot: self
 3321                .placeholder_display_map
 3322                .as_ref()
 3323                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3324            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3325            is_focused: self.focus_handle.is_focused(window),
 3326            current_line_highlight: self
 3327                .current_line_highlight
 3328                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3329            gutter_hovered: self.gutter_hovered,
 3330        }
 3331    }
 3332
 3333    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3334        self.buffer.read(cx).language_at(point, cx)
 3335    }
 3336
 3337    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3338        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3339    }
 3340
 3341    pub fn active_buffer(&self, cx: &App) -> Option<Entity<Buffer>> {
 3342        let multibuffer = self.buffer.read(cx);
 3343        let snapshot = multibuffer.snapshot(cx);
 3344        let (anchor, _) =
 3345            snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())?;
 3346        multibuffer.buffer(anchor.buffer_id)
 3347    }
 3348
 3349    pub fn mode(&self) -> &EditorMode {
 3350        &self.mode
 3351    }
 3352
 3353    pub fn set_mode(&mut self, mode: EditorMode) {
 3354        self.mode = mode;
 3355    }
 3356
 3357    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3358        self.collaboration_hub.as_deref()
 3359    }
 3360
 3361    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3362        self.collaboration_hub = Some(hub);
 3363    }
 3364
 3365    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3366        self.in_project_search = in_project_search;
 3367    }
 3368
 3369    pub fn set_custom_context_menu(
 3370        &mut self,
 3371        f: impl 'static
 3372        + Fn(
 3373            &mut Self,
 3374            DisplayPoint,
 3375            &mut Window,
 3376            &mut Context<Self>,
 3377        ) -> Option<Entity<ui::ContextMenu>>,
 3378    ) {
 3379        self.custom_context_menu = Some(Box::new(f))
 3380    }
 3381
 3382    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3383        self.completion_provider = provider;
 3384    }
 3385
 3386    #[cfg(any(test, feature = "test-support"))]
 3387    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3388        self.completion_provider.clone()
 3389    }
 3390
 3391    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3392        self.semantics_provider.clone()
 3393    }
 3394
 3395    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3396        self.semantics_provider = provider;
 3397    }
 3398
 3399    pub fn set_edit_prediction_provider<T>(
 3400        &mut self,
 3401        provider: Option<Entity<T>>,
 3402        window: &mut Window,
 3403        cx: &mut Context<Self>,
 3404    ) where
 3405        T: EditPredictionDelegate,
 3406    {
 3407        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3408            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3409                if this.focus_handle.is_focused(window) {
 3410                    this.update_visible_edit_prediction(window, cx);
 3411                }
 3412            }),
 3413            provider: Arc::new(provider),
 3414        });
 3415        self.update_edit_prediction_settings(cx);
 3416        self.refresh_edit_prediction(false, false, window, cx);
 3417    }
 3418
 3419    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3420        self.placeholder_display_map
 3421            .as_ref()
 3422            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3423    }
 3424
 3425    pub fn set_placeholder_text(
 3426        &mut self,
 3427        placeholder_text: &str,
 3428        window: &mut Window,
 3429        cx: &mut Context<Self>,
 3430    ) {
 3431        let multibuffer = cx
 3432            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3433
 3434        let style = window.text_style();
 3435
 3436        self.placeholder_display_map = Some(cx.new(|cx| {
 3437            DisplayMap::new(
 3438                multibuffer,
 3439                style.font(),
 3440                style.font_size.to_pixels(window.rem_size()),
 3441                None,
 3442                FILE_HEADER_HEIGHT,
 3443                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3444                Default::default(),
 3445                DiagnosticSeverity::Off,
 3446                cx,
 3447            )
 3448        }));
 3449        cx.notify();
 3450    }
 3451
 3452    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3453        self.cursor_shape = cursor_shape;
 3454
 3455        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3456        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3457
 3458        cx.notify();
 3459    }
 3460
 3461    pub fn cursor_shape(&self) -> CursorShape {
 3462        self.cursor_shape
 3463    }
 3464
 3465    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3466        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3467    }
 3468
 3469    pub fn set_current_line_highlight(
 3470        &mut self,
 3471        current_line_highlight: Option<CurrentLineHighlight>,
 3472    ) {
 3473        self.current_line_highlight = current_line_highlight;
 3474    }
 3475
 3476    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3477        self.collapse_matches = collapse_matches;
 3478    }
 3479
 3480    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3481        if self.collapse_matches {
 3482            return range.start..range.start;
 3483        }
 3484        range.clone()
 3485    }
 3486
 3487    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3488        self.display_map.read(cx).clip_at_line_ends
 3489    }
 3490
 3491    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3492        if self.display_map.read(cx).clip_at_line_ends != clip {
 3493            self.display_map
 3494                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3495        }
 3496    }
 3497
 3498    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3499        self.input_enabled = input_enabled;
 3500    }
 3501
 3502    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3503        self.expects_character_input = expects_character_input;
 3504    }
 3505
 3506    pub fn set_edit_predictions_hidden_for_vim_mode(
 3507        &mut self,
 3508        hidden: bool,
 3509        window: &mut Window,
 3510        cx: &mut Context<Self>,
 3511    ) {
 3512        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3513            self.edit_predictions_hidden_for_vim_mode = hidden;
 3514            if hidden {
 3515                self.update_visible_edit_prediction(window, cx);
 3516            } else {
 3517                self.refresh_edit_prediction(true, false, window, cx);
 3518            }
 3519        }
 3520    }
 3521
 3522    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3523        self.menu_edit_predictions_policy = value;
 3524    }
 3525
 3526    pub fn set_autoindent(&mut self, autoindent: bool) {
 3527        if autoindent {
 3528            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3529        } else {
 3530            self.autoindent_mode = None;
 3531        }
 3532    }
 3533
 3534    pub fn capability(&self, cx: &App) -> Capability {
 3535        if self.read_only {
 3536            Capability::ReadOnly
 3537        } else {
 3538            self.buffer.read(cx).capability()
 3539        }
 3540    }
 3541
 3542    pub fn read_only(&self, cx: &App) -> bool {
 3543        self.read_only || self.buffer.read(cx).read_only()
 3544    }
 3545
 3546    pub fn set_read_only(&mut self, read_only: bool) {
 3547        self.read_only = read_only;
 3548    }
 3549
 3550    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3551        self.use_autoclose = autoclose;
 3552    }
 3553
 3554    pub fn set_use_selection_highlight(&mut self, highlight: bool) {
 3555        self.use_selection_highlight = highlight;
 3556    }
 3557
 3558    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3559        self.use_auto_surround = auto_surround;
 3560    }
 3561
 3562    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3563        self.auto_replace_emoji_shortcode = auto_replace;
 3564    }
 3565
 3566    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3567        self.buffer_serialization = should_serialize.then(|| {
 3568            BufferSerialization::new(
 3569                ProjectSettings::get_global(cx)
 3570                    .session
 3571                    .restore_unsaved_buffers,
 3572            )
 3573        })
 3574    }
 3575
 3576    fn should_serialize_buffer(&self) -> bool {
 3577        self.buffer_serialization.is_some()
 3578    }
 3579
 3580    pub fn toggle_edit_predictions(
 3581        &mut self,
 3582        _: &ToggleEditPrediction,
 3583        window: &mut Window,
 3584        cx: &mut Context<Self>,
 3585    ) {
 3586        if self.show_edit_predictions_override.is_some() {
 3587            self.set_show_edit_predictions(None, window, cx);
 3588        } else {
 3589            let show_edit_predictions = !self.edit_predictions_enabled();
 3590            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3591        }
 3592    }
 3593
 3594    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3595        self.show_completions_on_input_override = show_completions_on_input;
 3596    }
 3597
 3598    pub fn set_show_edit_predictions(
 3599        &mut self,
 3600        show_edit_predictions: Option<bool>,
 3601        window: &mut Window,
 3602        cx: &mut Context<Self>,
 3603    ) {
 3604        self.show_edit_predictions_override = show_edit_predictions;
 3605        self.update_edit_prediction_settings(cx);
 3606
 3607        if let Some(false) = show_edit_predictions {
 3608            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3609        } else {
 3610            self.refresh_edit_prediction(false, true, window, cx);
 3611        }
 3612    }
 3613
 3614    fn edit_predictions_disabled_in_scope(
 3615        &self,
 3616        buffer: &Entity<Buffer>,
 3617        buffer_position: language::Anchor,
 3618        cx: &App,
 3619    ) -> bool {
 3620        let snapshot = buffer.read(cx).snapshot();
 3621        let settings = snapshot.settings_at(buffer_position, cx);
 3622
 3623        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3624            return false;
 3625        };
 3626
 3627        scope.override_name().is_some_and(|scope_name| {
 3628            settings
 3629                .edit_predictions_disabled_in
 3630                .iter()
 3631                .any(|s| s == scope_name)
 3632        })
 3633    }
 3634
 3635    pub fn set_use_modal_editing(&mut self, to: bool) {
 3636        self.use_modal_editing = to;
 3637    }
 3638
 3639    pub fn use_modal_editing(&self) -> bool {
 3640        self.use_modal_editing
 3641    }
 3642
 3643    fn selections_did_change(
 3644        &mut self,
 3645        local: bool,
 3646        old_cursor_position: &Anchor,
 3647        effects: SelectionEffects,
 3648        window: &mut Window,
 3649        cx: &mut Context<Self>,
 3650    ) {
 3651        window.invalidate_character_coordinates();
 3652
 3653        // Copy selections to primary selection buffer
 3654        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3655        if local {
 3656            let selections = self
 3657                .selections
 3658                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3659            let buffer_handle = self.buffer.read(cx).read(cx);
 3660
 3661            let mut text = String::new();
 3662            for (index, selection) in selections.iter().enumerate() {
 3663                let text_for_selection = buffer_handle
 3664                    .text_for_range(selection.start..selection.end)
 3665                    .collect::<String>();
 3666
 3667                text.push_str(&text_for_selection);
 3668                if index != selections.len() - 1 {
 3669                    text.push('\n');
 3670                }
 3671            }
 3672
 3673            if !text.is_empty() {
 3674                cx.write_to_primary(ClipboardItem::new_string(text));
 3675            }
 3676        }
 3677
 3678        let selection_anchors = self.selections.disjoint_anchors_arc();
 3679
 3680        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3681            self.buffer.update(cx, |buffer, cx| {
 3682                buffer.set_active_selections(
 3683                    &selection_anchors,
 3684                    self.selections.line_mode(),
 3685                    self.cursor_shape,
 3686                    cx,
 3687                )
 3688            });
 3689        }
 3690        let display_map = self
 3691            .display_map
 3692            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3693        let buffer = display_map.buffer_snapshot();
 3694        if self.selections.count() == 1 {
 3695            self.add_selections_state = None;
 3696        }
 3697        self.select_next_state = None;
 3698        self.select_prev_state = None;
 3699        self.select_syntax_node_history.try_clear();
 3700        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3701        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3702        self.take_rename(false, window, cx);
 3703
 3704        let newest_selection = self.selections.newest_anchor();
 3705        let new_cursor_position = newest_selection.head();
 3706        let selection_start = newest_selection.start;
 3707
 3708        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3709            self.push_to_nav_history(
 3710                *old_cursor_position,
 3711                Some(new_cursor_position.to_point(buffer)),
 3712                false,
 3713                effects.nav_history == Some(true),
 3714                cx,
 3715            );
 3716        }
 3717
 3718        if local {
 3719            if let Some((anchor, _)) = buffer.anchor_to_buffer_anchor(new_cursor_position) {
 3720                self.register_buffer(anchor.buffer_id, cx);
 3721            }
 3722
 3723            let mut context_menu = self.context_menu.borrow_mut();
 3724            let completion_menu = match context_menu.as_ref() {
 3725                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3726                Some(CodeContextMenu::CodeActions(_)) => {
 3727                    *context_menu = None;
 3728                    None
 3729                }
 3730                None => None,
 3731            };
 3732            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3733            drop(context_menu);
 3734
 3735            if effects.completions
 3736                && let Some(completion_position) = completion_position
 3737            {
 3738                let start_offset = selection_start.to_offset(buffer);
 3739                let position_matches = start_offset == completion_position.to_offset(buffer);
 3740                let continue_showing = if let Some((snap, ..)) =
 3741                    buffer.point_to_buffer_offset(completion_position)
 3742                    && !snap.capability.editable()
 3743                {
 3744                    false
 3745                } else if position_matches {
 3746                    if self.snippet_stack.is_empty() {
 3747                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3748                            == Some(CharKind::Word)
 3749                    } else {
 3750                        // Snippet choices can be shown even when the cursor is in whitespace.
 3751                        // Dismissing the menu with actions like backspace is handled by
 3752                        // invalidation regions.
 3753                        true
 3754                    }
 3755                } else {
 3756                    false
 3757                };
 3758
 3759                if continue_showing {
 3760                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3761                } else {
 3762                    self.hide_context_menu(window, cx);
 3763                }
 3764            }
 3765
 3766            hide_hover(self, cx);
 3767
 3768            if old_cursor_position.to_display_point(&display_map).row()
 3769                != new_cursor_position.to_display_point(&display_map).row()
 3770            {
 3771                self.available_code_actions.take();
 3772            }
 3773            self.refresh_code_actions(window, cx);
 3774            self.refresh_document_highlights(cx);
 3775            refresh_linked_ranges(self, window, cx);
 3776
 3777            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3778            self.refresh_matching_bracket_highlights(&display_map, cx);
 3779            self.refresh_outline_symbols_at_cursor(cx);
 3780            self.update_visible_edit_prediction(window, cx);
 3781            self.inline_blame_popover.take();
 3782            if self.git_blame_inline_enabled {
 3783                self.start_inline_blame_timer(window, cx);
 3784            }
 3785        }
 3786
 3787        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3788
 3789        if local && !self.suppress_selection_callback {
 3790            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3791                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3792                callback(cursor_position, window, cx);
 3793            }
 3794        }
 3795
 3796        cx.emit(EditorEvent::SelectionsChanged { local });
 3797
 3798        let selections = &self.selections.disjoint_anchors_arc();
 3799        if selections.len() == 1 {
 3800            cx.emit(SearchEvent::ActiveMatchChanged)
 3801        }
 3802        if local && let Some(buffer_snapshot) = buffer.as_singleton() {
 3803            let inmemory_selections = selections
 3804                .iter()
 3805                .map(|s| {
 3806                    let start = s.range().start.text_anchor_in(buffer_snapshot);
 3807                    let end = s.range().end.text_anchor_in(buffer_snapshot);
 3808                    (start..end).to_point(buffer_snapshot)
 3809                })
 3810                .collect();
 3811            self.update_restoration_data(cx, |data| {
 3812                data.selections = inmemory_selections;
 3813            });
 3814
 3815            if WorkspaceSettings::get(None, cx).restore_on_startup
 3816                != RestoreOnStartupBehavior::EmptyTab
 3817                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3818            {
 3819                let snapshot = self.buffer().read(cx).snapshot(cx);
 3820                let selections = selections.clone();
 3821                let background_executor = cx.background_executor().clone();
 3822                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3823                let db = EditorDb::global(cx);
 3824                self.serialize_selections = cx.background_spawn(async move {
 3825                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3826                    let db_selections = selections
 3827                        .iter()
 3828                        .map(|selection| {
 3829                            (
 3830                                selection.start.to_offset(&snapshot).0,
 3831                                selection.end.to_offset(&snapshot).0,
 3832                            )
 3833                        })
 3834                        .collect();
 3835
 3836                    db.save_editor_selections(editor_id, workspace_id, db_selections)
 3837                        .await
 3838                        .with_context(|| {
 3839                            format!(
 3840                                "persisting editor selections for editor {editor_id}, \
 3841                                workspace {workspace_id:?}"
 3842                            )
 3843                        })
 3844                        .log_err();
 3845                });
 3846            }
 3847        }
 3848
 3849        cx.notify();
 3850    }
 3851
 3852    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3853        use text::ToOffset as _;
 3854
 3855        if self.mode.is_minimap()
 3856            || WorkspaceSettings::get(None, cx).restore_on_startup
 3857                == RestoreOnStartupBehavior::EmptyTab
 3858        {
 3859            return;
 3860        }
 3861
 3862        let display_snapshot = self
 3863            .display_map
 3864            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3865        let Some(buffer_snapshot) = display_snapshot.buffer_snapshot().as_singleton() else {
 3866            return;
 3867        };
 3868        let inmemory_folds = display_snapshot
 3869            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3870            .map(|fold| {
 3871                let start = fold.range.start.text_anchor_in(buffer_snapshot);
 3872                let end = fold.range.end.text_anchor_in(buffer_snapshot);
 3873                (start..end).to_point(buffer_snapshot)
 3874            })
 3875            .collect();
 3876        self.update_restoration_data(cx, |data| {
 3877            data.folds = inmemory_folds;
 3878        });
 3879
 3880        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3881            return;
 3882        };
 3883
 3884        // Get file path for path-based fold storage (survives tab close)
 3885        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3886            project::File::from_dyn(buffer.read(cx).file())
 3887                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3888        }) else {
 3889            return;
 3890        };
 3891
 3892        let background_executor = cx.background_executor().clone();
 3893        const FINGERPRINT_LEN: usize = 32;
 3894        let db_folds = display_snapshot
 3895            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3896            .map(|fold| {
 3897                let start = fold
 3898                    .range
 3899                    .start
 3900                    .text_anchor_in(buffer_snapshot)
 3901                    .to_offset(buffer_snapshot);
 3902                let end = fold
 3903                    .range
 3904                    .end
 3905                    .text_anchor_in(buffer_snapshot)
 3906                    .to_offset(buffer_snapshot);
 3907
 3908                // Extract fingerprints - content at fold boundaries for validation on restore
 3909                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3910                // content that might change independently.
 3911                // start_fp: first min(32, fold_len) bytes of fold content
 3912                // end_fp: last min(32, fold_len) bytes of fold content
 3913                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3914                let fold_len = end - start;
 3915                let start_fp_end = buffer_snapshot
 3916                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3917                let start_fp: String = buffer_snapshot
 3918                    .text_for_range(start..start_fp_end)
 3919                    .collect();
 3920                let end_fp_start = buffer_snapshot
 3921                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3922                let end_fp: String = buffer_snapshot.text_for_range(end_fp_start..end).collect();
 3923
 3924                (start, end, start_fp, end_fp)
 3925            })
 3926            .collect::<Vec<_>>();
 3927        let db = EditorDb::global(cx);
 3928        self.serialize_folds = cx.background_spawn(async move {
 3929            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3930            if db_folds.is_empty() {
 3931                // No folds - delete any persisted folds for this file
 3932                db.delete_file_folds(workspace_id, file_path)
 3933                    .await
 3934                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3935                    .log_err();
 3936            } else {
 3937                db.save_file_folds(workspace_id, file_path, db_folds)
 3938                    .await
 3939                    .with_context(|| {
 3940                        format!("persisting file folds for workspace {workspace_id:?}")
 3941                    })
 3942                    .log_err();
 3943            }
 3944        });
 3945    }
 3946
 3947    pub fn sync_selections(
 3948        &mut self,
 3949        other: Entity<Editor>,
 3950        cx: &mut Context<Self>,
 3951    ) -> gpui::Subscription {
 3952        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3953        if !other_selections.is_empty() {
 3954            self.selections
 3955                .change_with(&self.display_snapshot(cx), |selections| {
 3956                    selections.select_anchors(other_selections);
 3957                });
 3958        }
 3959
 3960        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3961            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3962                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3963                if other_selections.is_empty() {
 3964                    return;
 3965                }
 3966                let snapshot = this.display_snapshot(cx);
 3967                this.selections.change_with(&snapshot, |selections| {
 3968                    selections.select_anchors(other_selections);
 3969                });
 3970            }
 3971        });
 3972
 3973        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3974            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3975                let these_selections = this.selections.disjoint_anchors().to_vec();
 3976                if these_selections.is_empty() {
 3977                    return;
 3978                }
 3979                other.update(cx, |other_editor, cx| {
 3980                    let snapshot = other_editor.display_snapshot(cx);
 3981                    other_editor
 3982                        .selections
 3983                        .change_with(&snapshot, |selections| {
 3984                            selections.select_anchors(these_selections);
 3985                        })
 3986                });
 3987            }
 3988        });
 3989
 3990        Subscription::join(other_subscription, this_subscription)
 3991    }
 3992
 3993    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3994        if self.buffer().read(cx).is_singleton() {
 3995            return;
 3996        }
 3997        let snapshot = self.buffer.read(cx).snapshot(cx);
 3998        let buffer_ids: HashSet<BufferId> = self
 3999            .selections
 4000            .disjoint_anchor_ranges()
 4001            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 4002            .collect();
 4003        for buffer_id in buffer_ids {
 4004            self.unfold_buffer(buffer_id, cx);
 4005        }
 4006    }
 4007
 4008    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 4009    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 4010    /// effects of selection change occur at the end of the transaction.
 4011    pub fn change_selections<R>(
 4012        &mut self,
 4013        effects: SelectionEffects,
 4014        window: &mut Window,
 4015        cx: &mut Context<Self>,
 4016        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 4017    ) -> R {
 4018        let snapshot = self.display_snapshot(cx);
 4019        if let Some(state) = &mut self.deferred_selection_effects_state {
 4020            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 4021            state.effects.completions = effects.completions;
 4022            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 4023            let (changed, result) = self.selections.change_with(&snapshot, change);
 4024            state.changed |= changed;
 4025            return result;
 4026        }
 4027        let mut state = DeferredSelectionEffectsState {
 4028            changed: false,
 4029            effects,
 4030            old_cursor_position: self.selections.newest_anchor().head(),
 4031            history_entry: SelectionHistoryEntry {
 4032                selections: self.selections.disjoint_anchors_arc(),
 4033                select_next_state: self.select_next_state.clone(),
 4034                select_prev_state: self.select_prev_state.clone(),
 4035                add_selections_state: self.add_selections_state.clone(),
 4036            },
 4037        };
 4038        let (changed, result) = self.selections.change_with(&snapshot, change);
 4039        state.changed = state.changed || changed;
 4040        if self.defer_selection_effects {
 4041            self.deferred_selection_effects_state = Some(state);
 4042        } else {
 4043            self.apply_selection_effects(state, window, cx);
 4044        }
 4045        result
 4046    }
 4047
 4048    /// Defers the effects of selection change, so that the effects of multiple calls to
 4049    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 4050    /// to selection history and the state of popovers based on selection position aren't
 4051    /// erroneously updated.
 4052    pub fn with_selection_effects_deferred<R>(
 4053        &mut self,
 4054        window: &mut Window,
 4055        cx: &mut Context<Self>,
 4056        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 4057    ) -> R {
 4058        let already_deferred = self.defer_selection_effects;
 4059        self.defer_selection_effects = true;
 4060        let result = update(self, window, cx);
 4061        if !already_deferred {
 4062            self.defer_selection_effects = false;
 4063            if let Some(state) = self.deferred_selection_effects_state.take() {
 4064                self.apply_selection_effects(state, window, cx);
 4065            }
 4066        }
 4067        result
 4068    }
 4069
 4070    fn apply_selection_effects(
 4071        &mut self,
 4072        state: DeferredSelectionEffectsState,
 4073        window: &mut Window,
 4074        cx: &mut Context<Self>,
 4075    ) {
 4076        if state.changed {
 4077            self.selection_history.push(state.history_entry);
 4078
 4079            if let Some(autoscroll) = state.effects.scroll {
 4080                self.request_autoscroll(autoscroll, cx);
 4081            }
 4082
 4083            let old_cursor_position = &state.old_cursor_position;
 4084
 4085            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 4086
 4087            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 4088                self.show_signature_help_auto(window, cx);
 4089            }
 4090        }
 4091    }
 4092
 4093    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4094    where
 4095        I: IntoIterator<Item = (Range<S>, T)>,
 4096        S: ToOffset,
 4097        T: Into<Arc<str>>,
 4098    {
 4099        if self.read_only(cx) {
 4100            return;
 4101        }
 4102
 4103        self.buffer
 4104            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 4105    }
 4106
 4107    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 4108    where
 4109        I: IntoIterator<Item = (Range<S>, T)>,
 4110        S: ToOffset,
 4111        T: Into<Arc<str>>,
 4112    {
 4113        if self.read_only(cx) {
 4114            return;
 4115        }
 4116
 4117        self.buffer.update(cx, |buffer, cx| {
 4118            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 4119        });
 4120    }
 4121
 4122    pub fn edit_with_block_indent<I, S, T>(
 4123        &mut self,
 4124        edits: I,
 4125        original_indent_columns: Vec<Option<u32>>,
 4126        cx: &mut Context<Self>,
 4127    ) where
 4128        I: IntoIterator<Item = (Range<S>, T)>,
 4129        S: ToOffset,
 4130        T: Into<Arc<str>>,
 4131    {
 4132        if self.read_only(cx) {
 4133            return;
 4134        }
 4135
 4136        self.buffer.update(cx, |buffer, cx| {
 4137            buffer.edit(
 4138                edits,
 4139                Some(AutoindentMode::Block {
 4140                    original_indent_columns,
 4141                }),
 4142                cx,
 4143            )
 4144        });
 4145    }
 4146
 4147    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 4148        self.hide_context_menu(window, cx);
 4149
 4150        match phase {
 4151            SelectPhase::Begin {
 4152                position,
 4153                add,
 4154                click_count,
 4155            } => self.begin_selection(position, add, click_count, window, cx),
 4156            SelectPhase::BeginColumnar {
 4157                position,
 4158                goal_column,
 4159                reset,
 4160                mode,
 4161            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 4162            SelectPhase::Extend {
 4163                position,
 4164                click_count,
 4165            } => self.extend_selection(position, click_count, window, cx),
 4166            SelectPhase::Update {
 4167                position,
 4168                goal_column,
 4169                scroll_delta,
 4170            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 4171            SelectPhase::End => self.end_selection(window, cx),
 4172        }
 4173    }
 4174
 4175    fn extend_selection(
 4176        &mut self,
 4177        position: DisplayPoint,
 4178        click_count: usize,
 4179        window: &mut Window,
 4180        cx: &mut Context<Self>,
 4181    ) {
 4182        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4183        let tail = self
 4184            .selections
 4185            .newest::<MultiBufferOffset>(&display_map)
 4186            .tail();
 4187        let click_count = click_count.max(match self.selections.select_mode() {
 4188            SelectMode::Character => 1,
 4189            SelectMode::Word(_) => 2,
 4190            SelectMode::Line(_) => 3,
 4191            SelectMode::All => 4,
 4192        });
 4193        self.begin_selection(position, false, click_count, window, cx);
 4194
 4195        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4196
 4197        let current_selection = match self.selections.select_mode() {
 4198            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4199            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4200        };
 4201
 4202        let mut pending_selection = self
 4203            .selections
 4204            .pending_anchor()
 4205            .cloned()
 4206            .expect("extend_selection not called with pending selection");
 4207
 4208        if pending_selection
 4209            .start
 4210            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4211            == Ordering::Greater
 4212        {
 4213            pending_selection.start = current_selection.start;
 4214        }
 4215        if pending_selection
 4216            .end
 4217            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4218            == Ordering::Less
 4219        {
 4220            pending_selection.end = current_selection.end;
 4221            pending_selection.reversed = true;
 4222        }
 4223
 4224        let mut pending_mode = self.selections.pending_mode().unwrap();
 4225        match &mut pending_mode {
 4226            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4227            _ => {}
 4228        }
 4229
 4230        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4231            SelectionEffects::scroll(Autoscroll::fit())
 4232        } else {
 4233            SelectionEffects::no_scroll()
 4234        };
 4235
 4236        self.change_selections(effects, window, cx, |s| {
 4237            s.set_pending(pending_selection.clone(), pending_mode);
 4238            s.set_is_extending(true);
 4239        });
 4240    }
 4241
 4242    fn begin_selection(
 4243        &mut self,
 4244        position: DisplayPoint,
 4245        add: bool,
 4246        click_count: usize,
 4247        window: &mut Window,
 4248        cx: &mut Context<Self>,
 4249    ) {
 4250        if !self.focus_handle.is_focused(window) {
 4251            self.last_focused_descendant = None;
 4252            window.focus(&self.focus_handle, cx);
 4253        }
 4254
 4255        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4256        let buffer = display_map.buffer_snapshot();
 4257        let position = display_map.clip_point(position, Bias::Left);
 4258
 4259        let start;
 4260        let end;
 4261        let mode;
 4262        let mut auto_scroll;
 4263        match click_count {
 4264            1 => {
 4265                start = buffer.anchor_before(position.to_point(&display_map));
 4266                end = start;
 4267                mode = SelectMode::Character;
 4268                auto_scroll = true;
 4269            }
 4270            2 => {
 4271                let position = display_map
 4272                    .clip_point(position, Bias::Left)
 4273                    .to_offset(&display_map, Bias::Left);
 4274                let (range, _) = buffer.surrounding_word(position, None);
 4275                start = buffer.anchor_before(range.start);
 4276                end = buffer.anchor_before(range.end);
 4277                mode = SelectMode::Word(start..end);
 4278                auto_scroll = true;
 4279            }
 4280            3 => {
 4281                let position = display_map
 4282                    .clip_point(position, Bias::Left)
 4283                    .to_point(&display_map);
 4284                let line_start = display_map.prev_line_boundary(position).0;
 4285                let next_line_start = buffer.clip_point(
 4286                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4287                    Bias::Left,
 4288                );
 4289                start = buffer.anchor_before(line_start);
 4290                end = buffer.anchor_before(next_line_start);
 4291                mode = SelectMode::Line(start..end);
 4292                auto_scroll = true;
 4293            }
 4294            _ => {
 4295                start = buffer.anchor_before(MultiBufferOffset(0));
 4296                end = buffer.anchor_before(buffer.len());
 4297                mode = SelectMode::All;
 4298                auto_scroll = false;
 4299            }
 4300        }
 4301        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4302
 4303        let point_to_delete: Option<usize> = {
 4304            let selected_points: Vec<Selection<Point>> =
 4305                self.selections.disjoint_in_range(start..end, &display_map);
 4306
 4307            if !add || click_count > 1 {
 4308                None
 4309            } else if !selected_points.is_empty() {
 4310                Some(selected_points[0].id)
 4311            } else {
 4312                let clicked_point_already_selected =
 4313                    self.selections.disjoint_anchors().iter().find(|selection| {
 4314                        selection.start.to_point(buffer) == start.to_point(buffer)
 4315                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4316                    });
 4317
 4318                clicked_point_already_selected.map(|selection| selection.id)
 4319            }
 4320        };
 4321
 4322        let selections_count = self.selections.count();
 4323        let effects = if auto_scroll {
 4324            SelectionEffects::default()
 4325        } else {
 4326            SelectionEffects::no_scroll()
 4327        };
 4328
 4329        self.change_selections(effects, window, cx, |s| {
 4330            if let Some(point_to_delete) = point_to_delete {
 4331                s.delete(point_to_delete);
 4332
 4333                if selections_count == 1 {
 4334                    s.set_pending_anchor_range(start..end, mode);
 4335                }
 4336            } else {
 4337                if !add {
 4338                    s.clear_disjoint();
 4339                }
 4340
 4341                s.set_pending_anchor_range(start..end, mode);
 4342            }
 4343        });
 4344    }
 4345
 4346    fn begin_columnar_selection(
 4347        &mut self,
 4348        position: DisplayPoint,
 4349        goal_column: u32,
 4350        reset: bool,
 4351        mode: ColumnarMode,
 4352        window: &mut Window,
 4353        cx: &mut Context<Self>,
 4354    ) {
 4355        if !self.focus_handle.is_focused(window) {
 4356            self.last_focused_descendant = None;
 4357            window.focus(&self.focus_handle, cx);
 4358        }
 4359
 4360        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4361
 4362        if reset {
 4363            let pointer_position = display_map
 4364                .buffer_snapshot()
 4365                .anchor_before(position.to_point(&display_map));
 4366
 4367            self.change_selections(
 4368                SelectionEffects::scroll(Autoscroll::newest()),
 4369                window,
 4370                cx,
 4371                |s| {
 4372                    s.clear_disjoint();
 4373                    s.set_pending_anchor_range(
 4374                        pointer_position..pointer_position,
 4375                        SelectMode::Character,
 4376                    );
 4377                },
 4378            );
 4379        };
 4380
 4381        let tail = self.selections.newest::<Point>(&display_map).tail();
 4382        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4383        self.columnar_selection_state = match mode {
 4384            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4385                selection_tail: selection_anchor,
 4386                display_point: if reset {
 4387                    if position.column() != goal_column {
 4388                        Some(DisplayPoint::new(position.row(), goal_column))
 4389                    } else {
 4390                        None
 4391                    }
 4392                } else {
 4393                    None
 4394                },
 4395            }),
 4396            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4397                selection_tail: selection_anchor,
 4398            }),
 4399        };
 4400
 4401        if !reset {
 4402            self.select_columns(position, goal_column, &display_map, window, cx);
 4403        }
 4404    }
 4405
 4406    fn update_selection(
 4407        &mut self,
 4408        position: DisplayPoint,
 4409        goal_column: u32,
 4410        scroll_delta: gpui::Point<f32>,
 4411        window: &mut Window,
 4412        cx: &mut Context<Self>,
 4413    ) {
 4414        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4415
 4416        if self.columnar_selection_state.is_some() {
 4417            self.select_columns(position, goal_column, &display_map, window, cx);
 4418        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4419            let buffer = display_map.buffer_snapshot();
 4420            let head;
 4421            let tail;
 4422            let mode = self.selections.pending_mode().unwrap();
 4423            match &mode {
 4424                SelectMode::Character => {
 4425                    head = position.to_point(&display_map);
 4426                    tail = pending.tail().to_point(buffer);
 4427                }
 4428                SelectMode::Word(original_range) => {
 4429                    let offset = display_map
 4430                        .clip_point(position, Bias::Left)
 4431                        .to_offset(&display_map, Bias::Left);
 4432                    let original_range = original_range.to_offset(buffer);
 4433
 4434                    let head_offset = if buffer.is_inside_word(offset, None)
 4435                        || original_range.contains(&offset)
 4436                    {
 4437                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4438                        if word_range.start < original_range.start {
 4439                            word_range.start
 4440                        } else {
 4441                            word_range.end
 4442                        }
 4443                    } else {
 4444                        offset
 4445                    };
 4446
 4447                    head = head_offset.to_point(buffer);
 4448                    if head_offset <= original_range.start {
 4449                        tail = original_range.end.to_point(buffer);
 4450                    } else {
 4451                        tail = original_range.start.to_point(buffer);
 4452                    }
 4453                }
 4454                SelectMode::Line(original_range) => {
 4455                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4456
 4457                    let position = display_map
 4458                        .clip_point(position, Bias::Left)
 4459                        .to_point(&display_map);
 4460                    let line_start = display_map.prev_line_boundary(position).0;
 4461                    let next_line_start = buffer.clip_point(
 4462                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4463                        Bias::Left,
 4464                    );
 4465
 4466                    if line_start < original_range.start {
 4467                        head = line_start
 4468                    } else {
 4469                        head = next_line_start
 4470                    }
 4471
 4472                    if head <= original_range.start {
 4473                        tail = original_range.end;
 4474                    } else {
 4475                        tail = original_range.start;
 4476                    }
 4477                }
 4478                SelectMode::All => {
 4479                    return;
 4480                }
 4481            };
 4482
 4483            if head < tail {
 4484                pending.start = buffer.anchor_before(head);
 4485                pending.end = buffer.anchor_before(tail);
 4486                pending.reversed = true;
 4487            } else {
 4488                pending.start = buffer.anchor_before(tail);
 4489                pending.end = buffer.anchor_before(head);
 4490                pending.reversed = false;
 4491            }
 4492
 4493            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4494                s.set_pending(pending.clone(), mode);
 4495            });
 4496        } else {
 4497            log::error!("update_selection dispatched with no pending selection");
 4498            return;
 4499        }
 4500
 4501        self.apply_scroll_delta(scroll_delta, window, cx);
 4502        cx.notify();
 4503    }
 4504
 4505    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4506        self.columnar_selection_state.take();
 4507        if let Some(pending_mode) = self.selections.pending_mode() {
 4508            let selections = self
 4509                .selections
 4510                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4511            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4512                s.select(selections);
 4513                s.clear_pending();
 4514                if s.is_extending() {
 4515                    s.set_is_extending(false);
 4516                } else {
 4517                    s.set_select_mode(pending_mode);
 4518                }
 4519            });
 4520        }
 4521    }
 4522
 4523    fn select_columns(
 4524        &mut self,
 4525        head: DisplayPoint,
 4526        goal_column: u32,
 4527        display_map: &DisplaySnapshot,
 4528        window: &mut Window,
 4529        cx: &mut Context<Self>,
 4530    ) {
 4531        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4532            return;
 4533        };
 4534
 4535        let tail = match columnar_state {
 4536            ColumnarSelectionState::FromMouse {
 4537                selection_tail,
 4538                display_point,
 4539            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4540            ColumnarSelectionState::FromSelection { selection_tail } => {
 4541                selection_tail.to_display_point(display_map)
 4542            }
 4543        };
 4544
 4545        let start_row = cmp::min(tail.row(), head.row());
 4546        let end_row = cmp::max(tail.row(), head.row());
 4547        let start_column = cmp::min(tail.column(), goal_column);
 4548        let end_column = cmp::max(tail.column(), goal_column);
 4549        let reversed = start_column < tail.column();
 4550
 4551        let selection_ranges = (start_row.0..=end_row.0)
 4552            .map(DisplayRow)
 4553            .filter_map(|row| {
 4554                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4555                    || start_column <= display_map.line_len(row))
 4556                    && !display_map.is_block_line(row)
 4557                {
 4558                    let start = display_map
 4559                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4560                        .to_point(display_map);
 4561                    let end = display_map
 4562                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4563                        .to_point(display_map);
 4564                    if reversed {
 4565                        Some(end..start)
 4566                    } else {
 4567                        Some(start..end)
 4568                    }
 4569                } else {
 4570                    None
 4571                }
 4572            })
 4573            .collect::<Vec<_>>();
 4574        if selection_ranges.is_empty() {
 4575            return;
 4576        }
 4577
 4578        let ranges = match columnar_state {
 4579            ColumnarSelectionState::FromMouse { .. } => {
 4580                let mut non_empty_ranges = selection_ranges
 4581                    .iter()
 4582                    .filter(|selection_range| selection_range.start != selection_range.end)
 4583                    .peekable();
 4584                if non_empty_ranges.peek().is_some() {
 4585                    non_empty_ranges.cloned().collect()
 4586                } else {
 4587                    selection_ranges
 4588                }
 4589            }
 4590            _ => selection_ranges,
 4591        };
 4592
 4593        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4594            s.select_ranges(ranges);
 4595        });
 4596        cx.notify();
 4597    }
 4598
 4599    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4600        self.selections
 4601            .all_adjusted(snapshot)
 4602            .iter()
 4603            .any(|selection| !selection.is_empty())
 4604    }
 4605
 4606    pub fn has_pending_nonempty_selection(&self) -> bool {
 4607        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4608            Some(Selection { start, end, .. }) => start != end,
 4609            None => false,
 4610        };
 4611
 4612        pending_nonempty_selection
 4613            || (self.columnar_selection_state.is_some()
 4614                && self.selections.disjoint_anchors().len() > 1)
 4615    }
 4616
 4617    pub fn has_pending_selection(&self) -> bool {
 4618        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4619    }
 4620
 4621    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4622        self.selection_mark_mode = false;
 4623        self.selection_drag_state = SelectionDragState::None;
 4624
 4625        if self.dismiss_menus_and_popups(true, window, cx) {
 4626            cx.notify();
 4627            return;
 4628        }
 4629        if self.clear_expanded_diff_hunks(cx) {
 4630            cx.notify();
 4631            return;
 4632        }
 4633        if self.show_git_blame_gutter {
 4634            self.show_git_blame_gutter = false;
 4635            cx.notify();
 4636            return;
 4637        }
 4638
 4639        if self.mode.is_full()
 4640            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4641        {
 4642            cx.notify();
 4643            return;
 4644        }
 4645
 4646        cx.propagate();
 4647    }
 4648
 4649    pub fn dismiss_menus_and_popups(
 4650        &mut self,
 4651        is_user_requested: bool,
 4652        window: &mut Window,
 4653        cx: &mut Context<Self>,
 4654    ) -> bool {
 4655        let mut dismissed = false;
 4656
 4657        dismissed |= self.take_rename(false, window, cx).is_some();
 4658        dismissed |= self.hide_blame_popover(true, cx);
 4659        dismissed |= hide_hover(self, cx);
 4660        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4661        dismissed |= self.hide_context_menu(window, cx).is_some();
 4662        dismissed |= self.mouse_context_menu.take().is_some();
 4663        dismissed |= is_user_requested
 4664            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4665        dismissed |= self.snippet_stack.pop().is_some();
 4666        if self.diff_review_drag_state.is_some() {
 4667            self.cancel_diff_review_drag(cx);
 4668            dismissed = true;
 4669        }
 4670        if !self.diff_review_overlays.is_empty() {
 4671            self.dismiss_all_diff_review_overlays(cx);
 4672            dismissed = true;
 4673        }
 4674
 4675        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4676            self.dismiss_diagnostics(cx);
 4677            dismissed = true;
 4678        }
 4679
 4680        dismissed
 4681    }
 4682
 4683    fn linked_editing_ranges_for(
 4684        &self,
 4685        query_range: Range<text::Anchor>,
 4686        cx: &App,
 4687    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4688        use text::ToOffset as TO;
 4689
 4690        if self.linked_edit_ranges.is_empty() {
 4691            return None;
 4692        }
 4693        if query_range.start.buffer_id != query_range.end.buffer_id {
 4694            return None;
 4695        };
 4696        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 4697        let buffer = self.buffer.read(cx).buffer(query_range.end.buffer_id)?;
 4698        let buffer_snapshot = buffer.read(cx).snapshot();
 4699        let (base_range, linked_ranges) = self.linked_edit_ranges.get(
 4700            buffer_snapshot.remote_id(),
 4701            query_range.clone(),
 4702            &buffer_snapshot,
 4703        )?;
 4704        // find offset from the start of current range to current cursor position
 4705        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4706
 4707        let start_offset = TO::to_offset(&query_range.start, &buffer_snapshot);
 4708        let start_difference = start_offset - start_byte_offset;
 4709        let end_offset = TO::to_offset(&query_range.end, &buffer_snapshot);
 4710        let end_difference = end_offset - start_byte_offset;
 4711
 4712        // Current range has associated linked ranges.
 4713        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4714        for range in linked_ranges.iter() {
 4715            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4716            let end_offset = start_offset + end_difference;
 4717            let start_offset = start_offset + start_difference;
 4718            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4719                continue;
 4720            }
 4721            if self.selections.disjoint_anchor_ranges().any(|s| {
 4722                let Some((selection_start, _)) =
 4723                    multibuffer_snapshot.anchor_to_buffer_anchor(s.start)
 4724                else {
 4725                    return false;
 4726                };
 4727                let Some((selection_end, _)) = multibuffer_snapshot.anchor_to_buffer_anchor(s.end)
 4728                else {
 4729                    return false;
 4730                };
 4731                if selection_start.buffer_id != query_range.start.buffer_id
 4732                    || selection_end.buffer_id != query_range.end.buffer_id
 4733                {
 4734                    return false;
 4735                }
 4736                TO::to_offset(&selection_start, &buffer_snapshot) <= end_offset
 4737                    && TO::to_offset(&selection_end, &buffer_snapshot) >= start_offset
 4738            }) {
 4739                continue;
 4740            }
 4741            let start = buffer_snapshot.anchor_after(start_offset);
 4742            let end = buffer_snapshot.anchor_after(end_offset);
 4743            linked_edits
 4744                .entry(buffer.clone())
 4745                .or_default()
 4746                .push(start..end);
 4747        }
 4748        Some(linked_edits)
 4749    }
 4750
 4751    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4752        let text: Arc<str> = text.into();
 4753
 4754        if self.read_only(cx) {
 4755            return;
 4756        }
 4757
 4758        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4759
 4760        self.unfold_buffers_with_selections(cx);
 4761
 4762        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4763        let mut bracket_inserted = false;
 4764        let mut edits = Vec::new();
 4765        let mut linked_edits = LinkedEdits::new();
 4766        let mut new_selections = Vec::with_capacity(selections.len());
 4767        let mut new_autoclose_regions = Vec::new();
 4768        let snapshot = self.buffer.read(cx).read(cx);
 4769        let mut clear_linked_edit_ranges = false;
 4770        let mut all_selections_read_only = true;
 4771        let mut has_adjacent_edits = false;
 4772        let mut in_adjacent_group = false;
 4773
 4774        let mut regions = self
 4775            .selections_with_autoclose_regions(selections, &snapshot)
 4776            .peekable();
 4777
 4778        while let Some((selection, autoclose_region)) = regions.next() {
 4779            if snapshot
 4780                .point_to_buffer_point(selection.head())
 4781                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4782            {
 4783                continue;
 4784            }
 4785            if snapshot
 4786                .point_to_buffer_point(selection.tail())
 4787                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4788            {
 4789                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4790                continue;
 4791            }
 4792            all_selections_read_only = false;
 4793
 4794            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4795                // Determine if the inserted text matches the opening or closing
 4796                // bracket of any of this language's bracket pairs.
 4797                let mut bracket_pair = None;
 4798                let mut is_bracket_pair_start = false;
 4799                let mut is_bracket_pair_end = false;
 4800                if !text.is_empty() {
 4801                    let mut bracket_pair_matching_end = None;
 4802                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4803                    //  and they are removing the character that triggered IME popup.
 4804                    for (pair, enabled) in scope.brackets() {
 4805                        if !pair.close && !pair.surround {
 4806                            continue;
 4807                        }
 4808
 4809                        if enabled && pair.start.ends_with(text.as_ref()) {
 4810                            let prefix_len = pair.start.len() - text.len();
 4811                            let preceding_text_matches_prefix = prefix_len == 0
 4812                                || (selection.start.column >= (prefix_len as u32)
 4813                                    && snapshot.contains_str_at(
 4814                                        Point::new(
 4815                                            selection.start.row,
 4816                                            selection.start.column - (prefix_len as u32),
 4817                                        ),
 4818                                        &pair.start[..prefix_len],
 4819                                    ));
 4820                            if preceding_text_matches_prefix {
 4821                                bracket_pair = Some(pair.clone());
 4822                                is_bracket_pair_start = true;
 4823                                break;
 4824                            }
 4825                        }
 4826                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4827                        {
 4828                            // take first bracket pair matching end, but don't break in case a later bracket
 4829                            // pair matches start
 4830                            bracket_pair_matching_end = Some(pair.clone());
 4831                        }
 4832                    }
 4833                    if let Some(end) = bracket_pair_matching_end
 4834                        && bracket_pair.is_none()
 4835                    {
 4836                        bracket_pair = Some(end);
 4837                        is_bracket_pair_end = true;
 4838                    }
 4839                }
 4840
 4841                if let Some(bracket_pair) = bracket_pair {
 4842                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4843                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4844                    let auto_surround =
 4845                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4846                    if selection.is_empty() {
 4847                        if is_bracket_pair_start {
 4848                            // If the inserted text is a suffix of an opening bracket and the
 4849                            // selection is preceded by the rest of the opening bracket, then
 4850                            // insert the closing bracket.
 4851                            let following_text_allows_autoclose = snapshot
 4852                                .chars_at(selection.start)
 4853                                .next()
 4854                                .is_none_or(|c| scope.should_autoclose_before(c));
 4855
 4856                            let preceding_text_allows_autoclose = selection.start.column == 0
 4857                                || snapshot
 4858                                    .reversed_chars_at(selection.start)
 4859                                    .next()
 4860                                    .is_none_or(|c| {
 4861                                        bracket_pair.start != bracket_pair.end
 4862                                            || !snapshot
 4863                                                .char_classifier_at(selection.start)
 4864                                                .is_word(c)
 4865                                    });
 4866
 4867                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4868                                && bracket_pair.start.len() == 1
 4869                            {
 4870                                let target = bracket_pair.start.chars().next().unwrap();
 4871                                let mut byte_offset = 0u32;
 4872                                let current_line_count = snapshot
 4873                                    .reversed_chars_at(selection.start)
 4874                                    .take_while(|&c| c != '\n')
 4875                                    .filter(|c| {
 4876                                        byte_offset += c.len_utf8() as u32;
 4877                                        if *c != target {
 4878                                            return false;
 4879                                        }
 4880
 4881                                        let point = Point::new(
 4882                                            selection.start.row,
 4883                                            selection.start.column.saturating_sub(byte_offset),
 4884                                        );
 4885
 4886                                        let is_enabled = snapshot
 4887                                            .language_scope_at(point)
 4888                                            .and_then(|scope| {
 4889                                                scope
 4890                                                    .brackets()
 4891                                                    .find(|(pair, _)| {
 4892                                                        pair.start == bracket_pair.start
 4893                                                    })
 4894                                                    .map(|(_, enabled)| enabled)
 4895                                            })
 4896                                            .unwrap_or(true);
 4897
 4898                                        let is_delimiter = snapshot
 4899                                            .language_scope_at(Point::new(
 4900                                                point.row,
 4901                                                point.column + 1,
 4902                                            ))
 4903                                            .and_then(|scope| {
 4904                                                scope
 4905                                                    .brackets()
 4906                                                    .find(|(pair, _)| {
 4907                                                        pair.start == bracket_pair.start
 4908                                                    })
 4909                                                    .map(|(_, enabled)| !enabled)
 4910                                            })
 4911                                            .unwrap_or(false);
 4912
 4913                                        is_enabled && !is_delimiter
 4914                                    })
 4915                                    .count();
 4916                                current_line_count % 2 == 1
 4917                            } else {
 4918                                false
 4919                            };
 4920
 4921                            if autoclose
 4922                                && bracket_pair.close
 4923                                && following_text_allows_autoclose
 4924                                && preceding_text_allows_autoclose
 4925                                && !is_closing_quote
 4926                            {
 4927                                let anchor = snapshot.anchor_before(selection.end);
 4928                                new_selections.push((selection.map(|_| anchor), text.len()));
 4929                                new_autoclose_regions.push((
 4930                                    anchor,
 4931                                    text.len(),
 4932                                    selection.id,
 4933                                    bracket_pair.clone(),
 4934                                ));
 4935                                edits.push((
 4936                                    selection.range(),
 4937                                    format!("{}{}", text, bracket_pair.end).into(),
 4938                                ));
 4939                                bracket_inserted = true;
 4940                                continue;
 4941                            }
 4942                        }
 4943
 4944                        if let Some(region) = autoclose_region {
 4945                            // If the selection is followed by an auto-inserted closing bracket,
 4946                            // then don't insert that closing bracket again; just move the selection
 4947                            // past the closing bracket.
 4948                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4949                                && text.as_ref() == region.pair.end.as_str()
 4950                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4951                            if should_skip {
 4952                                let anchor = snapshot.anchor_after(selection.end);
 4953                                new_selections
 4954                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4955                                continue;
 4956                            }
 4957                        }
 4958
 4959                        let always_treat_brackets_as_autoclosed = snapshot
 4960                            .language_settings_at(selection.start, cx)
 4961                            .always_treat_brackets_as_autoclosed;
 4962                        if always_treat_brackets_as_autoclosed
 4963                            && is_bracket_pair_end
 4964                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4965                        {
 4966                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4967                            // and the inserted text is a closing bracket and the selection is followed
 4968                            // by the closing bracket then move the selection past the closing bracket.
 4969                            let anchor = snapshot.anchor_after(selection.end);
 4970                            new_selections.push((selection.map(|_| anchor), text.len()));
 4971                            continue;
 4972                        }
 4973                    }
 4974                    // If an opening bracket is 1 character long and is typed while
 4975                    // text is selected, then surround that text with the bracket pair.
 4976                    else if auto_surround
 4977                        && bracket_pair.surround
 4978                        && is_bracket_pair_start
 4979                        && bracket_pair.start.chars().count() == 1
 4980                    {
 4981                        edits.push((selection.start..selection.start, text.clone()));
 4982                        edits.push((
 4983                            selection.end..selection.end,
 4984                            bracket_pair.end.as_str().into(),
 4985                        ));
 4986                        bracket_inserted = true;
 4987                        new_selections.push((
 4988                            Selection {
 4989                                id: selection.id,
 4990                                start: snapshot.anchor_after(selection.start),
 4991                                end: snapshot.anchor_before(selection.end),
 4992                                reversed: selection.reversed,
 4993                                goal: selection.goal,
 4994                            },
 4995                            0,
 4996                        ));
 4997                        continue;
 4998                    }
 4999                }
 5000            }
 5001
 5002            if self.auto_replace_emoji_shortcode
 5003                && selection.is_empty()
 5004                && text.as_ref().ends_with(':')
 5005                && let Some(possible_emoji_short_code) =
 5006                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 5007                && !possible_emoji_short_code.is_empty()
 5008                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 5009            {
 5010                let emoji_shortcode_start = Point::new(
 5011                    selection.start.row,
 5012                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 5013                );
 5014
 5015                // Remove shortcode from buffer
 5016                edits.push((
 5017                    emoji_shortcode_start..selection.start,
 5018                    "".to_string().into(),
 5019                ));
 5020                new_selections.push((
 5021                    Selection {
 5022                        id: selection.id,
 5023                        start: snapshot.anchor_after(emoji_shortcode_start),
 5024                        end: snapshot.anchor_before(selection.start),
 5025                        reversed: selection.reversed,
 5026                        goal: selection.goal,
 5027                    },
 5028                    0,
 5029                ));
 5030
 5031                // Insert emoji
 5032                let selection_start_anchor = snapshot.anchor_after(selection.start);
 5033                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 5034                edits.push((selection.start..selection.end, emoji.to_string().into()));
 5035
 5036                continue;
 5037            }
 5038
 5039            let next_is_adjacent = regions
 5040                .peek()
 5041                .is_some_and(|(next, _)| selection.end == next.start);
 5042
 5043            // If not handling any auto-close operation, then just replace the selected
 5044            // text with the given input and move the selection to the end of the
 5045            // newly inserted text.
 5046            let anchor = if in_adjacent_group || next_is_adjacent {
 5047                // After edits the right bias would shift those anchor to the next visible fragment
 5048                // but we want to resolve to the previous one
 5049                snapshot.anchor_before(selection.end)
 5050            } else {
 5051                snapshot.anchor_after(selection.end)
 5052            };
 5053
 5054            if !self.linked_edit_ranges.is_empty() {
 5055                let start_anchor = snapshot.anchor_before(selection.start);
 5056                let classifier = snapshot
 5057                    .char_classifier_at(start_anchor)
 5058                    .scope_context(Some(CharScopeContext::LinkedEdit));
 5059
 5060                if let Some((_, anchor_range)) =
 5061                    snapshot.anchor_range_to_buffer_anchor_range(start_anchor..anchor)
 5062                {
 5063                    let is_word_char = text
 5064                        .chars()
 5065                        .next()
 5066                        .is_none_or(|char| classifier.is_word(char));
 5067
 5068                    let is_dot = text.as_ref() == ".";
 5069                    let should_apply_linked_edit = is_word_char || is_dot;
 5070
 5071                    if should_apply_linked_edit {
 5072                        linked_edits.push(&self, anchor_range, text.clone(), cx);
 5073                    } else {
 5074                        clear_linked_edit_ranges = true;
 5075                    }
 5076                }
 5077            }
 5078
 5079            new_selections.push((selection.map(|_| anchor), 0));
 5080            edits.push((selection.start..selection.end, text.clone()));
 5081
 5082            has_adjacent_edits |= next_is_adjacent;
 5083            in_adjacent_group = next_is_adjacent;
 5084        }
 5085
 5086        if all_selections_read_only {
 5087            return;
 5088        }
 5089
 5090        drop(regions);
 5091        drop(snapshot);
 5092
 5093        self.transact(window, cx, |this, window, cx| {
 5094            if clear_linked_edit_ranges {
 5095                this.linked_edit_ranges.clear();
 5096            }
 5097            let initial_buffer_versions =
 5098                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 5099
 5100            this.buffer.update(cx, |buffer, cx| {
 5101                if has_adjacent_edits {
 5102                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 5103                } else {
 5104                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 5105                }
 5106            });
 5107            linked_edits.apply(cx);
 5108            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 5109            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 5110            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 5111            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 5112                new_anchor_selections,
 5113                &map,
 5114            )
 5115            .zip(new_selection_deltas)
 5116            .map(|(selection, delta)| Selection {
 5117                id: selection.id,
 5118                start: selection.start + delta,
 5119                end: selection.end + delta,
 5120                reversed: selection.reversed,
 5121                goal: SelectionGoal::None,
 5122            })
 5123            .collect::<Vec<_>>();
 5124
 5125            let mut i = 0;
 5126            for (position, delta, selection_id, pair) in new_autoclose_regions {
 5127                let position = position.to_offset(map.buffer_snapshot()) + delta;
 5128                let start = map.buffer_snapshot().anchor_before(position);
 5129                let end = map.buffer_snapshot().anchor_after(position);
 5130                while let Some(existing_state) = this.autoclose_regions.get(i) {
 5131                    match existing_state
 5132                        .range
 5133                        .start
 5134                        .cmp(&start, map.buffer_snapshot())
 5135                    {
 5136                        Ordering::Less => i += 1,
 5137                        Ordering::Greater => break,
 5138                        Ordering::Equal => {
 5139                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 5140                                Ordering::Less => i += 1,
 5141                                Ordering::Equal => break,
 5142                                Ordering::Greater => break,
 5143                            }
 5144                        }
 5145                    }
 5146                }
 5147                this.autoclose_regions.insert(
 5148                    i,
 5149                    AutocloseRegion {
 5150                        selection_id,
 5151                        range: start..end,
 5152                        pair,
 5153                    },
 5154                );
 5155            }
 5156
 5157            let had_active_edit_prediction = this.has_active_edit_prediction();
 5158            this.change_selections(
 5159                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 5160                window,
 5161                cx,
 5162                |s| s.select(new_selections),
 5163            );
 5164
 5165            if !bracket_inserted
 5166                && let Some(on_type_format_task) =
 5167                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 5168            {
 5169                on_type_format_task.detach_and_log_err(cx);
 5170            }
 5171
 5172            let editor_settings = EditorSettings::get_global(cx);
 5173            if bracket_inserted
 5174                && (editor_settings.auto_signature_help
 5175                    || editor_settings.show_signature_help_after_edits)
 5176            {
 5177                this.show_signature_help(&ShowSignatureHelp, window, cx);
 5178            }
 5179
 5180            let trigger_in_words =
 5181                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 5182            if this.hard_wrap.is_some() {
 5183                let latest: Range<Point> = this.selections.newest(&map).range();
 5184                if latest.is_empty()
 5185                    && this
 5186                        .buffer()
 5187                        .read(cx)
 5188                        .snapshot(cx)
 5189                        .line_len(MultiBufferRow(latest.start.row))
 5190                        == latest.start.column
 5191                {
 5192                    this.rewrap_impl(
 5193                        RewrapOptions {
 5194                            override_language_settings: true,
 5195                            preserve_existing_whitespace: true,
 5196                            line_length: None,
 5197                        },
 5198                        cx,
 5199                    )
 5200                }
 5201            }
 5202            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 5203            refresh_linked_ranges(this, window, cx);
 5204            this.refresh_edit_prediction(true, false, window, cx);
 5205            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5206        });
 5207    }
 5208
 5209    fn find_possible_emoji_shortcode_at_position(
 5210        snapshot: &MultiBufferSnapshot,
 5211        position: Point,
 5212    ) -> Option<String> {
 5213        let mut chars = Vec::new();
 5214        let mut found_colon = false;
 5215        for char in snapshot.reversed_chars_at(position).take(100) {
 5216            // Found a possible emoji shortcode in the middle of the buffer
 5217            if found_colon {
 5218                if char.is_whitespace() {
 5219                    chars.reverse();
 5220                    return Some(chars.iter().collect());
 5221                }
 5222                // If the previous character is not a whitespace, we are in the middle of a word
 5223                // and we only want to complete the shortcode if the word is made up of other emojis
 5224                let mut containing_word = String::new();
 5225                for ch in snapshot
 5226                    .reversed_chars_at(position)
 5227                    .skip(chars.len() + 1)
 5228                    .take(100)
 5229                {
 5230                    if ch.is_whitespace() {
 5231                        break;
 5232                    }
 5233                    containing_word.push(ch);
 5234                }
 5235                let containing_word = containing_word.chars().rev().collect::<String>();
 5236                if util::word_consists_of_emojis(containing_word.as_str()) {
 5237                    chars.reverse();
 5238                    return Some(chars.iter().collect());
 5239                }
 5240            }
 5241
 5242            if char.is_whitespace() || !char.is_ascii() {
 5243                return None;
 5244            }
 5245            if char == ':' {
 5246                found_colon = true;
 5247            } else {
 5248                chars.push(char);
 5249            }
 5250        }
 5251        // Found a possible emoji shortcode at the beginning of the buffer
 5252        chars.reverse();
 5253        Some(chars.iter().collect())
 5254    }
 5255
 5256    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5257        if self.read_only(cx) {
 5258            return;
 5259        }
 5260
 5261        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5262        self.transact(window, cx, |this, window, cx| {
 5263            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5264                let selections = this
 5265                    .selections
 5266                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5267                let multi_buffer = this.buffer.read(cx);
 5268                let buffer = multi_buffer.snapshot(cx);
 5269                selections
 5270                    .iter()
 5271                    .map(|selection| {
 5272                        let start_point = selection.start.to_point(&buffer);
 5273                        let mut existing_indent =
 5274                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5275                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5276                        let start = selection.start;
 5277                        let end = selection.end;
 5278                        let selection_is_empty = start == end;
 5279                        let language_scope = buffer.language_scope_at(start);
 5280                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5281                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5282                                &buffer,
 5283                                start..end,
 5284                                language,
 5285                            )
 5286                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5287                                    &buffer,
 5288                                    start..end,
 5289                                );
 5290
 5291                            let mut newline_config = NewlineConfig::Newline {
 5292                                additional_indent: IndentSize::spaces(0),
 5293                                extra_line_additional_indent: if needs_extra_newline {
 5294                                    Some(IndentSize::spaces(0))
 5295                                } else {
 5296                                    None
 5297                                },
 5298                                prevent_auto_indent: false,
 5299                            };
 5300
 5301                            let comment_delimiter = maybe!({
 5302                                if !selection_is_empty {
 5303                                    return None;
 5304                                }
 5305
 5306                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5307                                    return None;
 5308                                }
 5309
 5310                                return comment_delimiter_for_newline(
 5311                                    &start_point,
 5312                                    &buffer,
 5313                                    language,
 5314                                );
 5315                            });
 5316
 5317                            let doc_delimiter = maybe!({
 5318                                if !selection_is_empty {
 5319                                    return None;
 5320                                }
 5321
 5322                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5323                                    return None;
 5324                                }
 5325
 5326                                return documentation_delimiter_for_newline(
 5327                                    &start_point,
 5328                                    &buffer,
 5329                                    language,
 5330                                    &mut newline_config,
 5331                                );
 5332                            });
 5333
 5334                            let list_delimiter = maybe!({
 5335                                if !selection_is_empty {
 5336                                    return None;
 5337                                }
 5338
 5339                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5340                                    return None;
 5341                                }
 5342
 5343                                return list_delimiter_for_newline(
 5344                                    &start_point,
 5345                                    &buffer,
 5346                                    language,
 5347                                    &mut newline_config,
 5348                                );
 5349                            });
 5350
 5351                            (
 5352                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5353                                newline_config,
 5354                            )
 5355                        } else {
 5356                            (
 5357                                None,
 5358                                NewlineConfig::Newline {
 5359                                    additional_indent: IndentSize::spaces(0),
 5360                                    extra_line_additional_indent: None,
 5361                                    prevent_auto_indent: false,
 5362                                },
 5363                            )
 5364                        };
 5365
 5366                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5367                            NewlineConfig::ClearCurrentLine => {
 5368                                let row_start =
 5369                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5370                                (row_start, String::new(), false)
 5371                            }
 5372                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5373                                let row_start =
 5374                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5375                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5376                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5377                                let reduced_indent =
 5378                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5379                                let mut new_text = String::new();
 5380                                new_text.extend(reduced_indent.chars());
 5381                                new_text.push_str(continuation);
 5382                                (row_start, new_text, true)
 5383                            }
 5384                            NewlineConfig::Newline {
 5385                                additional_indent,
 5386                                extra_line_additional_indent,
 5387                                prevent_auto_indent,
 5388                            } => {
 5389                                let auto_indent_mode =
 5390                                    buffer.language_settings_at(start, cx).auto_indent;
 5391                                let preserve_indent =
 5392                                    auto_indent_mode != language::AutoIndentMode::None;
 5393                                let apply_syntax_indent =
 5394                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5395                                let capacity_for_delimiter =
 5396                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5397                                let existing_indent_len = if preserve_indent {
 5398                                    existing_indent.len as usize
 5399                                } else {
 5400                                    0
 5401                                };
 5402                                let extra_line_len = extra_line_additional_indent
 5403                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5404                                    .unwrap_or(0);
 5405                                let mut new_text = String::with_capacity(
 5406                                    1 + capacity_for_delimiter
 5407                                        + existing_indent_len
 5408                                        + additional_indent.len as usize
 5409                                        + extra_line_len,
 5410                                );
 5411                                new_text.push('\n');
 5412                                if preserve_indent {
 5413                                    new_text.extend(existing_indent.chars());
 5414                                }
 5415                                new_text.extend(additional_indent.chars());
 5416                                if let Some(delimiter) = &delimiter {
 5417                                    new_text.push_str(delimiter);
 5418                                }
 5419                                if let Some(extra_indent) = extra_line_additional_indent {
 5420                                    new_text.push('\n');
 5421                                    if preserve_indent {
 5422                                        new_text.extend(existing_indent.chars());
 5423                                    }
 5424                                    new_text.extend(extra_indent.chars());
 5425                                }
 5426                                (
 5427                                    start,
 5428                                    new_text,
 5429                                    *prevent_auto_indent || !apply_syntax_indent,
 5430                                )
 5431                            }
 5432                        };
 5433
 5434                        let anchor = buffer.anchor_after(end);
 5435                        let new_selection = selection.map(|_| anchor);
 5436                        (
 5437                            ((edit_start..end, new_text), prevent_auto_indent),
 5438                            (newline_config.has_extra_line(), new_selection),
 5439                        )
 5440                    })
 5441                    .unzip()
 5442            };
 5443
 5444            let mut auto_indent_edits = Vec::new();
 5445            let mut edits = Vec::new();
 5446            for (edit, prevent_auto_indent) in edits_with_flags {
 5447                if prevent_auto_indent {
 5448                    edits.push(edit);
 5449                } else {
 5450                    auto_indent_edits.push(edit);
 5451                }
 5452            }
 5453            if !edits.is_empty() {
 5454                this.edit(edits, cx);
 5455            }
 5456            if !auto_indent_edits.is_empty() {
 5457                this.edit_with_autoindent(auto_indent_edits, cx);
 5458            }
 5459
 5460            let buffer = this.buffer.read(cx).snapshot(cx);
 5461            let new_selections = selection_info
 5462                .into_iter()
 5463                .map(|(extra_newline_inserted, new_selection)| {
 5464                    let mut cursor = new_selection.end.to_point(&buffer);
 5465                    if extra_newline_inserted {
 5466                        cursor.row -= 1;
 5467                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5468                    }
 5469                    new_selection.map(|_| cursor)
 5470                })
 5471                .collect();
 5472
 5473            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5474            this.refresh_edit_prediction(true, false, window, cx);
 5475            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5476                task.detach_and_log_err(cx);
 5477            }
 5478        });
 5479    }
 5480
 5481    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5482        if self.read_only(cx) {
 5483            return;
 5484        }
 5485
 5486        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5487
 5488        let buffer = self.buffer.read(cx);
 5489        let snapshot = buffer.snapshot(cx);
 5490
 5491        let mut edits = Vec::new();
 5492        let mut rows = Vec::new();
 5493
 5494        for (rows_inserted, selection) in self
 5495            .selections
 5496            .all_adjusted(&self.display_snapshot(cx))
 5497            .into_iter()
 5498            .enumerate()
 5499        {
 5500            let cursor = selection.head();
 5501            let row = cursor.row;
 5502
 5503            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5504
 5505            let newline = "\n".to_string();
 5506            edits.push((start_of_line..start_of_line, newline));
 5507
 5508            rows.push(row + rows_inserted as u32);
 5509        }
 5510
 5511        self.transact(window, cx, |editor, window, cx| {
 5512            editor.edit(edits, cx);
 5513
 5514            editor.change_selections(Default::default(), window, cx, |s| {
 5515                let mut index = 0;
 5516                s.move_cursors_with(&mut |map, _, _| {
 5517                    let row = rows[index];
 5518                    index += 1;
 5519
 5520                    let point = Point::new(row, 0);
 5521                    let boundary = map.next_line_boundary(point).1;
 5522                    let clipped = map.clip_point(boundary, Bias::Left);
 5523
 5524                    (clipped, SelectionGoal::None)
 5525                });
 5526            });
 5527
 5528            let mut indent_edits = Vec::new();
 5529            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5530            for row in rows {
 5531                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5532                for (row, indent) in indents {
 5533                    if indent.len == 0 {
 5534                        continue;
 5535                    }
 5536
 5537                    let text = match indent.kind {
 5538                        IndentKind::Space => " ".repeat(indent.len as usize),
 5539                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5540                    };
 5541                    let point = Point::new(row.0, 0);
 5542                    indent_edits.push((point..point, text));
 5543                }
 5544            }
 5545            editor.edit(indent_edits, cx);
 5546            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5547                format.detach_and_log_err(cx);
 5548            }
 5549        });
 5550    }
 5551
 5552    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5553        if self.read_only(cx) {
 5554            return;
 5555        }
 5556
 5557        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5558
 5559        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5560        let mut rows = Vec::new();
 5561        let mut rows_inserted = 0;
 5562
 5563        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5564            let cursor = selection.head();
 5565            let row = cursor.row;
 5566
 5567            let point = Point::new(row, 0);
 5568            let Some((buffer_handle, buffer_point)) =
 5569                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5570            else {
 5571                continue;
 5572            };
 5573
 5574            buffer_edits
 5575                .entry(buffer_handle.entity_id())
 5576                .or_insert_with(|| (buffer_handle, Vec::new()))
 5577                .1
 5578                .push(buffer_point);
 5579
 5580            rows_inserted += 1;
 5581            rows.push(row + rows_inserted);
 5582        }
 5583
 5584        self.transact(window, cx, |editor, window, cx| {
 5585            for (_, (buffer_handle, points)) in &buffer_edits {
 5586                buffer_handle.update(cx, |buffer, cx| {
 5587                    let edits: Vec<_> = points
 5588                        .iter()
 5589                        .map(|point| {
 5590                            let target = Point::new(point.row + 1, 0);
 5591                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5592                            (start_of_line..start_of_line, "\n")
 5593                        })
 5594                        .collect();
 5595                    buffer.edit(edits, None, cx);
 5596                });
 5597            }
 5598
 5599            editor.change_selections(Default::default(), window, cx, |s| {
 5600                let mut index = 0;
 5601                s.move_cursors_with(&mut |map, _, _| {
 5602                    let row = rows[index];
 5603                    index += 1;
 5604
 5605                    let point = Point::new(row, 0);
 5606                    let boundary = map.next_line_boundary(point).1;
 5607                    let clipped = map.clip_point(boundary, Bias::Left);
 5608
 5609                    (clipped, SelectionGoal::None)
 5610                });
 5611            });
 5612
 5613            let mut indent_edits = Vec::new();
 5614            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5615            for row in rows {
 5616                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5617                for (row, indent) in indents {
 5618                    if indent.len == 0 {
 5619                        continue;
 5620                    }
 5621
 5622                    let text = match indent.kind {
 5623                        IndentKind::Space => " ".repeat(indent.len as usize),
 5624                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5625                    };
 5626                    let point = Point::new(row.0, 0);
 5627                    indent_edits.push((point..point, text));
 5628                }
 5629            }
 5630            editor.edit(indent_edits, cx);
 5631            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5632                format.detach_and_log_err(cx);
 5633            }
 5634        });
 5635    }
 5636
 5637    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5638        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5639            original_indent_columns: Vec::new(),
 5640        });
 5641        self.replace_selections(text, autoindent, window, cx, false);
 5642    }
 5643
 5644    /// Replaces the editor's selections with the provided `text`, applying the
 5645    /// given `autoindent_mode` (`None` will skip autoindentation).
 5646    ///
 5647    /// Early returns if the editor is in read-only mode, without applying any
 5648    /// edits.
 5649    fn replace_selections(
 5650        &mut self,
 5651        text: &str,
 5652        autoindent_mode: Option<AutoindentMode>,
 5653        window: &mut Window,
 5654        cx: &mut Context<Self>,
 5655        apply_linked_edits: bool,
 5656    ) {
 5657        if self.read_only(cx) {
 5658            return;
 5659        }
 5660
 5661        let text: Arc<str> = text.into();
 5662        self.transact(window, cx, |this, window, cx| {
 5663            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5664            let linked_edits = if apply_linked_edits {
 5665                this.linked_edits_for_selections(text.clone(), cx)
 5666            } else {
 5667                LinkedEdits::new()
 5668            };
 5669
 5670            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5671                let anchors = {
 5672                    let snapshot = buffer.read(cx);
 5673                    old_selections
 5674                        .iter()
 5675                        .map(|s| {
 5676                            let anchor = snapshot.anchor_after(s.head());
 5677                            s.map(|_| anchor)
 5678                        })
 5679                        .collect::<Vec<_>>()
 5680                };
 5681                buffer.edit(
 5682                    old_selections
 5683                        .iter()
 5684                        .map(|s| (s.start..s.end, text.clone())),
 5685                    autoindent_mode,
 5686                    cx,
 5687                );
 5688                anchors
 5689            });
 5690
 5691            linked_edits.apply(cx);
 5692
 5693            this.change_selections(Default::default(), window, cx, |s| {
 5694                s.select_anchors(selection_anchors);
 5695            });
 5696
 5697            if apply_linked_edits {
 5698                refresh_linked_ranges(this, window, cx);
 5699            }
 5700
 5701            cx.notify();
 5702        });
 5703    }
 5704
 5705    /// Collects linked edits for the current selections, pairing each linked
 5706    /// range with `text`.
 5707    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5708        let multibuffer_snapshot = self.buffer().read(cx).snapshot(cx);
 5709        let mut linked_edits = LinkedEdits::new();
 5710        if !self.linked_edit_ranges.is_empty() {
 5711            for selection in self.selections.disjoint_anchors() {
 5712                let Some((_, range)) =
 5713                    multibuffer_snapshot.anchor_range_to_buffer_anchor_range(selection.range())
 5714                else {
 5715                    continue;
 5716                };
 5717                linked_edits.push(self, range, text.clone(), cx);
 5718            }
 5719        }
 5720        linked_edits
 5721    }
 5722
 5723    /// Deletes the content covered by the current selections and applies
 5724    /// linked edits.
 5725    pub fn delete_selections_with_linked_edits(
 5726        &mut self,
 5727        window: &mut Window,
 5728        cx: &mut Context<Self>,
 5729    ) {
 5730        self.replace_selections("", None, window, cx, true);
 5731    }
 5732
 5733    #[cfg(any(test, feature = "test-support"))]
 5734    pub fn set_linked_edit_ranges_for_testing(
 5735        &mut self,
 5736        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5737        cx: &mut Context<Self>,
 5738    ) -> Option<()> {
 5739        let Some((buffer, _)) = self
 5740            .buffer
 5741            .read(cx)
 5742            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5743        else {
 5744            return None;
 5745        };
 5746        let buffer = buffer.read(cx);
 5747        let buffer_id = buffer.remote_id();
 5748        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5749        for (base_range, linked_ranges_points) in ranges {
 5750            let base_anchor =
 5751                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5752            let linked_anchors = linked_ranges_points
 5753                .into_iter()
 5754                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5755                .collect();
 5756            linked_ranges.push((base_anchor, linked_anchors));
 5757        }
 5758        let mut map = HashMap::default();
 5759        map.insert(buffer_id, linked_ranges);
 5760        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5761        Some(())
 5762    }
 5763
 5764    fn trigger_completion_on_input(
 5765        &mut self,
 5766        text: &str,
 5767        trigger_in_words: bool,
 5768        window: &mut Window,
 5769        cx: &mut Context<Self>,
 5770    ) {
 5771        let completions_source = self
 5772            .context_menu
 5773            .borrow()
 5774            .as_ref()
 5775            .and_then(|menu| match menu {
 5776                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5777                CodeContextMenu::CodeActions(_) => None,
 5778            });
 5779
 5780        match completions_source {
 5781            Some(CompletionsMenuSource::Words { .. }) => {
 5782                self.open_or_update_completions_menu(
 5783                    Some(CompletionsMenuSource::Words {
 5784                        ignore_threshold: false,
 5785                    }),
 5786                    None,
 5787                    trigger_in_words,
 5788                    window,
 5789                    cx,
 5790                );
 5791            }
 5792            _ => self.open_or_update_completions_menu(
 5793                None,
 5794                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5795                true,
 5796                window,
 5797                cx,
 5798            ),
 5799        }
 5800    }
 5801
 5802    /// If any empty selections is touching the start of its innermost containing autoclose
 5803    /// region, expand it to select the brackets.
 5804    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5805        let selections = self
 5806            .selections
 5807            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5808        let buffer = self.buffer.read(cx).read(cx);
 5809        let new_selections = self
 5810            .selections_with_autoclose_regions(selections, &buffer)
 5811            .map(|(mut selection, region)| {
 5812                if !selection.is_empty() {
 5813                    return selection;
 5814                }
 5815
 5816                if let Some(region) = region {
 5817                    let mut range = region.range.to_offset(&buffer);
 5818                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5819                        range.start -= region.pair.start.len();
 5820                        if buffer.contains_str_at(range.start, &region.pair.start)
 5821                            && buffer.contains_str_at(range.end, &region.pair.end)
 5822                        {
 5823                            range.end += region.pair.end.len();
 5824                            selection.start = range.start;
 5825                            selection.end = range.end;
 5826
 5827                            return selection;
 5828                        }
 5829                    }
 5830                }
 5831
 5832                let always_treat_brackets_as_autoclosed = buffer
 5833                    .language_settings_at(selection.start, cx)
 5834                    .always_treat_brackets_as_autoclosed;
 5835
 5836                if !always_treat_brackets_as_autoclosed {
 5837                    return selection;
 5838                }
 5839
 5840                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5841                    for (pair, enabled) in scope.brackets() {
 5842                        if !enabled || !pair.close {
 5843                            continue;
 5844                        }
 5845
 5846                        if buffer.contains_str_at(selection.start, &pair.end) {
 5847                            let pair_start_len = pair.start.len();
 5848                            if buffer.contains_str_at(
 5849                                selection.start.saturating_sub_usize(pair_start_len),
 5850                                &pair.start,
 5851                            ) {
 5852                                selection.start -= pair_start_len;
 5853                                selection.end += pair.end.len();
 5854
 5855                                return selection;
 5856                            }
 5857                        }
 5858                    }
 5859                }
 5860
 5861                selection
 5862            })
 5863            .collect();
 5864
 5865        drop(buffer);
 5866        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5867            selections.select(new_selections)
 5868        });
 5869    }
 5870
 5871    /// Iterate the given selections, and for each one, find the smallest surrounding
 5872    /// autoclose region. This uses the ordering of the selections and the autoclose
 5873    /// regions to avoid repeated comparisons.
 5874    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5875        &'a self,
 5876        selections: impl IntoIterator<Item = Selection<D>>,
 5877        buffer: &'a MultiBufferSnapshot,
 5878    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5879        let mut i = 0;
 5880        let mut regions = self.autoclose_regions.as_slice();
 5881        selections.into_iter().map(move |selection| {
 5882            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5883
 5884            let mut enclosing = None;
 5885            while let Some(pair_state) = regions.get(i) {
 5886                if pair_state.range.end.to_offset(buffer) < range.start {
 5887                    regions = &regions[i + 1..];
 5888                    i = 0;
 5889                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5890                    break;
 5891                } else {
 5892                    if pair_state.selection_id == selection.id {
 5893                        enclosing = Some(pair_state);
 5894                    }
 5895                    i += 1;
 5896                }
 5897            }
 5898
 5899            (selection, enclosing)
 5900        })
 5901    }
 5902
 5903    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5904    fn invalidate_autoclose_regions(
 5905        &mut self,
 5906        mut selections: &[Selection<Anchor>],
 5907        buffer: &MultiBufferSnapshot,
 5908    ) {
 5909        self.autoclose_regions.retain(|state| {
 5910            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5911                return false;
 5912            }
 5913
 5914            let mut i = 0;
 5915            while let Some(selection) = selections.get(i) {
 5916                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5917                    selections = &selections[1..];
 5918                    continue;
 5919                }
 5920                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5921                    break;
 5922                }
 5923                if selection.id == state.selection_id {
 5924                    return true;
 5925                } else {
 5926                    i += 1;
 5927                }
 5928            }
 5929            false
 5930        });
 5931    }
 5932
 5933    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5934        let offset = position.to_offset(buffer);
 5935        let (word_range, kind) =
 5936            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5937        if offset > word_range.start && kind == Some(CharKind::Word) {
 5938            Some(
 5939                buffer
 5940                    .text_for_range(word_range.start..offset)
 5941                    .collect::<String>(),
 5942            )
 5943        } else {
 5944            None
 5945        }
 5946    }
 5947
 5948    pub fn is_lsp_relevant(&self, file: Option<&Arc<dyn language::File>>, cx: &App) -> bool {
 5949        let Some(project) = self.project() else {
 5950            return false;
 5951        };
 5952        let Some(buffer_file) = project::File::from_dyn(file) else {
 5953            return false;
 5954        };
 5955        let Some(entry_id) = buffer_file.project_entry_id() else {
 5956            return false;
 5957        };
 5958        let project = project.read(cx);
 5959        let Some(buffer_worktree) = project.worktree_for_id(buffer_file.worktree_id(cx), cx) else {
 5960            return false;
 5961        };
 5962        let Some(worktree_entry) = buffer_worktree.read(cx).entry_for_id(entry_id) else {
 5963            return false;
 5964        };
 5965        !worktree_entry.is_ignored
 5966    }
 5967
 5968    pub fn visible_buffers(&self, cx: &mut Context<Editor>) -> Vec<Entity<Buffer>> {
 5969        let display_snapshot = self.display_snapshot(cx);
 5970        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5971        let multi_buffer = self.buffer().read(cx);
 5972        display_snapshot
 5973            .buffer_snapshot()
 5974            .range_to_buffer_ranges(visible_range)
 5975            .into_iter()
 5976            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5977            .filter_map(|(buffer_snapshot, _, _)| multi_buffer.buffer(buffer_snapshot.remote_id()))
 5978            .collect()
 5979    }
 5980
 5981    pub fn visible_buffer_ranges(
 5982        &self,
 5983        cx: &mut Context<Editor>,
 5984    ) -> Vec<(
 5985        BufferSnapshot,
 5986        Range<BufferOffset>,
 5987        ExcerptRange<text::Anchor>,
 5988    )> {
 5989        let display_snapshot = self.display_snapshot(cx);
 5990        let visible_range = self.multi_buffer_visible_range(&display_snapshot, cx);
 5991        display_snapshot
 5992            .buffer_snapshot()
 5993            .range_to_buffer_ranges(visible_range)
 5994            .into_iter()
 5995            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5996            .collect()
 5997    }
 5998
 5999    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 6000        TextLayoutDetails {
 6001            text_system: window.text_system().clone(),
 6002            editor_style: self.style.clone().unwrap(),
 6003            rem_size: window.rem_size(),
 6004            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 6005            visible_rows: self.visible_line_count(),
 6006            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 6007        }
 6008    }
 6009
 6010    fn trigger_on_type_formatting(
 6011        &self,
 6012        input: String,
 6013        window: &mut Window,
 6014        cx: &mut Context<Self>,
 6015    ) -> Option<Task<Result<()>>> {
 6016        if input.chars().count() != 1 {
 6017            return None;
 6018        }
 6019
 6020        let project = self.project()?;
 6021        let position = self.selections.newest_anchor().head();
 6022        let (buffer, buffer_position) = self
 6023            .buffer
 6024            .read(cx)
 6025            .text_anchor_for_position(position, cx)?;
 6026
 6027        let settings = LanguageSettings::for_buffer_at(&buffer.read(cx), buffer_position, cx);
 6028        if !settings.use_on_type_format {
 6029            return None;
 6030        }
 6031
 6032        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 6033        // hence we do LSP request & edit on host side only — add formats to host's history.
 6034        let push_to_lsp_host_history = true;
 6035        // If this is not the host, append its history with new edits.
 6036        let push_to_client_history = project.read(cx).is_via_collab();
 6037
 6038        let on_type_formatting = project.update(cx, |project, cx| {
 6039            project.on_type_format(
 6040                buffer.clone(),
 6041                buffer_position,
 6042                input,
 6043                push_to_lsp_host_history,
 6044                cx,
 6045            )
 6046        });
 6047        Some(cx.spawn_in(window, async move |editor, cx| {
 6048            if let Some(transaction) = on_type_formatting.await? {
 6049                if push_to_client_history {
 6050                    buffer.update(cx, |buffer, _| {
 6051                        buffer.push_transaction(transaction, Instant::now());
 6052                        buffer.finalize_last_transaction();
 6053                    });
 6054                }
 6055                editor.update(cx, |editor, cx| {
 6056                    editor.refresh_document_highlights(cx);
 6057                })?;
 6058            }
 6059            Ok(())
 6060        }))
 6061    }
 6062
 6063    pub fn show_word_completions(
 6064        &mut self,
 6065        _: &ShowWordCompletions,
 6066        window: &mut Window,
 6067        cx: &mut Context<Self>,
 6068    ) {
 6069        self.open_or_update_completions_menu(
 6070            Some(CompletionsMenuSource::Words {
 6071                ignore_threshold: true,
 6072            }),
 6073            None,
 6074            false,
 6075            window,
 6076            cx,
 6077        );
 6078    }
 6079
 6080    pub fn show_completions(
 6081        &mut self,
 6082        _: &ShowCompletions,
 6083        window: &mut Window,
 6084        cx: &mut Context<Self>,
 6085    ) {
 6086        self.open_or_update_completions_menu(None, None, false, window, cx);
 6087    }
 6088
 6089    fn open_or_update_completions_menu(
 6090        &mut self,
 6091        requested_source: Option<CompletionsMenuSource>,
 6092        trigger: Option<String>,
 6093        trigger_in_words: bool,
 6094        window: &mut Window,
 6095        cx: &mut Context<Self>,
 6096    ) {
 6097        if self.pending_rename.is_some() {
 6098            return;
 6099        }
 6100
 6101        let completions_source = self
 6102            .context_menu
 6103            .borrow()
 6104            .as_ref()
 6105            .and_then(|menu| match menu {
 6106                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 6107                CodeContextMenu::CodeActions(_) => None,
 6108            });
 6109
 6110        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 6111
 6112        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 6113        // inserted and selected. To handle that case, the start of the selection is used so that
 6114        // the menu starts with all choices.
 6115        let position = self
 6116            .selections
 6117            .newest_anchor()
 6118            .start
 6119            .bias_right(&multibuffer_snapshot);
 6120
 6121        if position.diff_base_anchor().is_some() {
 6122            return;
 6123        }
 6124        let multibuffer_position = multibuffer_snapshot.anchor_before(position);
 6125        let Some((buffer_position, _)) =
 6126            multibuffer_snapshot.anchor_to_buffer_anchor(multibuffer_position)
 6127        else {
 6128            return;
 6129        };
 6130        let Some(buffer) = self.buffer.read(cx).buffer(buffer_position.buffer_id) else {
 6131            return;
 6132        };
 6133        let buffer_snapshot = buffer.read(cx).snapshot();
 6134
 6135        let menu_is_open = matches!(
 6136            self.context_menu.borrow().as_ref(),
 6137            Some(CodeContextMenu::Completions(_))
 6138        );
 6139
 6140        let language = buffer_snapshot
 6141            .language_at(buffer_position)
 6142            .map(|language| language.name());
 6143        let language_settings = multibuffer_snapshot.language_settings_at(multibuffer_position, cx);
 6144        let completion_settings = language_settings.completions.clone();
 6145
 6146        let show_completions_on_input = self
 6147            .show_completions_on_input_override
 6148            .unwrap_or(language_settings.show_completions_on_input);
 6149        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 6150            return;
 6151        }
 6152
 6153        let query: Option<Arc<String>> =
 6154            Self::completion_query(&multibuffer_snapshot, multibuffer_position)
 6155                .map(|query| query.into());
 6156
 6157        drop(multibuffer_snapshot);
 6158
 6159        // Hide the current completions menu when query is empty. Without this, cached
 6160        // completions from before the trigger char may be reused (#32774).
 6161        if query.is_none() && menu_is_open {
 6162            self.hide_context_menu(window, cx);
 6163        }
 6164
 6165        let mut ignore_word_threshold = false;
 6166        let provider = match requested_source {
 6167            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 6168            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 6169                ignore_word_threshold = ignore_threshold;
 6170                None
 6171            }
 6172            Some(CompletionsMenuSource::SnippetChoices)
 6173            | Some(CompletionsMenuSource::SnippetsOnly) => {
 6174                log::error!("bug: SnippetChoices requested_source is not handled");
 6175                None
 6176            }
 6177        };
 6178
 6179        let sort_completions = provider
 6180            .as_ref()
 6181            .is_some_and(|provider| provider.sort_completions());
 6182
 6183        let filter_completions = provider
 6184            .as_ref()
 6185            .is_none_or(|provider| provider.filter_completions());
 6186
 6187        let was_snippets_only = matches!(
 6188            completions_source,
 6189            Some(CompletionsMenuSource::SnippetsOnly)
 6190        );
 6191
 6192        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 6193            if filter_completions {
 6194                menu.filter(
 6195                    query.clone().unwrap_or_default(),
 6196                    buffer_position,
 6197                    &buffer,
 6198                    provider.clone(),
 6199                    window,
 6200                    cx,
 6201                );
 6202            }
 6203            // When `is_incomplete` is false, no need to re-query completions when the current query
 6204            // is a suffix of the initial query.
 6205            let was_complete = !menu.is_incomplete;
 6206            if was_complete && !was_snippets_only {
 6207                // If the new query is a suffix of the old query (typing more characters) and
 6208                // the previous result was complete, the existing completions can be filtered.
 6209                //
 6210                // Note that snippet completions are always complete.
 6211                let query_matches = match (&menu.initial_query, &query) {
 6212                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6213                    (None, _) => true,
 6214                    _ => false,
 6215                };
 6216                if query_matches {
 6217                    let position_matches = if menu.initial_position == position {
 6218                        true
 6219                    } else {
 6220                        let snapshot = self.buffer.read(cx).read(cx);
 6221                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6222                    };
 6223                    if position_matches {
 6224                        return;
 6225                    }
 6226                }
 6227            }
 6228        };
 6229
 6230        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6231            buffer_snapshot.surrounding_word(buffer_position, None)
 6232        {
 6233            let word_to_exclude = buffer_snapshot
 6234                .text_for_range(word_range.clone())
 6235                .collect::<String>();
 6236            (
 6237                buffer_snapshot.anchor_before(word_range.start)
 6238                    ..buffer_snapshot.anchor_after(buffer_position),
 6239                Some(word_to_exclude),
 6240            )
 6241        } else {
 6242            (buffer_position..buffer_position, None)
 6243        };
 6244
 6245        let show_completion_documentation = buffer_snapshot
 6246            .settings_at(buffer_position, cx)
 6247            .show_completion_documentation;
 6248
 6249        // The document can be large, so stay in reasonable bounds when searching for words,
 6250        // otherwise completion pop-up might be slow to appear.
 6251        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6252        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6253        let min_word_search = buffer_snapshot.clip_point(
 6254            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6255            Bias::Left,
 6256        );
 6257        let max_word_search = buffer_snapshot.clip_point(
 6258            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6259            Bias::Right,
 6260        );
 6261        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6262            ..buffer_snapshot.point_to_offset(max_word_search);
 6263
 6264        let skip_digits = query
 6265            .as_ref()
 6266            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6267
 6268        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6269            trigger.as_ref().is_none_or(|trigger| {
 6270                provider.is_completion_trigger(
 6271                    &buffer,
 6272                    buffer_position,
 6273                    trigger,
 6274                    trigger_in_words,
 6275                    cx,
 6276                )
 6277            })
 6278        });
 6279
 6280        let provider_responses = if let Some(provider) = &provider
 6281            && load_provider_completions
 6282        {
 6283            let trigger_character =
 6284                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6285            let completion_context = CompletionContext {
 6286                trigger_kind: match &trigger_character {
 6287                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6288                    None => CompletionTriggerKind::INVOKED,
 6289                },
 6290                trigger_character,
 6291            };
 6292
 6293            provider.completions(&buffer, buffer_position, completion_context, window, cx)
 6294        } else {
 6295            Task::ready(Ok(Vec::new()))
 6296        };
 6297
 6298        let load_word_completions = if !self.word_completions_enabled {
 6299            false
 6300        } else if requested_source
 6301            == Some(CompletionsMenuSource::Words {
 6302                ignore_threshold: true,
 6303            })
 6304        {
 6305            true
 6306        } else {
 6307            load_provider_completions
 6308                && completion_settings.words != WordsCompletionMode::Disabled
 6309                && (ignore_word_threshold || {
 6310                    let words_min_length = completion_settings.words_min_length;
 6311                    // check whether word has at least `words_min_length` characters
 6312                    let query_chars = query.iter().flat_map(|q| q.chars());
 6313                    query_chars.take(words_min_length).count() == words_min_length
 6314                })
 6315        };
 6316
 6317        let mut words = if load_word_completions {
 6318            cx.background_spawn({
 6319                let buffer_snapshot = buffer_snapshot.clone();
 6320                async move {
 6321                    buffer_snapshot.words_in_range(WordsQuery {
 6322                        fuzzy_contents: None,
 6323                        range: word_search_range,
 6324                        skip_digits,
 6325                    })
 6326                }
 6327            })
 6328        } else {
 6329            Task::ready(BTreeMap::default())
 6330        };
 6331
 6332        let snippets = if let Some(provider) = &provider
 6333            && provider.show_snippets()
 6334            && let Some(project) = self.project()
 6335        {
 6336            let char_classifier = buffer_snapshot
 6337                .char_classifier_at(buffer_position)
 6338                .scope_context(Some(CharScopeContext::Completion));
 6339            project.update(cx, |project, cx| {
 6340                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6341            })
 6342        } else {
 6343            Task::ready(Ok(CompletionResponse {
 6344                completions: Vec::new(),
 6345                display_options: Default::default(),
 6346                is_incomplete: false,
 6347            }))
 6348        };
 6349
 6350        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6351
 6352        let id = post_inc(&mut self.next_completion_id);
 6353        let task = cx.spawn_in(window, async move |editor, cx| {
 6354            let Ok(()) = editor.update(cx, |this, _| {
 6355                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6356            }) else {
 6357                return;
 6358            };
 6359
 6360            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6361            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6362            let mut completions = Vec::new();
 6363            let mut is_incomplete = false;
 6364            let mut display_options: Option<CompletionDisplayOptions> = None;
 6365            if let Some(provider_responses) = provider_responses.await.log_err()
 6366                && !provider_responses.is_empty()
 6367            {
 6368                for response in provider_responses {
 6369                    completions.extend(response.completions);
 6370                    is_incomplete = is_incomplete || response.is_incomplete;
 6371                    match display_options.as_mut() {
 6372                        None => {
 6373                            display_options = Some(response.display_options);
 6374                        }
 6375                        Some(options) => options.merge(&response.display_options),
 6376                    }
 6377                }
 6378                if completion_settings.words == WordsCompletionMode::Fallback {
 6379                    words = Task::ready(BTreeMap::default());
 6380                }
 6381            }
 6382            let display_options = display_options.unwrap_or_default();
 6383
 6384            let mut words = words.await;
 6385            if let Some(word_to_exclude) = &word_to_exclude {
 6386                words.remove(word_to_exclude);
 6387            }
 6388            for lsp_completion in &completions {
 6389                words.remove(&lsp_completion.new_text);
 6390            }
 6391            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6392                replace_range: word_replace_range.clone(),
 6393                new_text: word.clone(),
 6394                label: CodeLabel::plain(word, None),
 6395                match_start: None,
 6396                snippet_deduplication_key: None,
 6397                icon_path: None,
 6398                documentation: None,
 6399                source: CompletionSource::BufferWord {
 6400                    word_range,
 6401                    resolved: false,
 6402                },
 6403                insert_text_mode: Some(InsertTextMode::AS_IS),
 6404                confirm: None,
 6405            }));
 6406
 6407            completions.extend(
 6408                snippets
 6409                    .await
 6410                    .into_iter()
 6411                    .flat_map(|response| response.completions),
 6412            );
 6413
 6414            let menu = if completions.is_empty() {
 6415                None
 6416            } else {
 6417                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6418                    let languages = editor
 6419                        .workspace
 6420                        .as_ref()
 6421                        .and_then(|(workspace, _)| workspace.upgrade())
 6422                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6423                    let menu = CompletionsMenu::new(
 6424                        id,
 6425                        requested_source.unwrap_or(if load_provider_completions {
 6426                            CompletionsMenuSource::Normal
 6427                        } else {
 6428                            CompletionsMenuSource::SnippetsOnly
 6429                        }),
 6430                        sort_completions,
 6431                        show_completion_documentation,
 6432                        position,
 6433                        query.clone(),
 6434                        is_incomplete,
 6435                        buffer.clone(),
 6436                        completions.into(),
 6437                        editor
 6438                            .context_menu()
 6439                            .borrow_mut()
 6440                            .as_ref()
 6441                            .map(|menu| menu.primary_scroll_handle()),
 6442                        display_options,
 6443                        snippet_sort_order,
 6444                        languages,
 6445                        language,
 6446                        cx,
 6447                    );
 6448
 6449                    let query = if filter_completions { query } else { None };
 6450                    let matches_task = menu.do_async_filtering(
 6451                        query.unwrap_or_default(),
 6452                        buffer_position,
 6453                        &buffer,
 6454                        cx,
 6455                    );
 6456                    (menu, matches_task)
 6457                }) else {
 6458                    return;
 6459                };
 6460
 6461                let matches = matches_task.await;
 6462
 6463                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6464                    // Newer menu already set, so exit.
 6465                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6466                        editor.context_menu.borrow().as_ref()
 6467                        && prev_menu.id > id
 6468                    {
 6469                        return;
 6470                    };
 6471
 6472                    // Only valid to take prev_menu because either the new menu is immediately set
 6473                    // below, or the menu is hidden.
 6474                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6475                        editor.context_menu.borrow_mut().take()
 6476                    {
 6477                        let position_matches =
 6478                            if prev_menu.initial_position == menu.initial_position {
 6479                                true
 6480                            } else {
 6481                                let snapshot = editor.buffer.read(cx).read(cx);
 6482                                prev_menu.initial_position.to_offset(&snapshot)
 6483                                    == menu.initial_position.to_offset(&snapshot)
 6484                            };
 6485                        if position_matches {
 6486                            // Preserve markdown cache before `set_filter_results` because it will
 6487                            // try to populate the documentation cache.
 6488                            menu.preserve_markdown_cache(prev_menu);
 6489                        }
 6490                    };
 6491
 6492                    menu.set_filter_results(matches, provider, window, cx);
 6493                }) else {
 6494                    return;
 6495                };
 6496
 6497                menu.visible().then_some(menu)
 6498            };
 6499
 6500            editor
 6501                .update_in(cx, |editor, window, cx| {
 6502                    if editor.focus_handle.is_focused(window)
 6503                        && let Some(menu) = menu
 6504                    {
 6505                        *editor.context_menu.borrow_mut() =
 6506                            Some(CodeContextMenu::Completions(menu));
 6507
 6508                        crate::hover_popover::hide_hover(editor, cx);
 6509                        if editor.show_edit_predictions_in_menu() {
 6510                            editor.update_visible_edit_prediction(window, cx);
 6511                        } else {
 6512                            editor
 6513                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6514                        }
 6515
 6516                        cx.notify();
 6517                        return;
 6518                    }
 6519
 6520                    if editor.completion_tasks.len() <= 1 {
 6521                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6522                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6523                        // If it was already hidden and we don't show edit predictions in the menu,
 6524                        // we should also show the edit prediction when available.
 6525                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6526                            editor.update_visible_edit_prediction(window, cx);
 6527                        }
 6528                    }
 6529                })
 6530                .ok();
 6531        });
 6532
 6533        self.completion_tasks.push((id, task));
 6534    }
 6535
 6536    #[cfg(any(test, feature = "test-support"))]
 6537    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6538        let menu = self.context_menu.borrow();
 6539        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6540            let completions = menu.completions.borrow();
 6541            Some(completions.to_vec())
 6542        } else {
 6543            None
 6544        }
 6545    }
 6546
 6547    pub fn with_completions_menu_matching_id<R>(
 6548        &self,
 6549        id: CompletionId,
 6550        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6551    ) -> R {
 6552        let mut context_menu = self.context_menu.borrow_mut();
 6553        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6554            return f(None);
 6555        };
 6556        if completions_menu.id != id {
 6557            return f(None);
 6558        }
 6559        f(Some(completions_menu))
 6560    }
 6561
 6562    pub fn confirm_completion(
 6563        &mut self,
 6564        action: &ConfirmCompletion,
 6565        window: &mut Window,
 6566        cx: &mut Context<Self>,
 6567    ) -> Option<Task<Result<()>>> {
 6568        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6569        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6570    }
 6571
 6572    pub fn confirm_completion_insert(
 6573        &mut self,
 6574        _: &ConfirmCompletionInsert,
 6575        window: &mut Window,
 6576        cx: &mut Context<Self>,
 6577    ) -> Option<Task<Result<()>>> {
 6578        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6579        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6580    }
 6581
 6582    pub fn confirm_completion_replace(
 6583        &mut self,
 6584        _: &ConfirmCompletionReplace,
 6585        window: &mut Window,
 6586        cx: &mut Context<Self>,
 6587    ) -> Option<Task<Result<()>>> {
 6588        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6589        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6590    }
 6591
 6592    pub fn compose_completion(
 6593        &mut self,
 6594        action: &ComposeCompletion,
 6595        window: &mut Window,
 6596        cx: &mut Context<Self>,
 6597    ) -> Option<Task<Result<()>>> {
 6598        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6599        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6600    }
 6601
 6602    fn do_completion(
 6603        &mut self,
 6604        item_ix: Option<usize>,
 6605        intent: CompletionIntent,
 6606        window: &mut Window,
 6607        cx: &mut Context<Editor>,
 6608    ) -> Option<Task<Result<()>>> {
 6609        use language::ToOffset as _;
 6610
 6611        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6612        else {
 6613            return None;
 6614        };
 6615
 6616        let candidate_id = {
 6617            let entries = completions_menu.entries.borrow();
 6618            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6619            if self.show_edit_predictions_in_menu() {
 6620                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6621            }
 6622            mat.candidate_id
 6623        };
 6624
 6625        let completion = completions_menu
 6626            .completions
 6627            .borrow()
 6628            .get(candidate_id)?
 6629            .clone();
 6630        cx.stop_propagation();
 6631
 6632        let buffer_handle = completions_menu.buffer.clone();
 6633        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
 6634        let (initial_position, _) =
 6635            multibuffer_snapshot.anchor_to_buffer_anchor(completions_menu.initial_position)?;
 6636
 6637        let CompletionEdit {
 6638            new_text,
 6639            snippet,
 6640            replace_range,
 6641        } = process_completion_for_edit(&completion, intent, &buffer_handle, &initial_position, cx);
 6642
 6643        let buffer = buffer_handle.read(cx).snapshot();
 6644        let newest_selection = self.selections.newest_anchor();
 6645
 6646        let Some(replace_range_multibuffer) =
 6647            multibuffer_snapshot.buffer_anchor_range_to_anchor_range(replace_range.clone())
 6648        else {
 6649            return None;
 6650        };
 6651
 6652        let Some((buffer_snapshot, newest_range_buffer)) =
 6653            multibuffer_snapshot.anchor_range_to_buffer_anchor_range(newest_selection.range())
 6654        else {
 6655            return None;
 6656        };
 6657
 6658        let old_text = buffer
 6659            .text_for_range(replace_range.clone())
 6660            .collect::<String>();
 6661        let lookbehind = newest_range_buffer
 6662            .start
 6663            .to_offset(buffer_snapshot)
 6664            .saturating_sub(replace_range.start.to_offset(&buffer_snapshot));
 6665        let lookahead = replace_range
 6666            .end
 6667            .to_offset(&buffer_snapshot)
 6668            .saturating_sub(newest_range_buffer.end.to_offset(&buffer));
 6669        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6670        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6671
 6672        let selections = self
 6673            .selections
 6674            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6675        let mut ranges = Vec::new();
 6676        let mut all_commit_ranges = Vec::new();
 6677        let mut linked_edits = LinkedEdits::new();
 6678
 6679        let text: Arc<str> = new_text.clone().into();
 6680        for selection in &selections {
 6681            let range = if selection.id == newest_selection.id {
 6682                replace_range_multibuffer.clone()
 6683            } else {
 6684                let mut range = selection.range();
 6685
 6686                // if prefix is present, don't duplicate it
 6687                if multibuffer_snapshot
 6688                    .contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix)
 6689                {
 6690                    range.start = range.start.saturating_sub_usize(lookbehind);
 6691
 6692                    // if suffix is also present, mimic the newest cursor and replace it
 6693                    if selection.id != newest_selection.id
 6694                        && multibuffer_snapshot.contains_str_at(range.end, suffix)
 6695                    {
 6696                        range.end += lookahead;
 6697                    }
 6698                }
 6699                range.to_anchors(&multibuffer_snapshot)
 6700            };
 6701
 6702            ranges.push(range.clone());
 6703
 6704            let start_anchor = multibuffer_snapshot.anchor_before(range.start);
 6705            let end_anchor = multibuffer_snapshot.anchor_after(range.end);
 6706
 6707            if let Some((buffer_snapshot_2, anchor_range)) =
 6708                multibuffer_snapshot.anchor_range_to_buffer_anchor_range(start_anchor..end_anchor)
 6709                && buffer_snapshot_2.remote_id() == buffer_snapshot.remote_id()
 6710            {
 6711                all_commit_ranges.push(anchor_range.clone());
 6712                if !self.linked_edit_ranges.is_empty() {
 6713                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 6714                }
 6715            }
 6716        }
 6717
 6718        let common_prefix_len = old_text
 6719            .chars()
 6720            .zip(new_text.chars())
 6721            .take_while(|(a, b)| a == b)
 6722            .map(|(a, _)| a.len_utf8())
 6723            .sum::<usize>();
 6724
 6725        cx.emit(EditorEvent::InputHandled {
 6726            utf16_range_to_replace: None,
 6727            text: new_text[common_prefix_len..].into(),
 6728        });
 6729
 6730        let tx_id = self.transact(window, cx, |editor, window, cx| {
 6731            if let Some(mut snippet) = snippet {
 6732                snippet.text = new_text.to_string();
 6733                let offset_ranges = ranges
 6734                    .iter()
 6735                    .map(|range| range.to_offset(&multibuffer_snapshot))
 6736                    .collect::<Vec<_>>();
 6737                editor
 6738                    .insert_snippet(&offset_ranges, snippet, window, cx)
 6739                    .log_err();
 6740            } else {
 6741                editor.buffer.update(cx, |multi_buffer, cx| {
 6742                    let auto_indent = match completion.insert_text_mode {
 6743                        Some(InsertTextMode::AS_IS) => None,
 6744                        _ => editor.autoindent_mode.clone(),
 6745                    };
 6746                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6747                    multi_buffer.edit(edits, auto_indent, cx);
 6748                });
 6749            }
 6750            linked_edits.apply(cx);
 6751            editor.refresh_edit_prediction(true, false, window, cx);
 6752        });
 6753        self.invalidate_autoclose_regions(
 6754            &self.selections.disjoint_anchors_arc(),
 6755            &multibuffer_snapshot,
 6756        );
 6757
 6758        let show_new_completions_on_confirm = completion
 6759            .confirm
 6760            .as_ref()
 6761            .is_some_and(|confirm| confirm(intent, window, cx));
 6762        if show_new_completions_on_confirm {
 6763            self.open_or_update_completions_menu(None, None, false, window, cx);
 6764        }
 6765
 6766        let provider = self.completion_provider.as_ref()?;
 6767
 6768        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6769        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6770            let CompletionSource::Lsp {
 6771                lsp_completion,
 6772                server_id,
 6773                ..
 6774            } = &completion.source
 6775            else {
 6776                return None;
 6777            };
 6778            let lsp_command = lsp_completion.command.as_ref()?;
 6779            let available_commands = lsp_store
 6780                .read(cx)
 6781                .lsp_server_capabilities
 6782                .get(server_id)
 6783                .and_then(|server_capabilities| {
 6784                    server_capabilities
 6785                        .execute_command_provider
 6786                        .as_ref()
 6787                        .map(|options| options.commands.as_slice())
 6788                })?;
 6789            if available_commands.contains(&lsp_command.command) {
 6790                Some(CodeAction {
 6791                    server_id: *server_id,
 6792                    range: language::Anchor::min_min_range_for_buffer(buffer.remote_id()),
 6793                    lsp_action: LspAction::Command(lsp_command.clone()),
 6794                    resolved: false,
 6795                })
 6796            } else {
 6797                None
 6798            }
 6799        });
 6800
 6801        drop(completion);
 6802        let apply_edits = provider.apply_additional_edits_for_completion(
 6803            buffer_handle.clone(),
 6804            completions_menu.completions.clone(),
 6805            candidate_id,
 6806            true,
 6807            all_commit_ranges,
 6808            cx,
 6809        );
 6810
 6811        let editor_settings = EditorSettings::get_global(cx);
 6812        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6813            // After the code completion is finished, users often want to know what signatures are needed.
 6814            // so we should automatically call signature_help
 6815            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6816        }
 6817
 6818        Some(cx.spawn_in(window, async move |editor, cx| {
 6819            let additional_edits_tx = apply_edits.await?;
 6820
 6821            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6822                let title = command.lsp_action.title().to_owned();
 6823                let project_transaction = lsp_store
 6824                    .update(cx, |lsp_store, cx| {
 6825                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6826                    })
 6827                    .await
 6828                    .context("applying post-completion command")?;
 6829                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6830                    Self::open_project_transaction(
 6831                        &editor,
 6832                        workspace.downgrade(),
 6833                        project_transaction,
 6834                        title,
 6835                        cx,
 6836                    )
 6837                    .await?;
 6838                }
 6839            }
 6840
 6841            if let Some(tx_id) = tx_id
 6842                && let Some(additional_edits_tx) = additional_edits_tx
 6843            {
 6844                editor
 6845                    .update(cx, |editor, cx| {
 6846                        editor.buffer.update(cx, |buffer, cx| {
 6847                            buffer.merge_transactions(additional_edits_tx.id, tx_id, cx)
 6848                        });
 6849                    })
 6850                    .context("merge transactions")?;
 6851            }
 6852
 6853            Ok(())
 6854        }))
 6855    }
 6856
 6857    pub fn toggle_code_actions(
 6858        &mut self,
 6859        action: &ToggleCodeActions,
 6860        window: &mut Window,
 6861        cx: &mut Context<Self>,
 6862    ) {
 6863        let quick_launch = action.quick_launch;
 6864        let mut context_menu = self.context_menu.borrow_mut();
 6865        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6866            if code_actions.deployed_from == action.deployed_from {
 6867                // Toggle if we're selecting the same one
 6868                *context_menu = None;
 6869                cx.notify();
 6870                return;
 6871            } else {
 6872                // Otherwise, clear it and start a new one
 6873                *context_menu = None;
 6874                cx.notify();
 6875            }
 6876        }
 6877        drop(context_menu);
 6878        let snapshot = self.snapshot(window, cx);
 6879        let deployed_from = action.deployed_from.clone();
 6880        let action = action.clone();
 6881        self.completion_tasks.clear();
 6882        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6883
 6884        let multibuffer_point = match &action.deployed_from {
 6885            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6886                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6887            }
 6888            _ => self
 6889                .selections
 6890                .newest::<Point>(&snapshot.display_snapshot)
 6891                .head(),
 6892        };
 6893        let Some((buffer, buffer_row)) = snapshot
 6894            .buffer_snapshot()
 6895            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6896            .and_then(|(buffer_snapshot, range)| {
 6897                self.buffer()
 6898                    .read(cx)
 6899                    .buffer(buffer_snapshot.remote_id())
 6900                    .map(|buffer| (buffer, range.start.row))
 6901            })
 6902        else {
 6903            return;
 6904        };
 6905        let buffer_id = buffer.read(cx).remote_id();
 6906        let tasks = self
 6907            .runnables
 6908            .runnables((buffer_id, buffer_row))
 6909            .map(|t| Arc::new(t.to_owned()));
 6910
 6911        if !self.focus_handle.is_focused(window) {
 6912            return;
 6913        }
 6914        let project = self.project.clone();
 6915
 6916        let code_actions_task = match deployed_from {
 6917            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6918            _ => self.code_actions(buffer_row, window, cx),
 6919        };
 6920
 6921        let runnable_task = match deployed_from {
 6922            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6923            _ => {
 6924                let mut task_context_task = Task::ready(None);
 6925                if let Some(tasks) = &tasks
 6926                    && let Some(project) = project
 6927                {
 6928                    task_context_task =
 6929                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6930                }
 6931
 6932                cx.spawn_in(window, {
 6933                    let buffer = buffer.clone();
 6934                    async move |editor, cx| {
 6935                        let task_context = task_context_task.await;
 6936
 6937                        let resolved_tasks =
 6938                            tasks
 6939                                .zip(task_context.clone())
 6940                                .map(|(tasks, task_context)| ResolvedTasks {
 6941                                    templates: tasks.resolve(&task_context).collect(),
 6942                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6943                                        multibuffer_point.row,
 6944                                        tasks.column,
 6945                                    )),
 6946                                });
 6947                        let debug_scenarios = editor
 6948                            .update(cx, |editor, cx| {
 6949                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6950                            })?
 6951                            .await;
 6952                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6953                    }
 6954                })
 6955            }
 6956        };
 6957
 6958        cx.spawn_in(window, async move |editor, cx| {
 6959            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6960            let code_actions = code_actions_task.await;
 6961            let spawn_straight_away = quick_launch
 6962                && resolved_tasks
 6963                    .as_ref()
 6964                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6965                && code_actions
 6966                    .as_ref()
 6967                    .is_none_or(|actions| actions.is_empty())
 6968                && debug_scenarios.is_empty();
 6969
 6970            editor.update_in(cx, |editor, window, cx| {
 6971                crate::hover_popover::hide_hover(editor, cx);
 6972                let actions = CodeActionContents::new(
 6973                    resolved_tasks,
 6974                    code_actions,
 6975                    debug_scenarios,
 6976                    task_context.unwrap_or_default(),
 6977                );
 6978
 6979                // Don't show the menu if there are no actions available
 6980                if actions.is_empty() {
 6981                    cx.notify();
 6982                    return Task::ready(Ok(()));
 6983                }
 6984
 6985                *editor.context_menu.borrow_mut() =
 6986                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6987                        buffer,
 6988                        actions,
 6989                        selected_item: Default::default(),
 6990                        scroll_handle: UniformListScrollHandle::default(),
 6991                        deployed_from,
 6992                    }));
 6993                cx.notify();
 6994                if spawn_straight_away
 6995                    && let Some(task) = editor.confirm_code_action(
 6996                        &ConfirmCodeAction { item_ix: Some(0) },
 6997                        window,
 6998                        cx,
 6999                    )
 7000                {
 7001                    return task;
 7002                }
 7003
 7004                Task::ready(Ok(()))
 7005            })
 7006        })
 7007        .detach_and_log_err(cx);
 7008    }
 7009
 7010    fn debug_scenarios(
 7011        &mut self,
 7012        resolved_tasks: &Option<ResolvedTasks>,
 7013        buffer: &Entity<Buffer>,
 7014        cx: &mut App,
 7015    ) -> Task<Vec<task::DebugScenario>> {
 7016        maybe!({
 7017            let project = self.project()?;
 7018            let dap_store = project.read(cx).dap_store();
 7019            let mut scenarios = vec![];
 7020            let resolved_tasks = resolved_tasks.as_ref()?;
 7021            let buffer = buffer.read(cx);
 7022            let language = buffer.language()?;
 7023            let debug_adapter = LanguageSettings::for_buffer(&buffer, cx)
 7024                .debuggers
 7025                .first()
 7026                .map(SharedString::from)
 7027                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 7028
 7029            dap_store.update(cx, |dap_store, cx| {
 7030                for (_, task) in &resolved_tasks.templates {
 7031                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 7032                        task.original_task().clone(),
 7033                        debug_adapter.clone().into(),
 7034                        task.display_label().to_owned().into(),
 7035                        cx,
 7036                    );
 7037                    scenarios.push(maybe_scenario);
 7038                }
 7039            });
 7040            Some(cx.background_spawn(async move {
 7041                futures::future::join_all(scenarios)
 7042                    .await
 7043                    .into_iter()
 7044                    .flatten()
 7045                    .collect::<Vec<_>>()
 7046            }))
 7047        })
 7048        .unwrap_or_else(|| Task::ready(vec![]))
 7049    }
 7050
 7051    fn code_actions(
 7052        &mut self,
 7053        buffer_row: u32,
 7054        window: &mut Window,
 7055        cx: &mut Context<Self>,
 7056    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 7057        let mut task = self.code_actions_task.take();
 7058        cx.spawn_in(window, async move |editor, cx| {
 7059            while let Some(prev_task) = task {
 7060                prev_task.await.log_err();
 7061                task = editor
 7062                    .update(cx, |this, _| this.code_actions_task.take())
 7063                    .ok()?;
 7064            }
 7065
 7066            editor
 7067                .update(cx, |editor, cx| {
 7068                    editor
 7069                        .available_code_actions
 7070                        .clone()
 7071                        .and_then(|(location, code_actions)| {
 7072                            let snapshot = location.buffer.read(cx).snapshot();
 7073                            let point_range = location.range.to_point(&snapshot);
 7074                            let point_range = point_range.start.row..=point_range.end.row;
 7075                            if point_range.contains(&buffer_row) {
 7076                                Some(code_actions)
 7077                            } else {
 7078                                None
 7079                            }
 7080                        })
 7081                })
 7082                .ok()
 7083                .flatten()
 7084        })
 7085    }
 7086
 7087    pub fn confirm_code_action(
 7088        &mut self,
 7089        action: &ConfirmCodeAction,
 7090        window: &mut Window,
 7091        cx: &mut Context<Self>,
 7092    ) -> Option<Task<Result<()>>> {
 7093        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 7094
 7095        let actions_menu =
 7096            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 7097                menu
 7098            } else {
 7099                return None;
 7100            };
 7101
 7102        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 7103        let action = actions_menu.actions.get(action_ix)?;
 7104        let title = action.label();
 7105        let buffer = actions_menu.buffer;
 7106        let workspace = self.workspace()?;
 7107
 7108        match action {
 7109            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 7110                workspace.update(cx, |workspace, cx| {
 7111                    workspace.schedule_resolved_task(
 7112                        task_source_kind,
 7113                        resolved_task,
 7114                        false,
 7115                        window,
 7116                        cx,
 7117                    );
 7118
 7119                    Some(Task::ready(Ok(())))
 7120                })
 7121            }
 7122            CodeActionsItem::CodeAction { action, provider } => {
 7123                let apply_code_action =
 7124                    provider.apply_code_action(buffer, action, true, window, cx);
 7125                let workspace = workspace.downgrade();
 7126                Some(cx.spawn_in(window, async move |editor, cx| {
 7127                    let project_transaction = apply_code_action.await?;
 7128                    Self::open_project_transaction(
 7129                        &editor,
 7130                        workspace,
 7131                        project_transaction,
 7132                        title,
 7133                        cx,
 7134                    )
 7135                    .await
 7136                }))
 7137            }
 7138            CodeActionsItem::DebugScenario(scenario) => {
 7139                let context = actions_menu.actions.context.into();
 7140
 7141                workspace.update(cx, |workspace, cx| {
 7142                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 7143                    workspace.start_debug_session(
 7144                        scenario,
 7145                        context,
 7146                        Some(buffer),
 7147                        None,
 7148                        window,
 7149                        cx,
 7150                    );
 7151                });
 7152                Some(Task::ready(Ok(())))
 7153            }
 7154        }
 7155    }
 7156
 7157    fn open_transaction_for_hidden_buffers(
 7158        workspace: Entity<Workspace>,
 7159        transaction: ProjectTransaction,
 7160        title: String,
 7161        window: &mut Window,
 7162        cx: &mut Context<Self>,
 7163    ) {
 7164        if transaction.0.is_empty() {
 7165            return;
 7166        }
 7167
 7168        let edited_buffers_already_open = {
 7169            let other_editors: Vec<Entity<Editor>> = workspace
 7170                .read(cx)
 7171                .panes()
 7172                .iter()
 7173                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 7174                .filter(|editor| editor.entity_id() != cx.entity_id())
 7175                .collect();
 7176
 7177            transaction.0.keys().all(|buffer| {
 7178                other_editors.iter().any(|editor| {
 7179                    let multi_buffer = editor.read(cx).buffer();
 7180                    multi_buffer.read(cx).is_singleton()
 7181                        && multi_buffer
 7182                            .read(cx)
 7183                            .as_singleton()
 7184                            .map_or(false, |singleton| {
 7185                                singleton.entity_id() == buffer.entity_id()
 7186                            })
 7187                })
 7188            })
 7189        };
 7190        if !edited_buffers_already_open {
 7191            let workspace = workspace.downgrade();
 7192            cx.defer_in(window, move |_, window, cx| {
 7193                cx.spawn_in(window, async move |editor, cx| {
 7194                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 7195                        .await
 7196                        .ok()
 7197                })
 7198                .detach();
 7199            });
 7200        }
 7201    }
 7202
 7203    pub async fn open_project_transaction(
 7204        editor: &WeakEntity<Editor>,
 7205        workspace: WeakEntity<Workspace>,
 7206        transaction: ProjectTransaction,
 7207        title: String,
 7208        cx: &mut AsyncWindowContext,
 7209    ) -> Result<()> {
 7210        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 7211        cx.update(|_, cx| {
 7212            entries.sort_unstable_by_key(|(buffer, _)| {
 7213                buffer.read(cx).file().map(|f| f.path().clone())
 7214            });
 7215        })?;
 7216        if entries.is_empty() {
 7217            return Ok(());
 7218        }
 7219
 7220        // If the project transaction's edits are all contained within this editor, then
 7221        // avoid opening a new editor to display them.
 7222
 7223        if let [(buffer, transaction)] = &*entries {
 7224            let cursor_excerpt = editor.update(cx, |editor, cx| {
 7225                let snapshot = editor.buffer().read(cx).snapshot(cx);
 7226                let head = editor.selections.newest_anchor().head();
 7227                let (buffer_snapshot, excerpt_range) = snapshot.excerpt_containing(head..head)?;
 7228                if buffer_snapshot.remote_id() != buffer.read(cx).remote_id() {
 7229                    return None;
 7230                }
 7231                Some(excerpt_range)
 7232            })?;
 7233
 7234            if let Some(excerpt_range) = cursor_excerpt {
 7235                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7236                    let excerpt_range = excerpt_range.context.to_offset(buffer);
 7237                    buffer
 7238                        .edited_ranges_for_transaction::<usize>(transaction)
 7239                        .all(|range| {
 7240                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7241                        })
 7242                });
 7243
 7244                if all_edits_within_excerpt {
 7245                    return Ok(());
 7246                }
 7247            }
 7248        }
 7249
 7250        let mut ranges_to_highlight = Vec::new();
 7251        let excerpt_buffer = cx.new(|cx| {
 7252            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7253            for (buffer_handle, transaction) in &entries {
 7254                let edited_ranges = buffer_handle
 7255                    .read(cx)
 7256                    .edited_ranges_for_transaction::<Point>(transaction)
 7257                    .collect::<Vec<_>>();
 7258                multibuffer.set_excerpts_for_path(
 7259                    PathKey::for_buffer(buffer_handle, cx),
 7260                    buffer_handle.clone(),
 7261                    edited_ranges.clone(),
 7262                    multibuffer_context_lines(cx),
 7263                    cx,
 7264                );
 7265                let snapshot = multibuffer.snapshot(cx);
 7266                let buffer_snapshot = buffer_handle.read(cx).snapshot();
 7267                ranges_to_highlight.extend(edited_ranges.into_iter().filter_map(|range| {
 7268                    let text_range = buffer_snapshot.anchor_range_inside(range);
 7269                    let start = snapshot.anchor_in_buffer(text_range.start)?;
 7270                    let end = snapshot.anchor_in_buffer(text_range.end)?;
 7271                    Some(start..end)
 7272                }));
 7273            }
 7274            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7275            multibuffer
 7276        });
 7277
 7278        workspace.update_in(cx, |workspace, window, cx| {
 7279            let project = workspace.project().clone();
 7280            let editor =
 7281                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7282            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7283            editor.update(cx, |editor, cx| {
 7284                editor.highlight_background(
 7285                    HighlightKey::Editor,
 7286                    &ranges_to_highlight,
 7287                    |_, theme| theme.colors().editor_highlighted_line_background,
 7288                    cx,
 7289                );
 7290            });
 7291        })?;
 7292
 7293        Ok(())
 7294    }
 7295
 7296    pub fn clear_code_action_providers(&mut self) {
 7297        self.code_action_providers.clear();
 7298        self.available_code_actions.take();
 7299    }
 7300
 7301    pub fn add_code_action_provider(
 7302        &mut self,
 7303        provider: Rc<dyn CodeActionProvider>,
 7304        window: &mut Window,
 7305        cx: &mut Context<Self>,
 7306    ) {
 7307        if self
 7308            .code_action_providers
 7309            .iter()
 7310            .any(|existing_provider| existing_provider.id() == provider.id())
 7311        {
 7312            return;
 7313        }
 7314
 7315        self.code_action_providers.push(provider);
 7316        self.refresh_code_actions(window, cx);
 7317    }
 7318
 7319    pub fn remove_code_action_provider(
 7320        &mut self,
 7321        id: Arc<str>,
 7322        window: &mut Window,
 7323        cx: &mut Context<Self>,
 7324    ) {
 7325        self.code_action_providers
 7326            .retain(|provider| provider.id() != id);
 7327        self.refresh_code_actions(window, cx);
 7328    }
 7329
 7330    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7331        !self.code_action_providers.is_empty()
 7332            && EditorSettings::get_global(cx).toolbar.code_actions
 7333    }
 7334
 7335    pub fn has_available_code_actions(&self) -> bool {
 7336        self.available_code_actions
 7337            .as_ref()
 7338            .is_some_and(|(_, actions)| !actions.is_empty())
 7339    }
 7340
 7341    fn render_inline_code_actions(
 7342        &self,
 7343        icon_size: ui::IconSize,
 7344        display_row: DisplayRow,
 7345        is_active: bool,
 7346        cx: &mut Context<Self>,
 7347    ) -> AnyElement {
 7348        let show_tooltip = !self.context_menu_visible();
 7349        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7350            .icon_size(icon_size)
 7351            .shape(ui::IconButtonShape::Square)
 7352            .icon_color(ui::Color::Hidden)
 7353            .toggle_state(is_active)
 7354            .when(show_tooltip, |this| {
 7355                this.tooltip({
 7356                    let focus_handle = self.focus_handle.clone();
 7357                    move |_window, cx| {
 7358                        Tooltip::for_action_in(
 7359                            "Toggle Code Actions",
 7360                            &ToggleCodeActions {
 7361                                deployed_from: None,
 7362                                quick_launch: false,
 7363                            },
 7364                            &focus_handle,
 7365                            cx,
 7366                        )
 7367                    }
 7368                })
 7369            })
 7370            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7371                window.focus(&editor.focus_handle(cx), cx);
 7372                editor.toggle_code_actions(
 7373                    &crate::actions::ToggleCodeActions {
 7374                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7375                            display_row,
 7376                        )),
 7377                        quick_launch: false,
 7378                    },
 7379                    window,
 7380                    cx,
 7381                );
 7382            }))
 7383            .into_any_element()
 7384    }
 7385
 7386    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7387        &self.context_menu
 7388    }
 7389
 7390    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7391        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7392            cx.background_executor()
 7393                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7394                .await;
 7395
 7396            let (start_buffer, start, _, end, _newest_selection) = this
 7397                .update(cx, |this, cx| {
 7398                    let newest_selection = this.selections.newest_anchor().clone();
 7399                    if newest_selection.head().diff_base_anchor().is_some() {
 7400                        return None;
 7401                    }
 7402                    let display_snapshot = this.display_snapshot(cx);
 7403                    let newest_selection_adjusted =
 7404                        this.selections.newest_adjusted(&display_snapshot);
 7405                    let buffer = this.buffer.read(cx);
 7406
 7407                    let (start_buffer, start) =
 7408                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7409                    let (end_buffer, end) =
 7410                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7411
 7412                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7413                })?
 7414                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7415                .context(
 7416                    "Expected selection to lie in a single buffer when refreshing code actions",
 7417                )?;
 7418            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7419                let providers = this.code_action_providers.clone();
 7420                let tasks = this
 7421                    .code_action_providers
 7422                    .iter()
 7423                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7424                    .collect::<Vec<_>>();
 7425                (providers, tasks)
 7426            })?;
 7427
 7428            let mut actions = Vec::new();
 7429            for (provider, provider_actions) in
 7430                providers.into_iter().zip(future::join_all(tasks).await)
 7431            {
 7432                if let Some(provider_actions) = provider_actions.log_err() {
 7433                    actions.extend(provider_actions.into_iter().map(|action| {
 7434                        AvailableCodeAction {
 7435                            action,
 7436                            provider: provider.clone(),
 7437                        }
 7438                    }));
 7439                }
 7440            }
 7441
 7442            this.update(cx, |this, cx| {
 7443                this.available_code_actions = if actions.is_empty() {
 7444                    None
 7445                } else {
 7446                    Some((
 7447                        Location {
 7448                            buffer: start_buffer,
 7449                            range: start..end,
 7450                        },
 7451                        actions.into(),
 7452                    ))
 7453                };
 7454                cx.notify();
 7455            })
 7456        }));
 7457    }
 7458
 7459    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7460        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7461            self.show_git_blame_inline = false;
 7462
 7463            self.show_git_blame_inline_delay_task =
 7464                Some(cx.spawn_in(window, async move |this, cx| {
 7465                    cx.background_executor().timer(delay).await;
 7466
 7467                    this.update(cx, |this, cx| {
 7468                        this.show_git_blame_inline = true;
 7469                        cx.notify();
 7470                    })
 7471                    .log_err();
 7472                }));
 7473        }
 7474    }
 7475
 7476    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7477        let snapshot = self.snapshot(window, cx);
 7478        let cursor = self
 7479            .selections
 7480            .newest::<Point>(&snapshot.display_snapshot)
 7481            .head();
 7482        let Some((buffer, point)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor) else {
 7483            return;
 7484        };
 7485
 7486        if self.blame.is_none() {
 7487            self.start_git_blame(true, window, cx);
 7488        }
 7489        let Some(blame) = self.blame.as_ref() else {
 7490            return;
 7491        };
 7492
 7493        let row_info = RowInfo {
 7494            buffer_id: Some(buffer.remote_id()),
 7495            buffer_row: Some(point.row),
 7496            ..Default::default()
 7497        };
 7498        let Some((buffer, blame_entry)) = blame
 7499            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7500            .flatten()
 7501        else {
 7502            return;
 7503        };
 7504
 7505        let anchor = self.selections.newest_anchor().head();
 7506        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7507        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7508            self.show_blame_popover(
 7509                buffer,
 7510                &blame_entry,
 7511                position + last_bounds.origin,
 7512                true,
 7513                cx,
 7514            );
 7515        };
 7516    }
 7517
 7518    fn show_blame_popover(
 7519        &mut self,
 7520        buffer: BufferId,
 7521        blame_entry: &BlameEntry,
 7522        position: gpui::Point<Pixels>,
 7523        ignore_timeout: bool,
 7524        cx: &mut Context<Self>,
 7525    ) {
 7526        if let Some(state) = &mut self.inline_blame_popover {
 7527            state.hide_task.take();
 7528        } else {
 7529            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7530            let blame_entry = blame_entry.clone();
 7531            let show_task = cx.spawn(async move |editor, cx| {
 7532                if !ignore_timeout {
 7533                    cx.background_executor()
 7534                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7535                        .await;
 7536                }
 7537                editor
 7538                    .update(cx, |editor, cx| {
 7539                        editor.inline_blame_popover_show_task.take();
 7540                        let Some(blame) = editor.blame.as_ref() else {
 7541                            return;
 7542                        };
 7543                        let blame = blame.read(cx);
 7544                        let details = blame.details_for_entry(buffer, &blame_entry);
 7545                        let markdown = cx.new(|cx| {
 7546                            Markdown::new(
 7547                                details
 7548                                    .as_ref()
 7549                                    .map(|message| message.message.clone())
 7550                                    .unwrap_or_default(),
 7551                                None,
 7552                                None,
 7553                                cx,
 7554                            )
 7555                        });
 7556                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7557                            position,
 7558                            hide_task: None,
 7559                            popover_bounds: None,
 7560                            popover_state: InlineBlamePopoverState {
 7561                                scroll_handle: ScrollHandle::new(),
 7562                                commit_message: details,
 7563                                markdown,
 7564                            },
 7565                            keyboard_grace: ignore_timeout,
 7566                        });
 7567                        cx.notify();
 7568                    })
 7569                    .ok();
 7570            });
 7571            self.inline_blame_popover_show_task = Some(show_task);
 7572        }
 7573    }
 7574
 7575    pub fn has_mouse_context_menu(&self) -> bool {
 7576        self.mouse_context_menu.is_some()
 7577    }
 7578
 7579    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7580        self.inline_blame_popover_show_task.take();
 7581        if let Some(state) = &mut self.inline_blame_popover {
 7582            let hide_task = cx.spawn(async move |editor, cx| {
 7583                if !ignore_timeout {
 7584                    cx.background_executor()
 7585                        .timer(std::time::Duration::from_millis(100))
 7586                        .await;
 7587                }
 7588                editor
 7589                    .update(cx, |editor, cx| {
 7590                        editor.inline_blame_popover.take();
 7591                        cx.notify();
 7592                    })
 7593                    .ok();
 7594            });
 7595            state.hide_task = Some(hide_task);
 7596            true
 7597        } else {
 7598            false
 7599        }
 7600    }
 7601
 7602    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7603        if self.pending_rename.is_some() {
 7604            return None;
 7605        }
 7606
 7607        let provider = self.semantics_provider.clone()?;
 7608        let buffer = self.buffer.read(cx);
 7609        let newest_selection = self.selections.newest_anchor().clone();
 7610        let cursor_position = newest_selection.head();
 7611        let (cursor_buffer, cursor_buffer_position) =
 7612            buffer.text_anchor_for_position(cursor_position, cx)?;
 7613        let (tail_buffer, tail_buffer_position) =
 7614            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7615        if cursor_buffer != tail_buffer {
 7616            return None;
 7617        }
 7618
 7619        let snapshot = cursor_buffer.read(cx).snapshot();
 7620        let word_ranges = cx.background_spawn(async move {
 7621            // this might look odd to put on the background thread, but
 7622            // `surrounding_word` can be quite expensive as it calls into
 7623            // tree-sitter language scopes
 7624            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7625            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7626            (start_word_range, end_word_range)
 7627        });
 7628
 7629        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7630        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7631            let (start_word_range, end_word_range) = word_ranges.await;
 7632            if start_word_range != end_word_range {
 7633                this.update(cx, |this, cx| {
 7634                    this.document_highlights_task.take();
 7635                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7636                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7637                })
 7638                .ok();
 7639                return;
 7640            }
 7641            cx.background_executor()
 7642                .timer(Duration::from_millis(debounce))
 7643                .await;
 7644
 7645            let highlights = if let Some(highlights) = cx.update(|cx| {
 7646                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7647            }) {
 7648                highlights.await.log_err()
 7649            } else {
 7650                None
 7651            };
 7652
 7653            if let Some(highlights) = highlights {
 7654                this.update(cx, |this, cx| {
 7655                    if this.pending_rename.is_some() {
 7656                        return;
 7657                    }
 7658
 7659                    let buffer = this.buffer.read(cx);
 7660                    if buffer
 7661                        .text_anchor_for_position(cursor_position, cx)
 7662                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7663                    {
 7664                        return;
 7665                    }
 7666
 7667                    let mut write_ranges = Vec::new();
 7668                    let mut read_ranges = Vec::new();
 7669                    let multibuffer_snapshot = buffer.snapshot(cx);
 7670                    for highlight in highlights {
 7671                        for range in
 7672                            multibuffer_snapshot.buffer_range_to_excerpt_ranges(highlight.range)
 7673                        {
 7674                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7675                                write_ranges.push(range);
 7676                            } else {
 7677                                read_ranges.push(range);
 7678                            }
 7679                        }
 7680                    }
 7681
 7682                    this.highlight_background(
 7683                        HighlightKey::DocumentHighlightRead,
 7684                        &read_ranges,
 7685                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7686                        cx,
 7687                    );
 7688                    this.highlight_background(
 7689                        HighlightKey::DocumentHighlightWrite,
 7690                        &write_ranges,
 7691                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7692                        cx,
 7693                    );
 7694                    cx.notify();
 7695                })
 7696                .log_err();
 7697            }
 7698        }));
 7699        None
 7700    }
 7701
 7702    fn prepare_highlight_query_from_selection(
 7703        &mut self,
 7704        snapshot: &DisplaySnapshot,
 7705        cx: &mut Context<Editor>,
 7706    ) -> Option<(String, Range<Anchor>)> {
 7707        if matches!(self.mode, EditorMode::SingleLine) {
 7708            return None;
 7709        }
 7710        if !self.use_selection_highlight || !EditorSettings::get_global(cx).selection_highlight {
 7711            return None;
 7712        }
 7713        if self.selections.count() != 1 || self.selections.line_mode() {
 7714            return None;
 7715        }
 7716        let selection = self.selections.newest::<Point>(&snapshot);
 7717        // If the selection spans multiple rows OR it is empty
 7718        if selection.start.row != selection.end.row
 7719            || selection.start.column == selection.end.column
 7720        {
 7721            return None;
 7722        }
 7723        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7724        let query = snapshot
 7725            .buffer_snapshot()
 7726            .text_for_range(selection_anchor_range.clone())
 7727            .collect::<String>();
 7728        if query.trim().is_empty() {
 7729            return None;
 7730        }
 7731        Some((query, selection_anchor_range))
 7732    }
 7733
 7734    #[ztracing::instrument(skip_all)]
 7735    fn update_selection_occurrence_highlights(
 7736        &mut self,
 7737        multi_buffer_snapshot: MultiBufferSnapshot,
 7738        query_text: String,
 7739        query_range: Range<Anchor>,
 7740        multi_buffer_range_to_query: Range<Point>,
 7741        use_debounce: bool,
 7742        window: &mut Window,
 7743        cx: &mut Context<Editor>,
 7744    ) -> Task<()> {
 7745        cx.spawn_in(window, async move |editor, cx| {
 7746            if use_debounce {
 7747                cx.background_executor()
 7748                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7749                    .await;
 7750            }
 7751            let match_task = cx.background_spawn(async move {
 7752                let buffer_ranges = multi_buffer_snapshot
 7753                    .range_to_buffer_ranges(
 7754                        multi_buffer_range_to_query.start..multi_buffer_range_to_query.end,
 7755                    )
 7756                    .into_iter()
 7757                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7758                let mut match_ranges = Vec::new();
 7759                let Ok(regex) = project::search::SearchQuery::text(
 7760                    query_text,
 7761                    false,
 7762                    false,
 7763                    false,
 7764                    Default::default(),
 7765                    Default::default(),
 7766                    false,
 7767                    None,
 7768                ) else {
 7769                    return Vec::default();
 7770                };
 7771                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7772                for (buffer_snapshot, search_range, _) in buffer_ranges {
 7773                    match_ranges.extend(
 7774                        regex
 7775                            .search(
 7776                                &buffer_snapshot,
 7777                                Some(search_range.start.0..search_range.end.0),
 7778                            )
 7779                            .await
 7780                            .into_iter()
 7781                            .filter_map(|match_range| {
 7782                                let match_start = buffer_snapshot
 7783                                    .anchor_after(search_range.start + match_range.start);
 7784                                let match_end = buffer_snapshot
 7785                                    .anchor_before(search_range.start + match_range.end);
 7786                                {
 7787                                    let range = multi_buffer_snapshot
 7788                                        .anchor_in_buffer(match_start)?
 7789                                        ..multi_buffer_snapshot.anchor_in_buffer(match_end)?;
 7790                                    Some(range).filter(|match_anchor_range| {
 7791                                        match_anchor_range != &query_range
 7792                                    })
 7793                                }
 7794                            }),
 7795                    );
 7796                }
 7797                match_ranges
 7798            });
 7799            let match_ranges = match_task.await;
 7800            editor
 7801                .update_in(cx, |editor, _, cx| {
 7802                    if use_debounce {
 7803                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7804                        editor.debounced_selection_highlight_complete = true;
 7805                    } else if editor.debounced_selection_highlight_complete {
 7806                        return;
 7807                    }
 7808                    if !match_ranges.is_empty() {
 7809                        editor.highlight_background(
 7810                            HighlightKey::SelectedTextHighlight,
 7811                            &match_ranges,
 7812                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7813                            cx,
 7814                        )
 7815                    }
 7816                })
 7817                .log_err();
 7818        })
 7819    }
 7820
 7821    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7822        struct NewlineFold;
 7823        let type_id = std::any::TypeId::of::<NewlineFold>();
 7824        if !self.mode.is_single_line() {
 7825            return;
 7826        }
 7827        let snapshot = self.snapshot(window, cx);
 7828        if snapshot.buffer_snapshot().max_point().row == 0 {
 7829            return;
 7830        }
 7831        let task = cx.background_spawn(async move {
 7832            let new_newlines = snapshot
 7833                .buffer_chars_at(MultiBufferOffset(0))
 7834                .filter_map(|(c, i)| {
 7835                    if c == '\n' {
 7836                        Some(
 7837                            snapshot.buffer_snapshot().anchor_after(i)
 7838                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7839                        )
 7840                    } else {
 7841                        None
 7842                    }
 7843                })
 7844                .collect::<Vec<_>>();
 7845            let existing_newlines = snapshot
 7846                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7847                .filter_map(|fold| {
 7848                    if fold.placeholder.type_tag == Some(type_id) {
 7849                        Some(fold.range.start..fold.range.end)
 7850                    } else {
 7851                        None
 7852                    }
 7853                })
 7854                .collect::<Vec<_>>();
 7855
 7856            (new_newlines, existing_newlines)
 7857        });
 7858        self.folding_newlines = cx.spawn(async move |this, cx| {
 7859            let (new_newlines, existing_newlines) = task.await;
 7860            if new_newlines == existing_newlines {
 7861                return;
 7862            }
 7863            let placeholder = FoldPlaceholder {
 7864                render: Arc::new(move |_, _, cx| {
 7865                    div()
 7866                        .bg(cx.theme().status().hint_background)
 7867                        .border_b_1()
 7868                        .size_full()
 7869                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7870                        .border_color(cx.theme().status().hint)
 7871                        .child("\\n")
 7872                        .into_any()
 7873                }),
 7874                constrain_width: false,
 7875                merge_adjacent: false,
 7876                type_tag: Some(type_id),
 7877                collapsed_text: None,
 7878            };
 7879            let creases = new_newlines
 7880                .into_iter()
 7881                .map(|range| Crease::simple(range, placeholder.clone()))
 7882                .collect();
 7883            this.update(cx, |this, cx| {
 7884                this.display_map.update(cx, |display_map, cx| {
 7885                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7886                    display_map.fold(creases, cx);
 7887                });
 7888            })
 7889            .ok();
 7890        });
 7891    }
 7892
 7893    #[ztracing::instrument(skip_all)]
 7894    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7895        if !self.lsp_data_enabled() {
 7896            return;
 7897        }
 7898        let cursor = self.selections.newest_anchor().head();
 7899        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7900
 7901        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7902            self.outline_symbols_at_cursor =
 7903                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7904            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7905            cx.notify();
 7906        } else {
 7907            let syntax = cx.theme().syntax().clone();
 7908            let background_task = cx.background_spawn(async move {
 7909                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7910            });
 7911            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7912                cx.spawn(async move |this, cx| {
 7913                    let symbols = background_task.await;
 7914                    this.update(cx, |this, cx| {
 7915                        this.outline_symbols_at_cursor = symbols;
 7916                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7917                        cx.notify();
 7918                    })
 7919                    .ok();
 7920                });
 7921        }
 7922    }
 7923
 7924    #[ztracing::instrument(skip_all)]
 7925    fn refresh_selected_text_highlights(
 7926        &mut self,
 7927        snapshot: &DisplaySnapshot,
 7928        on_buffer_edit: bool,
 7929        window: &mut Window,
 7930        cx: &mut Context<Editor>,
 7931    ) {
 7932        let Some((query_text, query_range)) =
 7933            self.prepare_highlight_query_from_selection(snapshot, cx)
 7934        else {
 7935            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7936            self.quick_selection_highlight_task.take();
 7937            self.debounced_selection_highlight_task.take();
 7938            self.debounced_selection_highlight_complete = false;
 7939            return;
 7940        };
 7941        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7942        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7943        let query_changed = self
 7944            .quick_selection_highlight_task
 7945            .as_ref()
 7946            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7947        if query_changed {
 7948            self.debounced_selection_highlight_complete = false;
 7949        }
 7950        if on_buffer_edit || query_changed {
 7951            self.quick_selection_highlight_task = Some((
 7952                query_range.clone(),
 7953                self.update_selection_occurrence_highlights(
 7954                    snapshot.buffer.clone(),
 7955                    query_text.clone(),
 7956                    query_range.clone(),
 7957                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7958                    false,
 7959                    window,
 7960                    cx,
 7961                ),
 7962            ));
 7963        }
 7964        if on_buffer_edit
 7965            || self
 7966                .debounced_selection_highlight_task
 7967                .as_ref()
 7968                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7969        {
 7970            let multi_buffer_start = multi_buffer_snapshot
 7971                .anchor_before(MultiBufferOffset(0))
 7972                .to_point(&multi_buffer_snapshot);
 7973            let multi_buffer_end = multi_buffer_snapshot
 7974                .anchor_after(multi_buffer_snapshot.len())
 7975                .to_point(&multi_buffer_snapshot);
 7976            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7977            self.debounced_selection_highlight_task = Some((
 7978                query_range.clone(),
 7979                self.update_selection_occurrence_highlights(
 7980                    snapshot.buffer.clone(),
 7981                    query_text,
 7982                    query_range,
 7983                    multi_buffer_full_range,
 7984                    true,
 7985                    window,
 7986                    cx,
 7987                ),
 7988            ));
 7989        }
 7990    }
 7991
 7992    pub fn multi_buffer_visible_range(
 7993        &self,
 7994        display_snapshot: &DisplaySnapshot,
 7995        cx: &App,
 7996    ) -> Range<Point> {
 7997        let visible_start = self
 7998            .scroll_manager
 7999            .native_anchor(display_snapshot, cx)
 8000            .anchor
 8001            .to_point(display_snapshot.buffer_snapshot())
 8002            .to_display_point(display_snapshot);
 8003
 8004        let mut target_end = visible_start;
 8005        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 8006
 8007        visible_start.to_point(display_snapshot)
 8008            ..display_snapshot
 8009                .clip_point(target_end, Bias::Right)
 8010                .to_point(display_snapshot)
 8011    }
 8012
 8013    pub fn refresh_edit_prediction(
 8014        &mut self,
 8015        debounce: bool,
 8016        user_requested: bool,
 8017        window: &mut Window,
 8018        cx: &mut Context<Self>,
 8019    ) -> Option<()> {
 8020        if self.leader_id.is_some() {
 8021            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8022            return None;
 8023        }
 8024
 8025        let cursor = self.selections.newest_anchor().head();
 8026        let (buffer, cursor_buffer_position) =
 8027            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8028
 8029        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8030            return None;
 8031        }
 8032
 8033        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 8034            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8035            return None;
 8036        }
 8037
 8038        self.update_visible_edit_prediction(window, cx);
 8039
 8040        if !user_requested
 8041            && (!self.should_show_edit_predictions()
 8042                || !self.is_focused(window)
 8043                || buffer.read(cx).is_empty())
 8044        {
 8045            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8046            return None;
 8047        }
 8048
 8049        self.edit_prediction_provider()?
 8050            .refresh(buffer, cursor_buffer_position, debounce, cx);
 8051        Some(())
 8052    }
 8053
 8054    fn show_edit_predictions_in_menu(&self) -> bool {
 8055        match self.edit_prediction_settings {
 8056            EditPredictionSettings::Disabled => false,
 8057            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 8058        }
 8059    }
 8060
 8061    pub fn edit_predictions_enabled(&self) -> bool {
 8062        match self.edit_prediction_settings {
 8063            EditPredictionSettings::Disabled => false,
 8064            EditPredictionSettings::Enabled { .. } => true,
 8065        }
 8066    }
 8067
 8068    fn edit_prediction_requires_modifier(&self) -> bool {
 8069        match self.edit_prediction_settings {
 8070            EditPredictionSettings::Disabled => false,
 8071            EditPredictionSettings::Enabled {
 8072                preview_requires_modifier,
 8073                ..
 8074            } => preview_requires_modifier,
 8075        }
 8076    }
 8077
 8078    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 8079        if self.edit_prediction_provider.is_none() {
 8080            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8081            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8082            return;
 8083        }
 8084
 8085        let selection = self.selections.newest_anchor();
 8086        let cursor = selection.head();
 8087
 8088        if let Some((buffer, cursor_buffer_position)) =
 8089            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8090        {
 8091            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8092                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8093                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8094                return;
 8095            }
 8096            self.edit_prediction_settings =
 8097                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8098        }
 8099    }
 8100
 8101    fn edit_prediction_settings_at_position(
 8102        &self,
 8103        buffer: &Entity<Buffer>,
 8104        buffer_position: language::Anchor,
 8105        cx: &App,
 8106    ) -> EditPredictionSettings {
 8107        if !self.mode.is_full()
 8108            || !self.show_edit_predictions_override.unwrap_or(true)
 8109            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 8110        {
 8111            return EditPredictionSettings::Disabled;
 8112        }
 8113
 8114        if !LanguageSettings::for_buffer(&buffer.read(cx), cx).show_edit_predictions {
 8115            return EditPredictionSettings::Disabled;
 8116        };
 8117
 8118        let by_provider = matches!(
 8119            self.menu_edit_predictions_policy,
 8120            MenuEditPredictionsPolicy::ByProvider
 8121        );
 8122
 8123        let show_in_menu = by_provider
 8124            && self
 8125                .edit_prediction_provider
 8126                .as_ref()
 8127                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 8128
 8129        let file = buffer.read(cx).file();
 8130        let preview_requires_modifier =
 8131            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 8132
 8133        EditPredictionSettings::Enabled {
 8134            show_in_menu,
 8135            preview_requires_modifier,
 8136        }
 8137    }
 8138
 8139    fn should_show_edit_predictions(&self) -> bool {
 8140        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 8141    }
 8142
 8143    pub fn edit_prediction_preview_is_active(&self) -> bool {
 8144        matches!(
 8145            self.edit_prediction_preview,
 8146            EditPredictionPreview::Active { .. }
 8147        )
 8148    }
 8149
 8150    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 8151        let cursor = self.selections.newest_anchor().head();
 8152        if let Some((buffer, cursor_position)) =
 8153            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 8154        {
 8155            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 8156        } else {
 8157            false
 8158        }
 8159    }
 8160
 8161    pub fn supports_minimap(&self, cx: &App) -> bool {
 8162        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 8163    }
 8164
 8165    fn edit_predictions_enabled_in_buffer(
 8166        &self,
 8167        buffer: &Entity<Buffer>,
 8168        buffer_position: language::Anchor,
 8169        cx: &App,
 8170    ) -> bool {
 8171        maybe!({
 8172            if self.read_only(cx) || self.leader_id.is_some() {
 8173                return Some(false);
 8174            }
 8175            let provider = self.edit_prediction_provider()?;
 8176            if !provider.is_enabled(buffer, buffer_position, cx) {
 8177                return Some(false);
 8178            }
 8179            let buffer = buffer.read(cx);
 8180            let Some(file) = buffer.file() else {
 8181                return Some(true);
 8182            };
 8183            let settings = all_language_settings(Some(file), cx);
 8184            Some(settings.edit_predictions_enabled_for_file(file, cx))
 8185        })
 8186        .unwrap_or(false)
 8187    }
 8188
 8189    pub fn show_edit_prediction(
 8190        &mut self,
 8191        _: &ShowEditPrediction,
 8192        window: &mut Window,
 8193        cx: &mut Context<Self>,
 8194    ) {
 8195        if !self.has_active_edit_prediction() {
 8196            self.refresh_edit_prediction(false, true, window, cx);
 8197            return;
 8198        }
 8199
 8200        self.update_visible_edit_prediction(window, cx);
 8201    }
 8202
 8203    pub fn display_cursor_names(
 8204        &mut self,
 8205        _: &DisplayCursorNames,
 8206        window: &mut Window,
 8207        cx: &mut Context<Self>,
 8208    ) {
 8209        self.show_cursor_names(window, cx);
 8210    }
 8211
 8212    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 8213        self.show_cursor_names = true;
 8214        cx.notify();
 8215        cx.spawn_in(window, async move |this, cx| {
 8216            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8217            this.update(cx, |this, cx| {
 8218                this.show_cursor_names = false;
 8219                cx.notify()
 8220            })
 8221            .ok()
 8222        })
 8223        .detach();
 8224    }
 8225
 8226    pub fn accept_partial_edit_prediction(
 8227        &mut self,
 8228        granularity: EditPredictionGranularity,
 8229        window: &mut Window,
 8230        cx: &mut Context<Self>,
 8231    ) {
 8232        if self.show_edit_predictions_in_menu() {
 8233            self.hide_context_menu(window, cx);
 8234        }
 8235
 8236        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8237            return;
 8238        };
 8239
 8240        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8241            return;
 8242        }
 8243
 8244        match &active_edit_prediction.completion {
 8245            EditPrediction::MoveWithin { target, .. } => {
 8246                let target = *target;
 8247
 8248                if matches!(granularity, EditPredictionGranularity::Full) {
 8249                    if let Some(position_map) = &self.last_position_map {
 8250                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8251                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8252
 8253                        if is_visible || !self.edit_prediction_requires_modifier() {
 8254                            self.unfold_ranges(&[target..target], true, false, cx);
 8255                            self.change_selections(
 8256                                SelectionEffects::scroll(Autoscroll::newest()),
 8257                                window,
 8258                                cx,
 8259                                |selections| {
 8260                                    selections.select_anchor_ranges([target..target]);
 8261                                },
 8262                            );
 8263                            self.clear_row_highlights::<EditPredictionPreview>();
 8264                            self.edit_prediction_preview
 8265                                .set_previous_scroll_position(None);
 8266                        } else {
 8267                            // Highlight and request scroll
 8268                            self.edit_prediction_preview
 8269                                .set_previous_scroll_position(Some(
 8270                                    position_map.snapshot.scroll_anchor,
 8271                                ));
 8272                            self.highlight_rows::<EditPredictionPreview>(
 8273                                target..target,
 8274                                cx.theme().colors().editor_highlighted_line_background,
 8275                                RowHighlightOptions {
 8276                                    autoscroll: true,
 8277                                    ..Default::default()
 8278                                },
 8279                                cx,
 8280                            );
 8281                            self.request_autoscroll(Autoscroll::fit(), cx);
 8282                        }
 8283                    }
 8284                } else {
 8285                    self.change_selections(
 8286                        SelectionEffects::scroll(Autoscroll::newest()),
 8287                        window,
 8288                        cx,
 8289                        |selections| {
 8290                            selections.select_anchor_ranges([target..target]);
 8291                        },
 8292                    );
 8293                }
 8294            }
 8295            EditPrediction::MoveOutside { snapshot, target } => {
 8296                if let Some(workspace) = self.workspace() {
 8297                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8298                        .detach_and_log_err(cx);
 8299                }
 8300            }
 8301            EditPrediction::Edit {
 8302                edits,
 8303                cursor_position,
 8304                ..
 8305            } => {
 8306                self.report_edit_prediction_event(
 8307                    active_edit_prediction.completion_id.clone(),
 8308                    true,
 8309                    cx,
 8310                );
 8311
 8312                match granularity {
 8313                    EditPredictionGranularity::Full => {
 8314                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8315
 8316                        // Compute fallback cursor position BEFORE applying the edit,
 8317                        // so the anchor tracks through the edit correctly
 8318                        let fallback_cursor_target = {
 8319                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8320                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8321                        };
 8322
 8323                        self.buffer.update(cx, |buffer, cx| {
 8324                            buffer.edit(edits.iter().cloned(), None, cx)
 8325                        });
 8326
 8327                        if let Some(provider) = self.edit_prediction_provider() {
 8328                            provider.accept(cx);
 8329                        }
 8330
 8331                        // Resolve cursor position after the edit is applied
 8332                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8333                            // The anchor tracks through the edit, then we add the offset
 8334                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8335                            let base_offset = anchor.to_offset(&snapshot).0;
 8336                            let target_offset =
 8337                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8338                            snapshot.anchor_after(target_offset)
 8339                        } else {
 8340                            fallback_cursor_target
 8341                        };
 8342
 8343                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8344                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8345                        });
 8346
 8347                        let selections = self.selections.disjoint_anchors_arc();
 8348                        if let Some(transaction_id_now) =
 8349                            self.buffer.read(cx).last_transaction_id(cx)
 8350                        {
 8351                            if transaction_id_prev != Some(transaction_id_now) {
 8352                                self.selection_history
 8353                                    .insert_transaction(transaction_id_now, selections);
 8354                            }
 8355                        }
 8356
 8357                        self.update_visible_edit_prediction(window, cx);
 8358                        if self.active_edit_prediction.is_none() {
 8359                            self.refresh_edit_prediction(true, true, window, cx);
 8360                        }
 8361                        cx.notify();
 8362                    }
 8363                    _ => {
 8364                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8365                        let cursor_offset = self
 8366                            .selections
 8367                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8368                            .head();
 8369
 8370                        let insertion = edits.iter().find_map(|(range, text)| {
 8371                            let range = range.to_offset(&snapshot);
 8372                            if range.is_empty() && range.start == cursor_offset {
 8373                                Some(text)
 8374                            } else {
 8375                                None
 8376                            }
 8377                        });
 8378
 8379                        if let Some(text) = insertion {
 8380                            let text_to_insert = match granularity {
 8381                                EditPredictionGranularity::Word => {
 8382                                    let mut partial = text
 8383                                        .chars()
 8384                                        .by_ref()
 8385                                        .take_while(|c| c.is_alphabetic())
 8386                                        .collect::<String>();
 8387                                    if partial.is_empty() {
 8388                                        partial = text
 8389                                            .chars()
 8390                                            .by_ref()
 8391                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8392                                            .collect::<String>();
 8393                                    }
 8394                                    partial
 8395                                }
 8396                                EditPredictionGranularity::Line => {
 8397                                    if let Some(line) = text.split_inclusive('\n').next() {
 8398                                        line.to_string()
 8399                                    } else {
 8400                                        text.to_string()
 8401                                    }
 8402                                }
 8403                                EditPredictionGranularity::Full => unreachable!(),
 8404                            };
 8405
 8406                            cx.emit(EditorEvent::InputHandled {
 8407                                utf16_range_to_replace: None,
 8408                                text: text_to_insert.clone().into(),
 8409                            });
 8410
 8411                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8412                            self.refresh_edit_prediction(true, true, window, cx);
 8413                            cx.notify();
 8414                        } else {
 8415                            self.accept_partial_edit_prediction(
 8416                                EditPredictionGranularity::Full,
 8417                                window,
 8418                                cx,
 8419                            );
 8420                        }
 8421                    }
 8422                }
 8423            }
 8424        }
 8425    }
 8426
 8427    pub fn accept_next_word_edit_prediction(
 8428        &mut self,
 8429        _: &AcceptNextWordEditPrediction,
 8430        window: &mut Window,
 8431        cx: &mut Context<Self>,
 8432    ) {
 8433        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8434    }
 8435
 8436    pub fn accept_next_line_edit_prediction(
 8437        &mut self,
 8438        _: &AcceptNextLineEditPrediction,
 8439        window: &mut Window,
 8440        cx: &mut Context<Self>,
 8441    ) {
 8442        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8443    }
 8444
 8445    pub fn accept_edit_prediction(
 8446        &mut self,
 8447        _: &AcceptEditPrediction,
 8448        window: &mut Window,
 8449        cx: &mut Context<Self>,
 8450    ) {
 8451        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8452    }
 8453
 8454    fn discard_edit_prediction(
 8455        &mut self,
 8456        reason: EditPredictionDiscardReason,
 8457        cx: &mut Context<Self>,
 8458    ) -> bool {
 8459        if reason == EditPredictionDiscardReason::Rejected {
 8460            let completion_id = self
 8461                .active_edit_prediction
 8462                .as_ref()
 8463                .and_then(|active_completion| active_completion.completion_id.clone());
 8464
 8465            self.report_edit_prediction_event(completion_id, false, cx);
 8466        }
 8467
 8468        if let Some(provider) = self.edit_prediction_provider() {
 8469            provider.discard(reason, cx);
 8470        }
 8471
 8472        self.take_active_edit_prediction(reason == EditPredictionDiscardReason::Ignored, cx)
 8473    }
 8474
 8475    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8476        let Some(provider) = self.edit_prediction_provider() else {
 8477            return;
 8478        };
 8479
 8480        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
 8481        let Some((position, _)) =
 8482            buffer_snapshot.anchor_to_buffer_anchor(self.selections.newest_anchor().head())
 8483        else {
 8484            return;
 8485        };
 8486        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
 8487            return;
 8488        };
 8489
 8490        let extension = buffer
 8491            .read(cx)
 8492            .file()
 8493            .and_then(|file| Some(file.path().extension()?.to_string()));
 8494
 8495        let event_type = match accepted {
 8496            true => "Edit Prediction Accepted",
 8497            false => "Edit Prediction Discarded",
 8498        };
 8499        telemetry::event!(
 8500            event_type,
 8501            provider = provider.name(),
 8502            prediction_id = id,
 8503            suggestion_accepted = accepted,
 8504            file_extension = extension,
 8505        );
 8506    }
 8507
 8508    fn open_editor_at_anchor(
 8509        snapshot: &language::BufferSnapshot,
 8510        target: language::Anchor,
 8511        workspace: &Entity<Workspace>,
 8512        window: &mut Window,
 8513        cx: &mut App,
 8514    ) -> Task<Result<()>> {
 8515        workspace.update(cx, |workspace, cx| {
 8516            let path = snapshot.file().map(|file| file.full_path(cx));
 8517            let Some(path) =
 8518                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8519            else {
 8520                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8521            };
 8522            let target = text::ToPoint::to_point(&target, snapshot);
 8523            let item = workspace.open_path(path, None, true, window, cx);
 8524            window.spawn(cx, async move |cx| {
 8525                let Some(editor) = item.await?.downcast::<Editor>() else {
 8526                    return Ok(());
 8527                };
 8528                editor
 8529                    .update_in(cx, |editor, window, cx| {
 8530                        editor.go_to_singleton_buffer_point(target, window, cx);
 8531                    })
 8532                    .ok();
 8533                anyhow::Ok(())
 8534            })
 8535        })
 8536    }
 8537
 8538    pub fn has_active_edit_prediction(&self) -> bool {
 8539        self.active_edit_prediction.is_some()
 8540    }
 8541
 8542    fn take_active_edit_prediction(
 8543        &mut self,
 8544        preserve_stale_in_menu: bool,
 8545        cx: &mut Context<Self>,
 8546    ) -> bool {
 8547        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8548            if !preserve_stale_in_menu {
 8549                self.stale_edit_prediction_in_menu = None;
 8550            }
 8551            return false;
 8552        };
 8553
 8554        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8555        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8556        self.stale_edit_prediction_in_menu =
 8557            preserve_stale_in_menu.then_some(active_edit_prediction);
 8558        true
 8559    }
 8560
 8561    /// Returns true when we're displaying the edit prediction popover below the cursor
 8562    /// like we are not previewing and the LSP autocomplete menu is visible
 8563    /// or we are in `when_holding_modifier` mode.
 8564    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8565        if self.edit_prediction_preview_is_active()
 8566            || !self.show_edit_predictions_in_menu()
 8567            || !self.edit_predictions_enabled()
 8568        {
 8569            return false;
 8570        }
 8571
 8572        if self.has_visible_completions_menu() {
 8573            return true;
 8574        }
 8575
 8576        has_completion && self.edit_prediction_requires_modifier()
 8577    }
 8578
 8579    fn handle_modifiers_changed(
 8580        &mut self,
 8581        modifiers: Modifiers,
 8582        position_map: &PositionMap,
 8583        window: &mut Window,
 8584        cx: &mut Context<Self>,
 8585    ) {
 8586        self.update_edit_prediction_settings(cx);
 8587
 8588        // Ensure that the edit prediction preview is updated, even when not
 8589        // enabled, if there's an active edit prediction preview.
 8590        if self.show_edit_predictions_in_menu()
 8591            || self.edit_prediction_requires_modifier()
 8592            || matches!(
 8593                self.edit_prediction_preview,
 8594                EditPredictionPreview::Active { .. }
 8595            )
 8596        {
 8597            self.update_edit_prediction_preview(&modifiers, window, cx);
 8598        }
 8599
 8600        self.update_selection_mode(&modifiers, position_map, window, cx);
 8601
 8602        let mouse_position = window.mouse_position();
 8603        if !position_map.text_hitbox.is_hovered(window) {
 8604            return;
 8605        }
 8606
 8607        self.update_hovered_link(
 8608            position_map.point_for_position(mouse_position),
 8609            Some(mouse_position),
 8610            &position_map.snapshot,
 8611            modifiers,
 8612            window,
 8613            cx,
 8614        )
 8615    }
 8616
 8617    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8618        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8619            MultiCursorModifier::Alt => modifiers.secondary(),
 8620            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8621        }
 8622    }
 8623
 8624    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8625        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8626            MultiCursorModifier::Alt => modifiers.alt,
 8627            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8628        }
 8629    }
 8630
 8631    fn columnar_selection_mode(
 8632        modifiers: &Modifiers,
 8633        cx: &mut Context<Self>,
 8634    ) -> Option<ColumnarMode> {
 8635        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8636            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8637                Some(ColumnarMode::FromMouse)
 8638            } else if Self::is_alt_pressed(modifiers, cx) {
 8639                Some(ColumnarMode::FromSelection)
 8640            } else {
 8641                None
 8642            }
 8643        } else {
 8644            None
 8645        }
 8646    }
 8647
 8648    fn update_selection_mode(
 8649        &mut self,
 8650        modifiers: &Modifiers,
 8651        position_map: &PositionMap,
 8652        window: &mut Window,
 8653        cx: &mut Context<Self>,
 8654    ) {
 8655        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8656            return;
 8657        };
 8658        if self.selections.pending_anchor().is_none() {
 8659            return;
 8660        }
 8661
 8662        let mouse_position = window.mouse_position();
 8663        let point_for_position = position_map.point_for_position(mouse_position);
 8664        let position = point_for_position.previous_valid;
 8665
 8666        self.select(
 8667            SelectPhase::BeginColumnar {
 8668                position,
 8669                reset: false,
 8670                mode,
 8671                goal_column: point_for_position.exact_unclipped.column(),
 8672            },
 8673            window,
 8674            cx,
 8675        );
 8676    }
 8677
 8678    fn update_edit_prediction_preview(
 8679        &mut self,
 8680        modifiers: &Modifiers,
 8681        window: &mut Window,
 8682        cx: &mut Context<Self>,
 8683    ) {
 8684        let modifiers_held = self.edit_prediction_preview_modifiers_held(modifiers, window, cx);
 8685
 8686        if modifiers_held {
 8687            if matches!(
 8688                self.edit_prediction_preview,
 8689                EditPredictionPreview::Inactive { .. }
 8690            ) {
 8691                self.edit_prediction_preview = EditPredictionPreview::Active {
 8692                    previous_scroll_position: None,
 8693                    since: Instant::now(),
 8694                };
 8695
 8696                self.update_visible_edit_prediction(window, cx);
 8697                cx.notify();
 8698            }
 8699        } else if let EditPredictionPreview::Active {
 8700            previous_scroll_position,
 8701            since,
 8702        } = self.edit_prediction_preview
 8703        {
 8704            if let (Some(previous_scroll_position), Some(position_map)) =
 8705                (previous_scroll_position, self.last_position_map.as_ref())
 8706            {
 8707                self.set_scroll_position(
 8708                    previous_scroll_position
 8709                        .scroll_position(&position_map.snapshot.display_snapshot),
 8710                    window,
 8711                    cx,
 8712                );
 8713            }
 8714
 8715            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8716                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8717            };
 8718            self.clear_row_highlights::<EditPredictionPreview>();
 8719            self.update_visible_edit_prediction(window, cx);
 8720            cx.notify();
 8721        }
 8722    }
 8723
 8724    fn update_visible_edit_prediction(
 8725        &mut self,
 8726        _window: &mut Window,
 8727        cx: &mut Context<Self>,
 8728    ) -> Option<()> {
 8729        if self.ime_transaction.is_some() {
 8730            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8731            return None;
 8732        }
 8733
 8734        let selection = self.selections.newest_anchor();
 8735        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8736        let cursor = selection.head();
 8737        let (cursor_text_anchor, _) = multibuffer.anchor_to_buffer_anchor(cursor)?;
 8738        let buffer = self.buffer.read(cx).buffer(cursor_text_anchor.buffer_id)?;
 8739
 8740        // Check project-level disable_ai setting for the current buffer
 8741        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8742            return None;
 8743        }
 8744        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8745
 8746        let show_in_menu = self.show_edit_predictions_in_menu();
 8747        let completions_menu_has_precedence = !show_in_menu
 8748            && (self.context_menu.borrow().is_some()
 8749                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8750
 8751        if completions_menu_has_precedence
 8752            || !offset_selection.is_empty()
 8753            || self
 8754                .active_edit_prediction
 8755                .as_ref()
 8756                .is_some_and(|completion| {
 8757                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8758                        return false;
 8759                    };
 8760                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8761                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8762                    !invalidation_range.contains(&offset_selection.head())
 8763                })
 8764        {
 8765            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8766            return None;
 8767        }
 8768
 8769        self.take_active_edit_prediction(true, cx);
 8770        let Some(provider) = self.edit_prediction_provider() else {
 8771            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8772            return None;
 8773        };
 8774
 8775        self.edit_prediction_settings =
 8776            self.edit_prediction_settings_at_position(&buffer, cursor_text_anchor, cx);
 8777
 8778        self.in_leading_whitespace = multibuffer.is_line_whitespace_upto(cursor);
 8779
 8780        if self.in_leading_whitespace {
 8781            let cursor_point = cursor.to_point(&multibuffer);
 8782            let mut suggested_indent = None;
 8783            multibuffer.suggested_indents_callback(
 8784                cursor_point.row..cursor_point.row + 1,
 8785                &mut |_, indent| {
 8786                    suggested_indent = Some(indent);
 8787                    ControlFlow::Break(())
 8788                },
 8789                cx,
 8790            );
 8791
 8792            if let Some(indent) = suggested_indent
 8793                && indent.len == cursor_point.column
 8794            {
 8795                self.in_leading_whitespace = false;
 8796            }
 8797        }
 8798
 8799        let edit_prediction = provider.suggest(&buffer, cursor_text_anchor, cx)?;
 8800
 8801        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8802        {
 8803            edit_prediction_types::EditPrediction::Local {
 8804                id,
 8805                edits,
 8806                cursor_position,
 8807                edit_preview,
 8808            } => (id, edits, cursor_position, edit_preview),
 8809            edit_prediction_types::EditPrediction::Jump {
 8810                id,
 8811                snapshot,
 8812                target,
 8813            } => {
 8814                if let Some(provider) = &self.edit_prediction_provider {
 8815                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8816                }
 8817                self.stale_edit_prediction_in_menu = None;
 8818                self.active_edit_prediction = Some(EditPredictionState {
 8819                    inlay_ids: vec![],
 8820                    completion: EditPrediction::MoveOutside { snapshot, target },
 8821                    completion_id: id,
 8822                    invalidation_range: None,
 8823                });
 8824                cx.notify();
 8825                return Some(());
 8826            }
 8827        };
 8828
 8829        let edits = edits
 8830            .into_iter()
 8831            .flat_map(|(range, new_text)| {
 8832                Some((
 8833                    multibuffer.buffer_anchor_range_to_anchor_range(range)?,
 8834                    new_text,
 8835                ))
 8836            })
 8837            .collect::<Vec<_>>();
 8838        if edits.is_empty() {
 8839            return None;
 8840        }
 8841
 8842        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8843            let anchor = multibuffer.anchor_in_excerpt(predicted.anchor)?;
 8844            Some((anchor, predicted.offset))
 8845        });
 8846
 8847        let first_edit_start = edits.first().unwrap().0.start;
 8848        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8849        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8850
 8851        let last_edit_end = edits.last().unwrap().0.end;
 8852        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8853        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8854
 8855        let cursor_row = cursor.to_point(&multibuffer).row;
 8856
 8857        let snapshot = multibuffer
 8858            .buffer_for_id(cursor_text_anchor.buffer_id)
 8859            .cloned()?;
 8860
 8861        let mut inlay_ids = Vec::new();
 8862        let invalidation_row_range;
 8863        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8864            Some(cursor_row..edit_end_row)
 8865        } else if cursor_row > edit_end_row {
 8866            Some(edit_start_row..cursor_row)
 8867        } else {
 8868            None
 8869        };
 8870        let supports_jump = self
 8871            .edit_prediction_provider
 8872            .as_ref()
 8873            .map(|provider| provider.provider.supports_jump_to_edit())
 8874            .unwrap_or(true);
 8875
 8876        let is_move = supports_jump
 8877            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8878        let completion = if is_move {
 8879            if let Some(provider) = &self.edit_prediction_provider {
 8880                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8881            }
 8882            invalidation_row_range =
 8883                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8884            let target = first_edit_start;
 8885            EditPrediction::MoveWithin { target, snapshot }
 8886        } else {
 8887            let show_completions_in_menu = self.has_visible_completions_menu();
 8888            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8889                && !self.edit_predictions_hidden_for_vim_mode;
 8890
 8891            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8892                if provider.show_tab_accept_marker() {
 8893                    EditDisplayMode::TabAccept
 8894                } else {
 8895                    EditDisplayMode::Inline
 8896                }
 8897            } else {
 8898                EditDisplayMode::DiffPopover
 8899            };
 8900
 8901            let report_shown = match display_mode {
 8902                EditDisplayMode::DiffPopover | EditDisplayMode::Inline => {
 8903                    show_completions_in_buffer || show_completions_in_menu
 8904                }
 8905                EditDisplayMode::TabAccept => {
 8906                    show_completions_in_menu || self.edit_prediction_preview_is_active()
 8907                }
 8908            };
 8909
 8910            if report_shown && let Some(provider) = &self.edit_prediction_provider {
 8911                let suggestion_display_type = match display_mode {
 8912                    EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8913                    EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8914                        SuggestionDisplayType::GhostText
 8915                    }
 8916                };
 8917                provider.provider.did_show(suggestion_display_type, cx);
 8918            }
 8919
 8920            if show_completions_in_buffer {
 8921                if edits
 8922                    .iter()
 8923                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8924                {
 8925                    let mut inlays = Vec::new();
 8926                    for (range, new_text) in &edits {
 8927                        let inlay = Inlay::edit_prediction(
 8928                            post_inc(&mut self.next_inlay_id),
 8929                            range.start,
 8930                            new_text.as_ref(),
 8931                        );
 8932                        inlay_ids.push(inlay.id);
 8933                        inlays.push(inlay);
 8934                    }
 8935
 8936                    self.splice_inlays(&[], inlays, cx);
 8937                } else {
 8938                    let background_color = cx.theme().status().deleted_background;
 8939                    self.highlight_text(
 8940                        HighlightKey::EditPredictionHighlight,
 8941                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8942                        HighlightStyle {
 8943                            background_color: Some(background_color),
 8944                            ..Default::default()
 8945                        },
 8946                        cx,
 8947                    );
 8948                }
 8949            }
 8950
 8951            invalidation_row_range = edit_start_row..edit_end_row;
 8952
 8953            EditPrediction::Edit {
 8954                edits,
 8955                cursor_position,
 8956                edit_preview,
 8957                display_mode,
 8958                snapshot,
 8959            }
 8960        };
 8961
 8962        let invalidation_range = multibuffer
 8963            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8964            ..multibuffer.anchor_after(Point::new(
 8965                invalidation_row_range.end,
 8966                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8967            ));
 8968
 8969        self.stale_edit_prediction_in_menu = None;
 8970        self.active_edit_prediction = Some(EditPredictionState {
 8971            inlay_ids,
 8972            completion,
 8973            completion_id,
 8974            invalidation_range: Some(invalidation_range),
 8975        });
 8976
 8977        cx.notify();
 8978
 8979        Some(())
 8980    }
 8981
 8982    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8983        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8984    }
 8985
 8986    /// Get all display points of breakpoints that will be rendered within editor
 8987    ///
 8988    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8989    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8990    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8991    fn active_breakpoints(
 8992        &self,
 8993        range: Range<DisplayRow>,
 8994        window: &mut Window,
 8995        cx: &mut Context<Self>,
 8996    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8997        let mut breakpoint_display_points = HashMap::default();
 8998
 8999        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 9000            return breakpoint_display_points;
 9001        };
 9002
 9003        let snapshot = self.snapshot(window, cx);
 9004
 9005        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 9006
 9007        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 9008            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 9009
 9010        for (buffer_snapshot, range, _) in
 9011            multi_buffer_snapshot.range_to_buffer_ranges(range.start..range.end)
 9012        {
 9013            let Some(buffer) = self.buffer().read(cx).buffer(buffer_snapshot.remote_id()) else {
 9014                continue;
 9015            };
 9016            let breakpoints = breakpoint_store.read(cx).breakpoints(
 9017                &buffer,
 9018                Some(
 9019                    buffer_snapshot.anchor_before(range.start)
 9020                        ..buffer_snapshot.anchor_after(range.end),
 9021                ),
 9022                &buffer_snapshot,
 9023                cx,
 9024            );
 9025            for (breakpoint, state) in breakpoints {
 9026                let Some(multi_buffer_anchor) =
 9027                    multi_buffer_snapshot.anchor_in_excerpt(breakpoint.position)
 9028                else {
 9029                    continue;
 9030                };
 9031                let position = multi_buffer_anchor
 9032                    .to_point(&multi_buffer_snapshot)
 9033                    .to_display_point(&snapshot);
 9034
 9035                breakpoint_display_points.insert(
 9036                    position.row(),
 9037                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 9038                );
 9039            }
 9040        }
 9041
 9042        breakpoint_display_points
 9043    }
 9044
 9045    fn breakpoint_context_menu(
 9046        &self,
 9047        anchor: Anchor,
 9048        window: &mut Window,
 9049        cx: &mut Context<Self>,
 9050    ) -> Entity<ui::ContextMenu> {
 9051        let weak_editor = cx.weak_entity();
 9052        let focus_handle = self.focus_handle(cx);
 9053
 9054        let row = self
 9055            .buffer
 9056            .read(cx)
 9057            .snapshot(cx)
 9058            .summary_for_anchor::<Point>(&anchor)
 9059            .row;
 9060
 9061        let breakpoint = self
 9062            .breakpoint_at_row(row, window, cx)
 9063            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 9064
 9065        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 9066            "Edit Log Breakpoint"
 9067        } else {
 9068            "Set Log Breakpoint"
 9069        };
 9070
 9071        let condition_breakpoint_msg = if breakpoint
 9072            .as_ref()
 9073            .is_some_and(|bp| bp.1.condition.is_some())
 9074        {
 9075            "Edit Condition Breakpoint"
 9076        } else {
 9077            "Set Condition Breakpoint"
 9078        };
 9079
 9080        let hit_condition_breakpoint_msg = if breakpoint
 9081            .as_ref()
 9082            .is_some_and(|bp| bp.1.hit_condition.is_some())
 9083        {
 9084            "Edit Hit Condition Breakpoint"
 9085        } else {
 9086            "Set Hit Condition Breakpoint"
 9087        };
 9088
 9089        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 9090            "Unset Breakpoint"
 9091        } else {
 9092            "Set Breakpoint"
 9093        };
 9094
 9095        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 9096
 9097        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 9098            BreakpointState::Enabled => Some("Disable"),
 9099            BreakpointState::Disabled => Some("Enable"),
 9100        });
 9101
 9102        let (anchor, breakpoint) =
 9103            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 9104
 9105        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 9106            menu.on_blur_subscription(Subscription::new(|| {}))
 9107                .context(focus_handle)
 9108                .when(run_to_cursor, |this| {
 9109                    let weak_editor = weak_editor.clone();
 9110                    this.entry("Run to Cursor", None, move |window, cx| {
 9111                        weak_editor
 9112                            .update(cx, |editor, cx| {
 9113                                editor.change_selections(
 9114                                    SelectionEffects::no_scroll(),
 9115                                    window,
 9116                                    cx,
 9117                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 9118                                );
 9119                            })
 9120                            .ok();
 9121
 9122                        window.dispatch_action(Box::new(RunToCursor), cx);
 9123                    })
 9124                    .separator()
 9125                })
 9126                .when_some(toggle_state_msg, |this, msg| {
 9127                    this.entry(msg, None, {
 9128                        let weak_editor = weak_editor.clone();
 9129                        let breakpoint = breakpoint.clone();
 9130                        move |_window, cx| {
 9131                            weak_editor
 9132                                .update(cx, |this, cx| {
 9133                                    this.edit_breakpoint_at_anchor(
 9134                                        anchor,
 9135                                        breakpoint.as_ref().clone(),
 9136                                        BreakpointEditAction::InvertState,
 9137                                        cx,
 9138                                    );
 9139                                })
 9140                                .log_err();
 9141                        }
 9142                    })
 9143                })
 9144                .entry(set_breakpoint_msg, None, {
 9145                    let weak_editor = weak_editor.clone();
 9146                    let breakpoint = breakpoint.clone();
 9147                    move |_window, cx| {
 9148                        weak_editor
 9149                            .update(cx, |this, cx| {
 9150                                this.edit_breakpoint_at_anchor(
 9151                                    anchor,
 9152                                    breakpoint.as_ref().clone(),
 9153                                    BreakpointEditAction::Toggle,
 9154                                    cx,
 9155                                );
 9156                            })
 9157                            .log_err();
 9158                    }
 9159                })
 9160                .entry(log_breakpoint_msg, None, {
 9161                    let breakpoint = breakpoint.clone();
 9162                    let weak_editor = weak_editor.clone();
 9163                    move |window, cx| {
 9164                        weak_editor
 9165                            .update(cx, |this, cx| {
 9166                                this.add_edit_breakpoint_block(
 9167                                    anchor,
 9168                                    breakpoint.as_ref(),
 9169                                    BreakpointPromptEditAction::Log,
 9170                                    window,
 9171                                    cx,
 9172                                );
 9173                            })
 9174                            .log_err();
 9175                    }
 9176                })
 9177                .entry(condition_breakpoint_msg, None, {
 9178                    let breakpoint = breakpoint.clone();
 9179                    let weak_editor = weak_editor.clone();
 9180                    move |window, cx| {
 9181                        weak_editor
 9182                            .update(cx, |this, cx| {
 9183                                this.add_edit_breakpoint_block(
 9184                                    anchor,
 9185                                    breakpoint.as_ref(),
 9186                                    BreakpointPromptEditAction::Condition,
 9187                                    window,
 9188                                    cx,
 9189                                );
 9190                            })
 9191                            .log_err();
 9192                    }
 9193                })
 9194                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 9195                    weak_editor
 9196                        .update(cx, |this, cx| {
 9197                            this.add_edit_breakpoint_block(
 9198                                anchor,
 9199                                breakpoint.as_ref(),
 9200                                BreakpointPromptEditAction::HitCondition,
 9201                                window,
 9202                                cx,
 9203                            );
 9204                        })
 9205                        .log_err();
 9206                })
 9207        })
 9208    }
 9209
 9210    fn render_breakpoint(
 9211        &self,
 9212        position: Anchor,
 9213        row: DisplayRow,
 9214        breakpoint: &Breakpoint,
 9215        state: Option<BreakpointSessionState>,
 9216        cx: &mut Context<Self>,
 9217    ) -> IconButton {
 9218        let is_rejected = state.is_some_and(|s| !s.verified);
 9219        // Is it a breakpoint that shows up when hovering over gutter?
 9220        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9221            (false, false),
 9222            |PhantomBreakpointIndicator {
 9223                 is_active,
 9224                 display_row,
 9225                 collides_with_existing_breakpoint,
 9226             }| {
 9227                (
 9228                    is_active && display_row == row,
 9229                    collides_with_existing_breakpoint,
 9230                )
 9231            },
 9232        );
 9233
 9234        let (color, icon) = {
 9235            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9236                (false, false) => ui::IconName::DebugBreakpoint,
 9237                (true, false) => ui::IconName::DebugLogBreakpoint,
 9238                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9239                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9240            };
 9241
 9242            let theme_colors = cx.theme().colors();
 9243
 9244            let color = if is_phantom {
 9245                if collides_with_existing {
 9246                    Color::Custom(
 9247                        theme_colors
 9248                            .debugger_accent
 9249                            .blend(theme_colors.text.opacity(0.6)),
 9250                    )
 9251                } else {
 9252                    Color::Hint
 9253                }
 9254            } else if is_rejected {
 9255                Color::Disabled
 9256            } else {
 9257                Color::Debugger
 9258            };
 9259
 9260            (color, icon)
 9261        };
 9262
 9263        let breakpoint = Arc::from(breakpoint.clone());
 9264
 9265        let alt_as_text = gpui::Keystroke {
 9266            modifiers: Modifiers::secondary_key(),
 9267            ..Default::default()
 9268        };
 9269        let primary_action_text = if breakpoint.is_disabled() {
 9270            "Enable breakpoint"
 9271        } else if is_phantom && !collides_with_existing {
 9272            "Set breakpoint"
 9273        } else {
 9274            "Unset breakpoint"
 9275        };
 9276        let focus_handle = self.focus_handle.clone();
 9277
 9278        let meta = if is_rejected {
 9279            SharedString::from("No executable code is associated with this line.")
 9280        } else if collides_with_existing && !breakpoint.is_disabled() {
 9281            SharedString::from(format!(
 9282                "{alt_as_text}-click to disable,\nright-click for more options."
 9283            ))
 9284        } else {
 9285            SharedString::from("Right-click for more options.")
 9286        };
 9287        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9288            .icon_size(IconSize::XSmall)
 9289            .size(ui::ButtonSize::None)
 9290            .when(is_rejected, |this| {
 9291                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9292            })
 9293            .icon_color(color)
 9294            .style(ButtonStyle::Transparent)
 9295            .on_click(cx.listener({
 9296                move |editor, event: &ClickEvent, window, cx| {
 9297                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9298                        BreakpointEditAction::InvertState
 9299                    } else {
 9300                        BreakpointEditAction::Toggle
 9301                    };
 9302
 9303                    window.focus(&editor.focus_handle(cx), cx);
 9304                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9305                    editor.edit_breakpoint_at_anchor(
 9306                        position,
 9307                        breakpoint.as_ref().clone(),
 9308                        edit_action,
 9309                        cx,
 9310                    );
 9311                }
 9312            }))
 9313            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9314                editor.set_breakpoint_context_menu(
 9315                    row,
 9316                    Some(position),
 9317                    event.position(),
 9318                    window,
 9319                    cx,
 9320                );
 9321            }))
 9322            .tooltip(move |_window, cx| {
 9323                Tooltip::with_meta_in(
 9324                    primary_action_text,
 9325                    Some(&ToggleBreakpoint),
 9326                    meta.clone(),
 9327                    &focus_handle,
 9328                    cx,
 9329                )
 9330            })
 9331    }
 9332
 9333    fn build_tasks_context(
 9334        project: &Entity<Project>,
 9335        buffer: &Entity<Buffer>,
 9336        buffer_row: u32,
 9337        tasks: &Arc<RunnableTasks>,
 9338        cx: &mut Context<Self>,
 9339    ) -> Task<Option<task::TaskContext>> {
 9340        let position = Point::new(buffer_row, tasks.column);
 9341        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9342        let location = Location {
 9343            buffer: buffer.clone(),
 9344            range: range_start..range_start,
 9345        };
 9346        // Fill in the environmental variables from the tree-sitter captures
 9347        let mut captured_task_variables = TaskVariables::default();
 9348        for (capture_name, value) in tasks.extra_variables.clone() {
 9349            captured_task_variables.insert(
 9350                task::VariableName::Custom(capture_name.into()),
 9351                value.clone(),
 9352            );
 9353        }
 9354        project.update(cx, |project, cx| {
 9355            project.task_store().update(cx, |task_store, cx| {
 9356                task_store.task_context_for_location(captured_task_variables, location, cx)
 9357            })
 9358        })
 9359    }
 9360
 9361    pub fn context_menu_visible(&self) -> bool {
 9362        !self.edit_prediction_preview_is_active()
 9363            && self
 9364                .context_menu
 9365                .borrow()
 9366                .as_ref()
 9367                .is_some_and(|menu| menu.visible())
 9368    }
 9369
 9370    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9371        self.context_menu
 9372            .borrow()
 9373            .as_ref()
 9374            .map(|menu| menu.origin())
 9375    }
 9376
 9377    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9378        self.context_menu_options = Some(options);
 9379    }
 9380
 9381    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9382    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9383
 9384    fn render_edit_prediction_popover(
 9385        &mut self,
 9386        text_bounds: &Bounds<Pixels>,
 9387        content_origin: gpui::Point<Pixels>,
 9388        right_margin: Pixels,
 9389        editor_snapshot: &EditorSnapshot,
 9390        visible_row_range: Range<DisplayRow>,
 9391        scroll_top: ScrollOffset,
 9392        scroll_bottom: ScrollOffset,
 9393        line_layouts: &[LineWithInvisibles],
 9394        line_height: Pixels,
 9395        scroll_position: gpui::Point<ScrollOffset>,
 9396        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9397        newest_selection_head: Option<DisplayPoint>,
 9398        editor_width: Pixels,
 9399        style: &EditorStyle,
 9400        window: &mut Window,
 9401        cx: &mut App,
 9402    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9403        if self.mode().is_minimap() {
 9404            return None;
 9405        }
 9406        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9407
 9408        if self.edit_prediction_visible_in_cursor_popover(true) {
 9409            return None;
 9410        }
 9411
 9412        match &active_edit_prediction.completion {
 9413            EditPrediction::MoveWithin { target, .. } => {
 9414                let target_display_point = target.to_display_point(editor_snapshot);
 9415
 9416                if self.edit_prediction_requires_modifier() {
 9417                    if !self.edit_prediction_preview_is_active() {
 9418                        return None;
 9419                    }
 9420
 9421                    self.render_edit_prediction_modifier_jump_popover(
 9422                        text_bounds,
 9423                        content_origin,
 9424                        visible_row_range,
 9425                        line_layouts,
 9426                        line_height,
 9427                        scroll_pixel_position,
 9428                        newest_selection_head,
 9429                        target_display_point,
 9430                        window,
 9431                        cx,
 9432                    )
 9433                } else {
 9434                    self.render_edit_prediction_eager_jump_popover(
 9435                        text_bounds,
 9436                        content_origin,
 9437                        editor_snapshot,
 9438                        visible_row_range,
 9439                        scroll_top,
 9440                        scroll_bottom,
 9441                        line_height,
 9442                        scroll_pixel_position,
 9443                        target_display_point,
 9444                        editor_width,
 9445                        window,
 9446                        cx,
 9447                    )
 9448                }
 9449            }
 9450            EditPrediction::Edit {
 9451                display_mode: EditDisplayMode::Inline,
 9452                ..
 9453            } => None,
 9454            EditPrediction::Edit {
 9455                display_mode: EditDisplayMode::TabAccept,
 9456                edits,
 9457                ..
 9458            } => {
 9459                let range = &edits.first()?.0;
 9460                let target_display_point = range.end.to_display_point(editor_snapshot);
 9461
 9462                self.render_edit_prediction_end_of_line_popover(
 9463                    "Accept",
 9464                    editor_snapshot,
 9465                    visible_row_range,
 9466                    target_display_point,
 9467                    line_height,
 9468                    scroll_pixel_position,
 9469                    content_origin,
 9470                    editor_width,
 9471                    window,
 9472                    cx,
 9473                )
 9474            }
 9475            EditPrediction::Edit {
 9476                edits,
 9477                edit_preview,
 9478                display_mode: EditDisplayMode::DiffPopover,
 9479                snapshot,
 9480                ..
 9481            } => self.render_edit_prediction_diff_popover(
 9482                text_bounds,
 9483                content_origin,
 9484                right_margin,
 9485                editor_snapshot,
 9486                visible_row_range,
 9487                line_layouts,
 9488                line_height,
 9489                scroll_position,
 9490                scroll_pixel_position,
 9491                newest_selection_head,
 9492                editor_width,
 9493                style,
 9494                edits,
 9495                edit_preview,
 9496                snapshot,
 9497                window,
 9498                cx,
 9499            ),
 9500            EditPrediction::MoveOutside { snapshot, .. } => {
 9501                let mut element = self
 9502                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9503                    .into_any();
 9504
 9505                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9506                let origin_x = text_bounds.size.width - size.width - px(30.);
 9507                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9508                element.prepaint_at(origin, window, cx);
 9509
 9510                Some((element, origin))
 9511            }
 9512        }
 9513    }
 9514
 9515    fn render_edit_prediction_modifier_jump_popover(
 9516        &mut self,
 9517        text_bounds: &Bounds<Pixels>,
 9518        content_origin: gpui::Point<Pixels>,
 9519        visible_row_range: Range<DisplayRow>,
 9520        line_layouts: &[LineWithInvisibles],
 9521        line_height: Pixels,
 9522        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9523        newest_selection_head: Option<DisplayPoint>,
 9524        target_display_point: DisplayPoint,
 9525        window: &mut Window,
 9526        cx: &mut App,
 9527    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9528        let scrolled_content_origin =
 9529            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9530
 9531        const SCROLL_PADDING_Y: Pixels = px(12.);
 9532
 9533        if target_display_point.row() < visible_row_range.start {
 9534            return self.render_edit_prediction_scroll_popover(
 9535                &|_| SCROLL_PADDING_Y,
 9536                IconName::ArrowUp,
 9537                visible_row_range,
 9538                line_layouts,
 9539                newest_selection_head,
 9540                scrolled_content_origin,
 9541                window,
 9542                cx,
 9543            );
 9544        } else if target_display_point.row() >= visible_row_range.end {
 9545            return self.render_edit_prediction_scroll_popover(
 9546                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9547                IconName::ArrowDown,
 9548                visible_row_range,
 9549                line_layouts,
 9550                newest_selection_head,
 9551                scrolled_content_origin,
 9552                window,
 9553                cx,
 9554            );
 9555        }
 9556
 9557        const POLE_WIDTH: Pixels = px(2.);
 9558
 9559        let line_layout =
 9560            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9561        let target_column = target_display_point.column() as usize;
 9562
 9563        let target_x = line_layout.x_for_index(target_column);
 9564        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9565            - scroll_pixel_position.y;
 9566
 9567        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9568
 9569        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9570        border_color.l += 0.001;
 9571
 9572        let mut element = v_flex()
 9573            .items_end()
 9574            .when(flag_on_right, |el| el.items_start())
 9575            .child(if flag_on_right {
 9576                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9577                    .rounded_bl(px(0.))
 9578                    .rounded_tl(px(0.))
 9579                    .border_l_2()
 9580                    .border_color(border_color)
 9581            } else {
 9582                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9583                    .rounded_br(px(0.))
 9584                    .rounded_tr(px(0.))
 9585                    .border_r_2()
 9586                    .border_color(border_color)
 9587            })
 9588            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9589            .into_any();
 9590
 9591        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9592
 9593        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9594            - point(
 9595                if flag_on_right {
 9596                    POLE_WIDTH
 9597                } else {
 9598                    size.width - POLE_WIDTH
 9599                },
 9600                size.height - line_height,
 9601            );
 9602
 9603        origin.x = origin.x.max(content_origin.x);
 9604
 9605        element.prepaint_at(origin, window, cx);
 9606
 9607        Some((element, origin))
 9608    }
 9609
 9610    fn render_edit_prediction_scroll_popover(
 9611        &mut self,
 9612        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9613        scroll_icon: IconName,
 9614        visible_row_range: Range<DisplayRow>,
 9615        line_layouts: &[LineWithInvisibles],
 9616        newest_selection_head: Option<DisplayPoint>,
 9617        scrolled_content_origin: gpui::Point<Pixels>,
 9618        window: &mut Window,
 9619        cx: &mut App,
 9620    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9621        let mut element = self
 9622            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9623            .into_any();
 9624
 9625        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9626
 9627        let cursor = newest_selection_head?;
 9628        let cursor_row_layout =
 9629            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9630        let cursor_column = cursor.column() as usize;
 9631
 9632        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9633
 9634        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9635
 9636        element.prepaint_at(origin, window, cx);
 9637        Some((element, origin))
 9638    }
 9639
 9640    fn render_edit_prediction_eager_jump_popover(
 9641        &mut self,
 9642        text_bounds: &Bounds<Pixels>,
 9643        content_origin: gpui::Point<Pixels>,
 9644        editor_snapshot: &EditorSnapshot,
 9645        visible_row_range: Range<DisplayRow>,
 9646        scroll_top: ScrollOffset,
 9647        scroll_bottom: ScrollOffset,
 9648        line_height: Pixels,
 9649        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9650        target_display_point: DisplayPoint,
 9651        editor_width: Pixels,
 9652        window: &mut Window,
 9653        cx: &mut App,
 9654    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9655        if target_display_point.row().as_f64() < scroll_top {
 9656            let mut element = self
 9657                .render_edit_prediction_line_popover(
 9658                    "Jump to Edit",
 9659                    Some(IconName::ArrowUp),
 9660                    window,
 9661                    cx,
 9662                )
 9663                .into_any();
 9664
 9665            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9666            let offset = point(
 9667                (text_bounds.size.width - size.width) / 2.,
 9668                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9669            );
 9670
 9671            let origin = text_bounds.origin + offset;
 9672            element.prepaint_at(origin, window, cx);
 9673            Some((element, origin))
 9674        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9675            let mut element = self
 9676                .render_edit_prediction_line_popover(
 9677                    "Jump to Edit",
 9678                    Some(IconName::ArrowDown),
 9679                    window,
 9680                    cx,
 9681                )
 9682                .into_any();
 9683
 9684            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9685            let offset = point(
 9686                (text_bounds.size.width - size.width) / 2.,
 9687                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9688            );
 9689
 9690            let origin = text_bounds.origin + offset;
 9691            element.prepaint_at(origin, window, cx);
 9692            Some((element, origin))
 9693        } else {
 9694            self.render_edit_prediction_end_of_line_popover(
 9695                "Jump to Edit",
 9696                editor_snapshot,
 9697                visible_row_range,
 9698                target_display_point,
 9699                line_height,
 9700                scroll_pixel_position,
 9701                content_origin,
 9702                editor_width,
 9703                window,
 9704                cx,
 9705            )
 9706        }
 9707    }
 9708
 9709    fn render_edit_prediction_end_of_line_popover(
 9710        self: &mut Editor,
 9711        label: &'static str,
 9712        editor_snapshot: &EditorSnapshot,
 9713        visible_row_range: Range<DisplayRow>,
 9714        target_display_point: DisplayPoint,
 9715        line_height: Pixels,
 9716        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9717        content_origin: gpui::Point<Pixels>,
 9718        editor_width: Pixels,
 9719        window: &mut Window,
 9720        cx: &mut App,
 9721    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9722        let target_line_end = DisplayPoint::new(
 9723            target_display_point.row(),
 9724            editor_snapshot.line_len(target_display_point.row()),
 9725        );
 9726
 9727        let mut element = self
 9728            .render_edit_prediction_line_popover(label, None, window, cx)
 9729            .into_any();
 9730
 9731        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9732
 9733        let line_origin =
 9734            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9735
 9736        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9737        let mut origin = start_point
 9738            + line_origin
 9739            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9740        origin.x = origin.x.max(content_origin.x);
 9741
 9742        let max_x = content_origin.x + editor_width - size.width;
 9743
 9744        if origin.x > max_x {
 9745            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9746
 9747            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9748                origin.y += offset;
 9749                IconName::ArrowUp
 9750            } else {
 9751                origin.y -= offset;
 9752                IconName::ArrowDown
 9753            };
 9754
 9755            element = self
 9756                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9757                .into_any();
 9758
 9759            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9760
 9761            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9762        }
 9763
 9764        element.prepaint_at(origin, window, cx);
 9765        Some((element, origin))
 9766    }
 9767
 9768    fn render_edit_prediction_diff_popover(
 9769        self: &Editor,
 9770        text_bounds: &Bounds<Pixels>,
 9771        content_origin: gpui::Point<Pixels>,
 9772        right_margin: Pixels,
 9773        editor_snapshot: &EditorSnapshot,
 9774        visible_row_range: Range<DisplayRow>,
 9775        line_layouts: &[LineWithInvisibles],
 9776        line_height: Pixels,
 9777        scroll_position: gpui::Point<ScrollOffset>,
 9778        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9779        newest_selection_head: Option<DisplayPoint>,
 9780        editor_width: Pixels,
 9781        style: &EditorStyle,
 9782        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9783        edit_preview: &Option<language::EditPreview>,
 9784        snapshot: &language::BufferSnapshot,
 9785        window: &mut Window,
 9786        cx: &mut App,
 9787    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9788        let edit_start = edits
 9789            .first()
 9790            .unwrap()
 9791            .0
 9792            .start
 9793            .to_display_point(editor_snapshot);
 9794        let edit_end = edits
 9795            .last()
 9796            .unwrap()
 9797            .0
 9798            .end
 9799            .to_display_point(editor_snapshot);
 9800
 9801        let is_visible = visible_row_range.contains(&edit_start.row())
 9802            || visible_row_range.contains(&edit_end.row());
 9803        if !is_visible {
 9804            return None;
 9805        }
 9806
 9807        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9808            crate::edit_prediction_edit_text(
 9809                snapshot,
 9810                edits,
 9811                edit_preview,
 9812                false,
 9813                editor_snapshot.buffer_snapshot(),
 9814                cx,
 9815            )
 9816        } else {
 9817            // Fallback for providers without edit_preview
 9818            crate::edit_prediction_fallback_text(edits, cx)
 9819        };
 9820
 9821        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9822        let line_count = highlighted_edits.text.lines().count();
 9823
 9824        const BORDER_WIDTH: Pixels = px(1.);
 9825
 9826        let keybind = self.render_edit_prediction_keybind(window, cx);
 9827        let has_keybind = keybind.is_some();
 9828
 9829        let mut element = h_flex()
 9830            .items_start()
 9831            .child(
 9832                h_flex()
 9833                    .bg(cx.theme().colors().editor_background)
 9834                    .border(BORDER_WIDTH)
 9835                    .shadow_xs()
 9836                    .border_color(cx.theme().colors().border)
 9837                    .rounded_l_lg()
 9838                    .when(line_count > 1, |el| el.rounded_br_lg())
 9839                    .pr_1()
 9840                    .child(styled_text),
 9841            )
 9842            .child(
 9843                h_flex()
 9844                    .h(line_height + BORDER_WIDTH * 2.)
 9845                    .px_1p5()
 9846                    .gap_1()
 9847                    // Workaround: For some reason, there's a gap if we don't do this
 9848                    .ml(-BORDER_WIDTH)
 9849                    .shadow(vec![gpui::BoxShadow {
 9850                        color: gpui::black().opacity(0.05),
 9851                        offset: point(px(1.), px(1.)),
 9852                        blur_radius: px(2.),
 9853                        spread_radius: px(0.),
 9854                    }])
 9855                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9856                    .border(BORDER_WIDTH)
 9857                    .border_color(cx.theme().colors().border)
 9858                    .rounded_r_lg()
 9859                    .id("edit_prediction_diff_popover_keybind")
 9860                    .when(!has_keybind, |el| {
 9861                        let status_colors = cx.theme().status();
 9862
 9863                        el.bg(status_colors.error_background)
 9864                            .border_color(status_colors.error.opacity(0.6))
 9865                            .child(Icon::new(IconName::Info).color(Color::Error))
 9866                            .cursor_default()
 9867                            .hoverable_tooltip(move |_window, cx| {
 9868                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9869                            })
 9870                    })
 9871                    .children(keybind),
 9872            )
 9873            .into_any();
 9874
 9875        let longest_row =
 9876            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9877        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9878            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9879        } else {
 9880            layout_line(
 9881                longest_row,
 9882                editor_snapshot,
 9883                style,
 9884                editor_width,
 9885                |_| false,
 9886                window,
 9887                cx,
 9888            )
 9889            .width
 9890        };
 9891
 9892        let viewport_bounds =
 9893            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9894                right: -right_margin,
 9895                ..Default::default()
 9896            });
 9897
 9898        let x_after_longest = Pixels::from(
 9899            ScrollPixelOffset::from(
 9900                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9901            ) - scroll_pixel_position.x,
 9902        );
 9903
 9904        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9905
 9906        // Fully visible if it can be displayed within the window (allow overlapping other
 9907        // panes). However, this is only allowed if the popover starts within text_bounds.
 9908        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9909            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9910
 9911        let mut origin = if can_position_to_the_right {
 9912            point(
 9913                x_after_longest,
 9914                text_bounds.origin.y
 9915                    + Pixels::from(
 9916                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9917                            - scroll_pixel_position.y,
 9918                    ),
 9919            )
 9920        } else {
 9921            let cursor_row = newest_selection_head.map(|head| head.row());
 9922            let above_edit = edit_start
 9923                .row()
 9924                .0
 9925                .checked_sub(line_count as u32)
 9926                .map(DisplayRow);
 9927            let below_edit = Some(edit_end.row() + 1);
 9928            let above_cursor =
 9929                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9930            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9931
 9932            // Place the edit popover adjacent to the edit if there is a location
 9933            // available that is onscreen and does not obscure the cursor. Otherwise,
 9934            // place it adjacent to the cursor.
 9935            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9936                .into_iter()
 9937                .flatten()
 9938                .find(|&start_row| {
 9939                    let end_row = start_row + line_count as u32;
 9940                    visible_row_range.contains(&start_row)
 9941                        && visible_row_range.contains(&end_row)
 9942                        && cursor_row
 9943                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9944                })?;
 9945
 9946            content_origin
 9947                + point(
 9948                    Pixels::from(-scroll_pixel_position.x),
 9949                    Pixels::from(
 9950                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9951                    ),
 9952                )
 9953        };
 9954
 9955        origin.x -= BORDER_WIDTH;
 9956
 9957        window.with_content_mask(
 9958            Some(gpui::ContentMask {
 9959                bounds: *text_bounds,
 9960            }),
 9961            |window| {
 9962                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9963            },
 9964        );
 9965
 9966        // Do not return an element, since it will already be drawn due to defer_draw.
 9967        None
 9968    }
 9969
 9970    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9971        px(30.)
 9972    }
 9973
 9974    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9975        if self.read_only(cx) {
 9976            cx.theme().players().read_only()
 9977        } else {
 9978            self.style.as_ref().unwrap().local_player
 9979        }
 9980    }
 9981
 9982    fn render_edit_prediction_inline_keystroke(
 9983        &self,
 9984        keystroke: &gpui::KeybindingKeystroke,
 9985        modifiers_color: Color,
 9986        cx: &App,
 9987    ) -> AnyElement {
 9988        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9989
 9990        h_flex()
 9991            .px_0p5()
 9992            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9993            .font(
 9994                theme_settings::ThemeSettings::get_global(cx)
 9995                    .buffer_font
 9996                    .clone(),
 9997            )
 9998            .text_size(TextSize::XSmall.rems(cx))
 9999            .child(h_flex().children(ui::render_modifiers(
10000                keystroke.modifiers(),
10001                PlatformStyle::platform(),
10002                Some(modifiers_color),
10003                Some(IconSize::XSmall.rems().into()),
10004                true,
10005            )))
10006            .when(is_platform_style_mac, |parent| {
10007                parent.child(keystroke.key().to_string())
10008            })
10009            .when(!is_platform_style_mac, |parent| {
10010                parent.child(
10011                    Key::new(ui::utils::capitalize(keystroke.key()), Some(Color::Default))
10012                        .size(Some(IconSize::XSmall.rems().into())),
10013                )
10014            })
10015            .into_any()
10016    }
10017
10018    fn render_edit_prediction_popover_keystroke(
10019        &self,
10020        keystroke: &gpui::KeybindingKeystroke,
10021        color: Color,
10022        cx: &App,
10023    ) -> AnyElement {
10024        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10025
10026        if keystroke.modifiers().modified() {
10027            h_flex()
10028                .font(
10029                    theme_settings::ThemeSettings::get_global(cx)
10030                        .buffer_font
10031                        .clone(),
10032                )
10033                .when(is_platform_style_mac, |parent| parent.gap_1())
10034                .child(h_flex().children(ui::render_modifiers(
10035                    keystroke.modifiers(),
10036                    PlatformStyle::platform(),
10037                    Some(color),
10038                    None,
10039                    false,
10040                )))
10041                .into_any()
10042        } else {
10043            Key::new(ui::utils::capitalize(keystroke.key()), Some(color))
10044                .size(Some(IconSize::XSmall.rems().into()))
10045                .into_any_element()
10046        }
10047    }
10048
10049    fn render_edit_prediction_keybind(
10050        &self,
10051        window: &mut Window,
10052        cx: &mut App,
10053    ) -> Option<AnyElement> {
10054        let keybind_display =
10055            self.edit_prediction_keybind_display(EditPredictionKeybindSurface::Inline, window, cx);
10056        let keystroke = keybind_display.displayed_keystroke.as_ref()?;
10057
10058        let modifiers_color = if *keystroke.modifiers() == window.modifiers() {
10059            Color::Accent
10060        } else {
10061            Color::Muted
10062        };
10063
10064        Some(self.render_edit_prediction_inline_keystroke(keystroke, modifiers_color, cx))
10065    }
10066
10067    fn render_edit_prediction_line_popover(
10068        &self,
10069        label: impl Into<SharedString>,
10070        icon: Option<IconName>,
10071        window: &mut Window,
10072        cx: &mut App,
10073    ) -> Stateful<Div> {
10074        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
10075
10076        let keybind = self.render_edit_prediction_keybind(window, cx);
10077        let has_keybind = keybind.is_some();
10078        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10079
10080        h_flex()
10081            .id("ep-line-popover")
10082            .py_0p5()
10083            .pl_1()
10084            .pr(padding_right)
10085            .gap_1()
10086            .rounded_md()
10087            .border_1()
10088            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10089            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10090            .shadow_xs()
10091            .when(!has_keybind, |el| {
10092                let status_colors = cx.theme().status();
10093
10094                el.bg(status_colors.error_background)
10095                    .border_color(status_colors.error.opacity(0.6))
10096                    .pl_2()
10097                    .child(Icon::new(icons.error).color(Color::Error))
10098                    .cursor_default()
10099                    .hoverable_tooltip(move |_window, cx| {
10100                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10101                    })
10102            })
10103            .children(keybind)
10104            .child(
10105                Label::new(label)
10106                    .size(LabelSize::Small)
10107                    .when(!has_keybind, |el| {
10108                        el.color(cx.theme().status().error.into()).strikethrough()
10109                    }),
10110            )
10111            .when(!has_keybind, |el| {
10112                el.child(
10113                    h_flex().ml_1().child(
10114                        Icon::new(IconName::Info)
10115                            .size(IconSize::Small)
10116                            .color(cx.theme().status().error.into()),
10117                    ),
10118                )
10119            })
10120            .when_some(icon, |element, icon| {
10121                element.child(
10122                    div()
10123                        .mt(px(1.5))
10124                        .child(Icon::new(icon).size(IconSize::Small)),
10125                )
10126            })
10127    }
10128
10129    fn render_edit_prediction_jump_outside_popover(
10130        &self,
10131        snapshot: &BufferSnapshot,
10132        window: &mut Window,
10133        cx: &mut App,
10134    ) -> Stateful<Div> {
10135        let keybind = self.render_edit_prediction_keybind(window, cx);
10136        let has_keybind = keybind.is_some();
10137        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10138
10139        let file_name = snapshot
10140            .file()
10141            .map(|file| SharedString::new(file.file_name(cx)))
10142            .unwrap_or(SharedString::new_static("untitled"));
10143
10144        h_flex()
10145            .id("ep-jump-outside-popover")
10146            .py_1()
10147            .px_2()
10148            .gap_1()
10149            .rounded_md()
10150            .border_1()
10151            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10152            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
10153            .shadow_xs()
10154            .when(!has_keybind, |el| {
10155                let status_colors = cx.theme().status();
10156
10157                el.bg(status_colors.error_background)
10158                    .border_color(status_colors.error.opacity(0.6))
10159                    .pl_2()
10160                    .child(Icon::new(icons.error).color(Color::Error))
10161                    .cursor_default()
10162                    .hoverable_tooltip(move |_window, cx| {
10163                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
10164                    })
10165            })
10166            .children(keybind)
10167            .child(
10168                Label::new(file_name)
10169                    .size(LabelSize::Small)
10170                    .buffer_font(cx)
10171                    .when(!has_keybind, |el| {
10172                        el.color(cx.theme().status().error.into()).strikethrough()
10173                    }),
10174            )
10175            .when(!has_keybind, |el| {
10176                el.child(
10177                    h_flex().ml_1().child(
10178                        Icon::new(IconName::Info)
10179                            .size(IconSize::Small)
10180                            .color(cx.theme().status().error.into()),
10181                    ),
10182                )
10183            })
10184            .child(
10185                div()
10186                    .mt(px(1.5))
10187                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
10188            )
10189    }
10190
10191    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
10192        let accent_color = cx.theme().colors().text_accent;
10193        let editor_bg_color = cx.theme().colors().editor_background;
10194        editor_bg_color.blend(accent_color.opacity(0.1))
10195    }
10196
10197    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
10198        let accent_color = cx.theme().colors().text_accent;
10199        let editor_bg_color = cx.theme().colors().editor_background;
10200        editor_bg_color.blend(accent_color.opacity(0.6))
10201    }
10202    fn get_prediction_provider_icons(
10203        provider: &Option<RegisteredEditPredictionDelegate>,
10204        cx: &App,
10205    ) -> edit_prediction_types::EditPredictionIconSet {
10206        match provider {
10207            Some(provider) => provider.provider.icons(cx),
10208            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
10209        }
10210    }
10211
10212    fn render_edit_prediction_cursor_popover(
10213        &self,
10214        min_width: Pixels,
10215        max_width: Pixels,
10216        cursor_point: Point,
10217        style: &EditorStyle,
10218        window: &mut Window,
10219        cx: &mut Context<Editor>,
10220    ) -> Option<AnyElement> {
10221        let provider = self.edit_prediction_provider.as_ref()?;
10222        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10223
10224        let is_refreshing = provider.provider.is_refreshing(cx);
10225
10226        fn pending_completion_container(icon: IconName) -> Div {
10227            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
10228        }
10229
10230        let completion = match &self.active_edit_prediction {
10231            Some(prediction) => {
10232                if !self.has_visible_completions_menu() {
10233                    const RADIUS: Pixels = px(6.);
10234                    const BORDER_WIDTH: Pixels = px(1.);
10235                    let keybind_display = self.edit_prediction_keybind_display(
10236                        EditPredictionKeybindSurface::CursorPopoverCompact,
10237                        window,
10238                        cx,
10239                    );
10240
10241                    return Some(
10242                        h_flex()
10243                            .elevation_2(cx)
10244                            .border(BORDER_WIDTH)
10245                            .border_color(cx.theme().colors().border)
10246                            .when(keybind_display.missing_accept_keystroke, |el| {
10247                                el.border_color(cx.theme().status().error)
10248                            })
10249                            .rounded(RADIUS)
10250                            .rounded_tl(px(0.))
10251                            .overflow_hidden()
10252                            .child(div().px_1p5().child(match &prediction.completion {
10253                                EditPrediction::MoveWithin { target, snapshot } => {
10254                                    use text::ToPoint as _;
10255                                    if target.text_anchor_in(&snapshot).to_point(snapshot).row
10256                                        > cursor_point.row
10257                                    {
10258                                        Icon::new(icons.down)
10259                                    } else {
10260                                        Icon::new(icons.up)
10261                                    }
10262                                }
10263                                EditPrediction::MoveOutside { .. } => {
10264                                    // TODO [zeta2] custom icon for external jump?
10265                                    Icon::new(icons.base)
10266                                }
10267                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10268                            }))
10269                            .child(
10270                                h_flex()
10271                                    .gap_1()
10272                                    .py_1()
10273                                    .px_2()
10274                                    .rounded_r(RADIUS - BORDER_WIDTH)
10275                                    .border_l_1()
10276                                    .border_color(cx.theme().colors().border)
10277                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10278                                    .when(keybind_display.show_hold_label, |el| {
10279                                        el.child(
10280                                            Label::new("Hold")
10281                                                .size(LabelSize::Small)
10282                                                .when(
10283                                                    keybind_display.missing_accept_keystroke,
10284                                                    |el| el.strikethrough(),
10285                                                )
10286                                                .line_height_style(LineHeightStyle::UiLabel),
10287                                        )
10288                                    })
10289                                    .id("edit_prediction_cursor_popover_keybind")
10290                                    .when(keybind_display.missing_accept_keystroke, |el| {
10291                                        let status_colors = cx.theme().status();
10292
10293                                        el.bg(status_colors.error_background)
10294                                            .border_color(status_colors.error.opacity(0.6))
10295                                            .child(Icon::new(IconName::Info).color(Color::Error))
10296                                            .cursor_default()
10297                                            .hoverable_tooltip(move |_window, cx| {
10298                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10299                                                    .into()
10300                                            })
10301                                    })
10302                                    .when_some(
10303                                        keybind_display.displayed_keystroke.as_ref(),
10304                                        |el, compact_keystroke| {
10305                                            el.child(self.render_edit_prediction_popover_keystroke(
10306                                                compact_keystroke,
10307                                                Color::Default,
10308                                                cx,
10309                                            ))
10310                                        },
10311                                    ),
10312                            )
10313                            .into_any(),
10314                    );
10315                }
10316
10317                self.render_edit_prediction_cursor_popover_preview(
10318                    prediction,
10319                    cursor_point,
10320                    style,
10321                    cx,
10322                )?
10323            }
10324
10325            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10326                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10327                    stale_completion,
10328                    cursor_point,
10329                    style,
10330                    cx,
10331                )?,
10332
10333                None => pending_completion_container(icons.base)
10334                    .child(Label::new("...").size(LabelSize::Small)),
10335            },
10336
10337            None => pending_completion_container(icons.base)
10338                .child(Label::new("...").size(LabelSize::Small)),
10339        };
10340
10341        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10342            completion
10343                .with_animation(
10344                    "loading-completion",
10345                    Animation::new(Duration::from_secs(2))
10346                        .repeat()
10347                        .with_easing(pulsating_between(0.4, 0.8)),
10348                    |label, delta| label.opacity(delta),
10349                )
10350                .into_any_element()
10351        } else {
10352            completion.into_any_element()
10353        };
10354
10355        let has_completion = self.active_edit_prediction.is_some();
10356        let keybind_display = self.edit_prediction_keybind_display(
10357            EditPredictionKeybindSurface::CursorPopoverExpanded,
10358            window,
10359            cx,
10360        );
10361
10362        Some(
10363            h_flex()
10364                .min_w(min_width)
10365                .max_w(max_width)
10366                .flex_1()
10367                .elevation_2(cx)
10368                .border_color(cx.theme().colors().border)
10369                .child(
10370                    div()
10371                        .flex_1()
10372                        .py_1()
10373                        .px_2()
10374                        .overflow_hidden()
10375                        .child(completion),
10376                )
10377                .when_some(
10378                    keybind_display.displayed_keystroke.as_ref(),
10379                    |el, keystroke| {
10380                        let key_color = if !has_completion {
10381                            Color::Muted
10382                        } else {
10383                            Color::Default
10384                        };
10385
10386                        if keybind_display.action == EditPredictionKeybindAction::Preview {
10387                            el.child(
10388                                h_flex()
10389                                    .h_full()
10390                                    .border_l_1()
10391                                    .rounded_r_lg()
10392                                    .border_color(cx.theme().colors().border)
10393                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10394                                    .gap_1()
10395                                    .py_1()
10396                                    .px_2()
10397                                    .child(self.render_edit_prediction_popover_keystroke(
10398                                        keystroke, key_color, cx,
10399                                    ))
10400                                    .child(Label::new("Preview").into_any_element())
10401                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10402                            )
10403                        } else {
10404                            el.child(
10405                                h_flex()
10406                                    .h_full()
10407                                    .border_l_1()
10408                                    .rounded_r_lg()
10409                                    .border_color(cx.theme().colors().border)
10410                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10411                                    .gap_1()
10412                                    .py_1()
10413                                    .px_2()
10414                                    .child(self.render_edit_prediction_popover_keystroke(
10415                                        keystroke, key_color, cx,
10416                                    ))
10417                                    .opacity(if has_completion { 1.0 } else { 0.4 }),
10418                            )
10419                        }
10420                    },
10421                )
10422                .into_any(),
10423        )
10424    }
10425
10426    fn render_edit_prediction_cursor_popover_preview(
10427        &self,
10428        completion: &EditPredictionState,
10429        cursor_point: Point,
10430        style: &EditorStyle,
10431        cx: &mut Context<Editor>,
10432    ) -> Option<Div> {
10433        use text::ToPoint as _;
10434
10435        fn render_relative_row_jump(
10436            prefix: impl Into<String>,
10437            current_row: u32,
10438            target_row: u32,
10439        ) -> Div {
10440            let (row_diff, arrow) = if target_row < current_row {
10441                (current_row - target_row, IconName::ArrowUp)
10442            } else {
10443                (target_row - current_row, IconName::ArrowDown)
10444            };
10445
10446            h_flex()
10447                .child(
10448                    Label::new(format!("{}{}", prefix.into(), row_diff))
10449                        .color(Color::Muted)
10450                        .size(LabelSize::Small),
10451                )
10452                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10453        }
10454
10455        let supports_jump = self
10456            .edit_prediction_provider
10457            .as_ref()
10458            .map(|provider| provider.provider.supports_jump_to_edit())
10459            .unwrap_or(true);
10460
10461        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10462
10463        match &completion.completion {
10464            EditPrediction::MoveWithin {
10465                target, snapshot, ..
10466            } => {
10467                if !supports_jump {
10468                    return None;
10469                }
10470                let (target, _) = self.display_snapshot(cx).anchor_to_buffer_anchor(*target)?;
10471
10472                Some(
10473                    h_flex()
10474                        .px_2()
10475                        .gap_2()
10476                        .flex_1()
10477                        .child(if target.to_point(snapshot).row > cursor_point.row {
10478                            Icon::new(icons.down)
10479                        } else {
10480                            Icon::new(icons.up)
10481                        })
10482                        .child(Label::new("Jump to Edit")),
10483                )
10484            }
10485            EditPrediction::MoveOutside { snapshot, .. } => {
10486                let file_name = snapshot
10487                    .file()
10488                    .map(|file| file.file_name(cx))
10489                    .unwrap_or("untitled");
10490                Some(
10491                    h_flex()
10492                        .px_2()
10493                        .gap_2()
10494                        .flex_1()
10495                        .child(Icon::new(icons.base))
10496                        .child(Label::new(format!("Jump to {file_name}"))),
10497                )
10498            }
10499            EditPrediction::Edit {
10500                edits,
10501                edit_preview,
10502                snapshot,
10503                ..
10504            } => {
10505                let first_edit_row = self
10506                    .display_snapshot(cx)
10507                    .anchor_to_buffer_anchor(edits.first()?.0.start)?
10508                    .0
10509                    .to_point(snapshot)
10510                    .row;
10511
10512                let (highlighted_edits, has_more_lines) =
10513                    if let Some(edit_preview) = edit_preview.as_ref() {
10514                        crate::edit_prediction_edit_text(
10515                            snapshot,
10516                            edits,
10517                            edit_preview,
10518                            true,
10519                            &self.display_snapshot(cx),
10520                            cx,
10521                        )
10522                        .first_line_preview()
10523                    } else {
10524                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10525                    };
10526
10527                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10528                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10529
10530                let preview = h_flex()
10531                    .gap_1()
10532                    .min_w_16()
10533                    .child(styled_text)
10534                    .when(has_more_lines, |parent| parent.child(""));
10535
10536                let left = if supports_jump && first_edit_row != cursor_point.row {
10537                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10538                        .into_any_element()
10539                } else {
10540                    Icon::new(icons.base).into_any_element()
10541                };
10542
10543                Some(
10544                    h_flex()
10545                        .h_full()
10546                        .flex_1()
10547                        .gap_2()
10548                        .pr_1()
10549                        .overflow_x_hidden()
10550                        .font(
10551                            theme_settings::ThemeSettings::get_global(cx)
10552                                .buffer_font
10553                                .clone(),
10554                        )
10555                        .child(left)
10556                        .child(preview),
10557                )
10558            }
10559        }
10560    }
10561
10562    pub fn render_context_menu(
10563        &mut self,
10564        max_height_in_lines: u32,
10565        window: &mut Window,
10566        cx: &mut Context<Editor>,
10567    ) -> Option<AnyElement> {
10568        let menu = self.context_menu.borrow();
10569        let menu = menu.as_ref()?;
10570        if !menu.visible() {
10571            return None;
10572        };
10573        self.style
10574            .as_ref()
10575            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10576    }
10577
10578    fn render_context_menu_aside(
10579        &mut self,
10580        max_size: Size<Pixels>,
10581        window: &mut Window,
10582        cx: &mut Context<Editor>,
10583    ) -> Option<AnyElement> {
10584        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10585            if menu.visible() {
10586                menu.render_aside(max_size, window, cx)
10587            } else {
10588                None
10589            }
10590        })
10591    }
10592
10593    fn hide_context_menu(
10594        &mut self,
10595        window: &mut Window,
10596        cx: &mut Context<Self>,
10597    ) -> Option<CodeContextMenu> {
10598        cx.notify();
10599        self.completion_tasks.clear();
10600        let context_menu = self.context_menu.borrow_mut().take();
10601        self.stale_edit_prediction_in_menu.take();
10602        self.update_visible_edit_prediction(window, cx);
10603        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10604            && let Some(completion_provider) = &self.completion_provider
10605        {
10606            completion_provider.selection_changed(None, window, cx);
10607        }
10608        context_menu
10609    }
10610
10611    fn show_snippet_choices(
10612        &mut self,
10613        choices: &Vec<String>,
10614        selection: Range<Anchor>,
10615        cx: &mut Context<Self>,
10616    ) {
10617        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
10618        let Some((buffer_snapshot, range)) =
10619            buffer_snapshot.anchor_range_to_buffer_anchor_range(selection.clone())
10620        else {
10621            return;
10622        };
10623        let Some(buffer) = self.buffer.read(cx).buffer(buffer_snapshot.remote_id()) else {
10624            return;
10625        };
10626
10627        let id = post_inc(&mut self.next_completion_id);
10628        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10629        let mut context_menu = self.context_menu.borrow_mut();
10630        let old_menu = context_menu.take();
10631        *context_menu = Some(CodeContextMenu::Completions(
10632            CompletionsMenu::new_snippet_choices(
10633                id,
10634                true,
10635                choices,
10636                selection.start,
10637                range,
10638                buffer,
10639                old_menu.map(|menu| menu.primary_scroll_handle()),
10640                snippet_sort_order,
10641            ),
10642        ));
10643    }
10644
10645    pub fn insert_snippet(
10646        &mut self,
10647        insertion_ranges: &[Range<MultiBufferOffset>],
10648        snippet: Snippet,
10649        window: &mut Window,
10650        cx: &mut Context<Self>,
10651    ) -> Result<()> {
10652        struct Tabstop<T> {
10653            is_end_tabstop: bool,
10654            ranges: Vec<Range<T>>,
10655            choices: Option<Vec<String>>,
10656        }
10657
10658        let tabstops = self.buffer.update(cx, |buffer, cx| {
10659            let snippet_text: Arc<str> = snippet.text.clone().into();
10660            let edits = insertion_ranges
10661                .iter()
10662                .cloned()
10663                .map(|range| (range, snippet_text.clone()));
10664            let autoindent_mode = AutoindentMode::Block {
10665                original_indent_columns: Vec::new(),
10666            };
10667            buffer.edit(edits, Some(autoindent_mode), cx);
10668
10669            let snapshot = &*buffer.read(cx);
10670            let snippet = &snippet;
10671            snippet
10672                .tabstops
10673                .iter()
10674                .map(|tabstop| {
10675                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10676                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10677                    });
10678                    let mut tabstop_ranges = tabstop
10679                        .ranges
10680                        .iter()
10681                        .flat_map(|tabstop_range| {
10682                            let mut delta = 0_isize;
10683                            insertion_ranges.iter().map(move |insertion_range| {
10684                                let insertion_start = insertion_range.start + delta;
10685                                delta += snippet.text.len() as isize
10686                                    - (insertion_range.end - insertion_range.start) as isize;
10687
10688                                let start =
10689                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10690                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10691                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10692                            })
10693                        })
10694                        .collect::<Vec<_>>();
10695                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10696
10697                    Tabstop {
10698                        is_end_tabstop,
10699                        ranges: tabstop_ranges,
10700                        choices: tabstop.choices.clone(),
10701                    }
10702                })
10703                .collect::<Vec<_>>()
10704        });
10705        if let Some(tabstop) = tabstops.first() {
10706            self.change_selections(Default::default(), window, cx, |s| {
10707                // Reverse order so that the first range is the newest created selection.
10708                // Completions will use it and autoscroll will prioritize it.
10709                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10710            });
10711
10712            if let Some(choices) = &tabstop.choices
10713                && let Some(selection) = tabstop.ranges.first()
10714            {
10715                self.show_snippet_choices(choices, selection.clone(), cx)
10716            }
10717
10718            // If we're already at the last tabstop and it's at the end of the snippet,
10719            // we're done, we don't need to keep the state around.
10720            if !tabstop.is_end_tabstop {
10721                let choices = tabstops
10722                    .iter()
10723                    .map(|tabstop| tabstop.choices.clone())
10724                    .collect();
10725
10726                let ranges = tabstops
10727                    .into_iter()
10728                    .map(|tabstop| tabstop.ranges)
10729                    .collect::<Vec<_>>();
10730
10731                self.snippet_stack.push(SnippetState {
10732                    active_index: 0,
10733                    ranges,
10734                    choices,
10735                });
10736            }
10737
10738            // Check whether the just-entered snippet ends with an auto-closable bracket.
10739            if self.autoclose_regions.is_empty() {
10740                let snapshot = self.buffer.read(cx).snapshot(cx);
10741                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10742                    let selection_head = selection.head();
10743                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10744                        continue;
10745                    };
10746
10747                    let mut bracket_pair = None;
10748                    let max_lookup_length = scope
10749                        .brackets()
10750                        .map(|(pair, _)| {
10751                            pair.start
10752                                .as_str()
10753                                .chars()
10754                                .count()
10755                                .max(pair.end.as_str().chars().count())
10756                        })
10757                        .max();
10758                    if let Some(max_lookup_length) = max_lookup_length {
10759                        let next_text = snapshot
10760                            .chars_at(selection_head)
10761                            .take(max_lookup_length)
10762                            .collect::<String>();
10763                        let prev_text = snapshot
10764                            .reversed_chars_at(selection_head)
10765                            .take(max_lookup_length)
10766                            .collect::<String>();
10767
10768                        for (pair, enabled) in scope.brackets() {
10769                            if enabled
10770                                && pair.close
10771                                && prev_text.starts_with(pair.start.as_str())
10772                                && next_text.starts_with(pair.end.as_str())
10773                            {
10774                                bracket_pair = Some(pair.clone());
10775                                break;
10776                            }
10777                        }
10778                    }
10779
10780                    if let Some(pair) = bracket_pair {
10781                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10782                        let autoclose_enabled =
10783                            self.use_autoclose && snapshot_settings.use_autoclose;
10784                        if autoclose_enabled {
10785                            let start = snapshot.anchor_after(selection_head);
10786                            let end = snapshot.anchor_after(selection_head);
10787                            self.autoclose_regions.push(AutocloseRegion {
10788                                selection_id: selection.id,
10789                                range: start..end,
10790                                pair,
10791                            });
10792                        }
10793                    }
10794                }
10795            }
10796        }
10797        Ok(())
10798    }
10799
10800    pub fn move_to_next_snippet_tabstop(
10801        &mut self,
10802        window: &mut Window,
10803        cx: &mut Context<Self>,
10804    ) -> bool {
10805        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10806    }
10807
10808    pub fn move_to_prev_snippet_tabstop(
10809        &mut self,
10810        window: &mut Window,
10811        cx: &mut Context<Self>,
10812    ) -> bool {
10813        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10814    }
10815
10816    pub fn move_to_snippet_tabstop(
10817        &mut self,
10818        bias: Bias,
10819        window: &mut Window,
10820        cx: &mut Context<Self>,
10821    ) -> bool {
10822        if let Some(mut snippet) = self.snippet_stack.pop() {
10823            match bias {
10824                Bias::Left => {
10825                    if snippet.active_index > 0 {
10826                        snippet.active_index -= 1;
10827                    } else {
10828                        self.snippet_stack.push(snippet);
10829                        return false;
10830                    }
10831                }
10832                Bias::Right => {
10833                    if snippet.active_index + 1 < snippet.ranges.len() {
10834                        snippet.active_index += 1;
10835                    } else {
10836                        self.snippet_stack.push(snippet);
10837                        return false;
10838                    }
10839                }
10840            }
10841            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10842                self.change_selections(Default::default(), window, cx, |s| {
10843                    // Reverse order so that the first range is the newest created selection.
10844                    // Completions will use it and autoscroll will prioritize it.
10845                    s.select_ranges(current_ranges.iter().rev().cloned())
10846                });
10847
10848                if let Some(choices) = &snippet.choices[snippet.active_index]
10849                    && let Some(selection) = current_ranges.first()
10850                {
10851                    self.show_snippet_choices(choices, selection.clone(), cx);
10852                }
10853
10854                // If snippet state is not at the last tabstop, push it back on the stack
10855                if snippet.active_index + 1 < snippet.ranges.len() {
10856                    self.snippet_stack.push(snippet);
10857                }
10858                return true;
10859            }
10860        }
10861
10862        false
10863    }
10864
10865    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10866        self.transact(window, cx, |this, window, cx| {
10867            this.select_all(&SelectAll, window, cx);
10868            this.insert("", window, cx);
10869        });
10870    }
10871
10872    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10873        if self.read_only(cx) {
10874            return;
10875        }
10876        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10877        self.transact(window, cx, |this, window, cx| {
10878            this.select_autoclose_pair(window, cx);
10879
10880            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10881
10882            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10883            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10884            for selection in &mut selections {
10885                if selection.is_empty() {
10886                    let old_head = selection.head();
10887                    let mut new_head =
10888                        movement::left(&display_map, old_head.to_display_point(&display_map))
10889                            .to_point(&display_map);
10890                    if let Some((buffer, line_buffer_range)) = display_map
10891                        .buffer_snapshot()
10892                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10893                    {
10894                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10895                        let indent_len = match indent_size.kind {
10896                            IndentKind::Space => {
10897                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10898                            }
10899                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10900                        };
10901                        if old_head.column <= indent_size.len && old_head.column > 0 {
10902                            let indent_len = indent_len.get();
10903                            new_head = cmp::min(
10904                                new_head,
10905                                MultiBufferPoint::new(
10906                                    old_head.row,
10907                                    ((old_head.column - 1) / indent_len) * indent_len,
10908                                ),
10909                            );
10910                        }
10911                    }
10912
10913                    selection.set_head(new_head, SelectionGoal::None);
10914                }
10915            }
10916
10917            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10918            this.insert("", window, cx);
10919            linked_edits.apply_with_left_expansion(cx);
10920            this.refresh_edit_prediction(true, false, window, cx);
10921            refresh_linked_ranges(this, window, cx);
10922        });
10923    }
10924
10925    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10926        if self.read_only(cx) {
10927            return;
10928        }
10929        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10930        self.transact(window, cx, |this, window, cx| {
10931            this.change_selections(Default::default(), window, cx, |s| {
10932                s.move_with(&mut |map, selection| {
10933                    if selection.is_empty() {
10934                        let cursor = movement::right(map, selection.head());
10935                        selection.end = cursor;
10936                        selection.reversed = true;
10937                        selection.goal = SelectionGoal::None;
10938                    }
10939                })
10940            });
10941            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10942            this.insert("", window, cx);
10943            linked_edits.apply(cx);
10944            this.refresh_edit_prediction(true, false, window, cx);
10945            refresh_linked_ranges(this, window, cx);
10946        });
10947    }
10948
10949    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10950        if self.mode.is_single_line() {
10951            cx.propagate();
10952            return;
10953        }
10954
10955        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10956        if self.move_to_prev_snippet_tabstop(window, cx) {
10957            return;
10958        }
10959        self.outdent(&Outdent, window, cx);
10960    }
10961
10962    pub fn next_snippet_tabstop(
10963        &mut self,
10964        _: &NextSnippetTabstop,
10965        window: &mut Window,
10966        cx: &mut Context<Self>,
10967    ) {
10968        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10969            cx.propagate();
10970            return;
10971        }
10972
10973        if self.move_to_next_snippet_tabstop(window, cx) {
10974            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10975            return;
10976        }
10977        cx.propagate();
10978    }
10979
10980    pub fn previous_snippet_tabstop(
10981        &mut self,
10982        _: &PreviousSnippetTabstop,
10983        window: &mut Window,
10984        cx: &mut Context<Self>,
10985    ) {
10986        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10987            cx.propagate();
10988            return;
10989        }
10990
10991        if self.move_to_prev_snippet_tabstop(window, cx) {
10992            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10993            return;
10994        }
10995        cx.propagate();
10996    }
10997
10998    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10999        if self.mode.is_single_line() {
11000            cx.propagate();
11001            return;
11002        }
11003
11004        if self.move_to_next_snippet_tabstop(window, cx) {
11005            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11006            return;
11007        }
11008        if self.read_only(cx) {
11009            return;
11010        }
11011        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11012        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
11013        let buffer = self.buffer.read(cx);
11014        let snapshot = buffer.snapshot(cx);
11015        let rows_iter = selections.iter().map(|s| s.head().row);
11016        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
11017
11018        let has_some_cursor_in_whitespace = selections
11019            .iter()
11020            .filter(|selection| selection.is_empty())
11021            .any(|selection| {
11022                let cursor = selection.head();
11023                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11024                cursor.column < current_indent.len
11025            });
11026
11027        let mut edits = Vec::new();
11028        let mut prev_edited_row = 0;
11029        let mut row_delta = 0;
11030        for selection in &mut selections {
11031            if selection.start.row != prev_edited_row {
11032                row_delta = 0;
11033            }
11034            prev_edited_row = selection.end.row;
11035
11036            // If cursor is after a list prefix, make selection non-empty to trigger line indent
11037            if selection.is_empty() {
11038                let cursor = selection.head();
11039                let settings = buffer.language_settings_at(cursor, cx);
11040                if settings.indent_list_on_tab {
11041                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
11042                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
11043                            row_delta = Self::indent_selection(
11044                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
11045                            );
11046                            continue;
11047                        }
11048                    }
11049                }
11050            }
11051
11052            // If the selection is non-empty, then increase the indentation of the selected lines.
11053            if !selection.is_empty() {
11054                row_delta =
11055                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11056                continue;
11057            }
11058
11059            let cursor = selection.head();
11060            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
11061            if let Some(suggested_indent) =
11062                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
11063            {
11064                // Don't do anything if already at suggested indent
11065                // and there is any other cursor which is not
11066                if has_some_cursor_in_whitespace
11067                    && cursor.column == current_indent.len
11068                    && current_indent.len == suggested_indent.len
11069                {
11070                    continue;
11071                }
11072
11073                // Adjust line and move cursor to suggested indent
11074                // if cursor is not at suggested indent
11075                if cursor.column < suggested_indent.len
11076                    && cursor.column <= current_indent.len
11077                    && current_indent.len <= suggested_indent.len
11078                {
11079                    selection.start = Point::new(cursor.row, suggested_indent.len);
11080                    selection.end = selection.start;
11081                    if row_delta == 0 {
11082                        edits.extend(Buffer::edit_for_indent_size_adjustment(
11083                            cursor.row,
11084                            current_indent,
11085                            suggested_indent,
11086                        ));
11087                        row_delta = suggested_indent.len - current_indent.len;
11088                    }
11089                    continue;
11090                }
11091
11092                // If current indent is more than suggested indent
11093                // only move cursor to current indent and skip indent
11094                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
11095                    selection.start = Point::new(cursor.row, current_indent.len);
11096                    selection.end = selection.start;
11097                    continue;
11098                }
11099            }
11100
11101            // Otherwise, insert a hard or soft tab.
11102            let settings = buffer.language_settings_at(cursor, cx);
11103            let tab_size = if settings.hard_tabs {
11104                IndentSize::tab()
11105            } else {
11106                let tab_size = settings.tab_size.get();
11107                let indent_remainder = snapshot
11108                    .text_for_range(Point::new(cursor.row, 0)..cursor)
11109                    .flat_map(str::chars)
11110                    .fold(row_delta % tab_size, |counter: u32, c| {
11111                        if c == '\t' {
11112                            0
11113                        } else {
11114                            (counter + 1) % tab_size
11115                        }
11116                    });
11117
11118                let chars_to_next_tab_stop = tab_size - indent_remainder;
11119                IndentSize::spaces(chars_to_next_tab_stop)
11120            };
11121            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
11122            selection.end = selection.start;
11123            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
11124            row_delta += tab_size.len;
11125        }
11126
11127        self.transact(window, cx, |this, window, cx| {
11128            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11129            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11130            this.refresh_edit_prediction(true, false, window, cx);
11131        });
11132    }
11133
11134    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
11135        if self.read_only(cx) {
11136            return;
11137        }
11138        if self.mode.is_single_line() {
11139            cx.propagate();
11140            return;
11141        }
11142
11143        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11144        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
11145        let mut prev_edited_row = 0;
11146        let mut row_delta = 0;
11147        let mut edits = Vec::new();
11148        let buffer = self.buffer.read(cx);
11149        let snapshot = buffer.snapshot(cx);
11150        for selection in &mut selections {
11151            if selection.start.row != prev_edited_row {
11152                row_delta = 0;
11153            }
11154            prev_edited_row = selection.end.row;
11155
11156            row_delta =
11157                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
11158        }
11159
11160        self.transact(window, cx, |this, window, cx| {
11161            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
11162            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11163        });
11164    }
11165
11166    fn indent_selection(
11167        buffer: &MultiBuffer,
11168        snapshot: &MultiBufferSnapshot,
11169        selection: &mut Selection<Point>,
11170        edits: &mut Vec<(Range<Point>, String)>,
11171        delta_for_start_row: u32,
11172        cx: &App,
11173    ) -> u32 {
11174        let settings = buffer.language_settings_at(selection.start, cx);
11175        let tab_size = settings.tab_size.get();
11176        let indent_kind = if settings.hard_tabs {
11177            IndentKind::Tab
11178        } else {
11179            IndentKind::Space
11180        };
11181        let mut start_row = selection.start.row;
11182        let mut end_row = selection.end.row + 1;
11183
11184        // If a selection ends at the beginning of a line, don't indent
11185        // that last line.
11186        if selection.end.column == 0 && selection.end.row > selection.start.row {
11187            end_row -= 1;
11188        }
11189
11190        // Avoid re-indenting a row that has already been indented by a
11191        // previous selection, but still update this selection's column
11192        // to reflect that indentation.
11193        if delta_for_start_row > 0 {
11194            start_row += 1;
11195            selection.start.column += delta_for_start_row;
11196            if selection.end.row == selection.start.row {
11197                selection.end.column += delta_for_start_row;
11198            }
11199        }
11200
11201        let mut delta_for_end_row = 0;
11202        let has_multiple_rows = start_row + 1 != end_row;
11203        for row in start_row..end_row {
11204            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
11205            let indent_delta = match (current_indent.kind, indent_kind) {
11206                (IndentKind::Space, IndentKind::Space) => {
11207                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
11208                    IndentSize::spaces(columns_to_next_tab_stop)
11209                }
11210                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
11211                (_, IndentKind::Tab) => IndentSize::tab(),
11212            };
11213
11214            let start = if has_multiple_rows || current_indent.len < selection.start.column {
11215                0
11216            } else {
11217                selection.start.column
11218            };
11219            let row_start = Point::new(row, start);
11220            edits.push((
11221                row_start..row_start,
11222                indent_delta.chars().collect::<String>(),
11223            ));
11224
11225            // Update this selection's endpoints to reflect the indentation.
11226            if row == selection.start.row {
11227                selection.start.column += indent_delta.len;
11228            }
11229            if row == selection.end.row {
11230                selection.end.column += indent_delta.len;
11231                delta_for_end_row = indent_delta.len;
11232            }
11233        }
11234
11235        if selection.start.row == selection.end.row {
11236            delta_for_start_row + delta_for_end_row
11237        } else {
11238            delta_for_end_row
11239        }
11240    }
11241
11242    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
11243        if self.read_only(cx) {
11244            return;
11245        }
11246        if self.mode.is_single_line() {
11247            cx.propagate();
11248            return;
11249        }
11250
11251        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11252        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11253        let selections = self.selections.all::<Point>(&display_map);
11254        let mut deletion_ranges = Vec::new();
11255        let mut last_outdent = None;
11256        {
11257            let buffer = self.buffer.read(cx);
11258            let snapshot = buffer.snapshot(cx);
11259            for selection in &selections {
11260                let settings = buffer.language_settings_at(selection.start, cx);
11261                let tab_size = settings.tab_size.get();
11262                let mut rows = selection.spanned_rows(false, &display_map);
11263
11264                // Avoid re-outdenting a row that has already been outdented by a
11265                // previous selection.
11266                if let Some(last_row) = last_outdent
11267                    && last_row == rows.start
11268                {
11269                    rows.start = rows.start.next_row();
11270                }
11271                let has_multiple_rows = rows.len() > 1;
11272                for row in rows.iter_rows() {
11273                    let indent_size = snapshot.indent_size_for_line(row);
11274                    if indent_size.len > 0 {
11275                        let deletion_len = match indent_size.kind {
11276                            IndentKind::Space => {
11277                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
11278                                if columns_to_prev_tab_stop == 0 {
11279                                    tab_size
11280                                } else {
11281                                    columns_to_prev_tab_stop
11282                                }
11283                            }
11284                            IndentKind::Tab => 1,
11285                        };
11286                        let start = if has_multiple_rows
11287                            || deletion_len > selection.start.column
11288                            || indent_size.len < selection.start.column
11289                        {
11290                            0
11291                        } else {
11292                            selection.start.column - deletion_len
11293                        };
11294                        deletion_ranges.push(
11295                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11296                        );
11297                        last_outdent = Some(row);
11298                    }
11299                }
11300            }
11301        }
11302
11303        self.transact(window, cx, |this, window, cx| {
11304            this.buffer.update(cx, |buffer, cx| {
11305                let empty_str: Arc<str> = Arc::default();
11306                buffer.edit(
11307                    deletion_ranges
11308                        .into_iter()
11309                        .map(|range| (range, empty_str.clone())),
11310                    None,
11311                    cx,
11312                );
11313            });
11314            let selections = this
11315                .selections
11316                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11317            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11318        });
11319    }
11320
11321    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11322        if self.read_only(cx) {
11323            return;
11324        }
11325        if self.mode.is_single_line() {
11326            cx.propagate();
11327            return;
11328        }
11329
11330        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11331        let selections = self
11332            .selections
11333            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11334            .into_iter()
11335            .map(|s| s.range());
11336
11337        self.transact(window, cx, |this, window, cx| {
11338            this.buffer.update(cx, |buffer, cx| {
11339                buffer.autoindent_ranges(selections, cx);
11340            });
11341            let selections = this
11342                .selections
11343                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11344            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11345        });
11346    }
11347
11348    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11349        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11350        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11351        let selections = self.selections.all::<Point>(&display_map);
11352
11353        let mut new_cursors = Vec::new();
11354        let mut edit_ranges = Vec::new();
11355        let mut selections = selections.iter().peekable();
11356        while let Some(selection) = selections.next() {
11357            let mut rows = selection.spanned_rows(false, &display_map);
11358
11359            // Accumulate contiguous regions of rows that we want to delete.
11360            while let Some(next_selection) = selections.peek() {
11361                let next_rows = next_selection.spanned_rows(false, &display_map);
11362                if next_rows.start <= rows.end {
11363                    rows.end = next_rows.end;
11364                    selections.next().unwrap();
11365                } else {
11366                    break;
11367                }
11368            }
11369
11370            let buffer = display_map.buffer_snapshot();
11371            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11372            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11373                // If there's a line after the range, delete the \n from the end of the row range
11374                (
11375                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11376                    rows.end,
11377                )
11378            } else {
11379                // If there isn't a line after the range, delete the \n from the line before the
11380                // start of the row range
11381                edit_start = edit_start.saturating_sub_usize(1);
11382                (buffer.len(), rows.start.previous_row())
11383            };
11384
11385            let text_layout_details = self.text_layout_details(window, cx);
11386            let x = display_map.x_for_display_point(
11387                selection.head().to_display_point(&display_map),
11388                &text_layout_details,
11389            );
11390            let row = Point::new(target_row.0, 0)
11391                .to_display_point(&display_map)
11392                .row();
11393            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11394
11395            new_cursors.push((
11396                selection.id,
11397                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11398                SelectionGoal::None,
11399            ));
11400            edit_ranges.push(edit_start..edit_end);
11401        }
11402
11403        self.transact(window, cx, |this, window, cx| {
11404            let buffer = this.buffer.update(cx, |buffer, cx| {
11405                let empty_str: Arc<str> = Arc::default();
11406                buffer.edit(
11407                    edit_ranges
11408                        .into_iter()
11409                        .map(|range| (range, empty_str.clone())),
11410                    None,
11411                    cx,
11412                );
11413                buffer.snapshot(cx)
11414            });
11415            let new_selections = new_cursors
11416                .into_iter()
11417                .map(|(id, cursor, goal)| {
11418                    let cursor = cursor.to_point(&buffer);
11419                    Selection {
11420                        id,
11421                        start: cursor,
11422                        end: cursor,
11423                        reversed: false,
11424                        goal,
11425                    }
11426                })
11427                .collect();
11428
11429            this.change_selections(Default::default(), window, cx, |s| {
11430                s.select(new_selections);
11431            });
11432        });
11433    }
11434
11435    pub fn join_lines_impl(
11436        &mut self,
11437        insert_whitespace: bool,
11438        window: &mut Window,
11439        cx: &mut Context<Self>,
11440    ) {
11441        if self.read_only(cx) {
11442            return;
11443        }
11444        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11445        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11446            let start = MultiBufferRow(selection.start.row);
11447            // Treat single line selections as if they include the next line. Otherwise this action
11448            // would do nothing for single line selections individual cursors.
11449            let end = if selection.start.row == selection.end.row {
11450                MultiBufferRow(selection.start.row + 1)
11451            } else if selection.end.column == 0 {
11452                // If the selection ends at the start of a line, it's logically at the end of the
11453                // previous line (plus its newline).
11454                // Don't include the end line unless there's only one line selected.
11455                if selection.start.row + 1 == selection.end.row {
11456                    MultiBufferRow(selection.end.row)
11457                } else {
11458                    MultiBufferRow(selection.end.row - 1)
11459                }
11460            } else {
11461                MultiBufferRow(selection.end.row)
11462            };
11463
11464            if let Some(last_row_range) = row_ranges.last_mut()
11465                && start <= last_row_range.end
11466            {
11467                last_row_range.end = end;
11468                continue;
11469            }
11470            row_ranges.push(start..end);
11471        }
11472
11473        let snapshot = self.buffer.read(cx).snapshot(cx);
11474        let mut cursor_positions = Vec::new();
11475        for row_range in &row_ranges {
11476            let anchor = snapshot.anchor_before(Point::new(
11477                row_range.end.previous_row().0,
11478                snapshot.line_len(row_range.end.previous_row()),
11479            ));
11480            cursor_positions.push(anchor..anchor);
11481        }
11482
11483        self.transact(window, cx, |this, window, cx| {
11484            for row_range in row_ranges.into_iter().rev() {
11485                for row in row_range.iter_rows().rev() {
11486                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11487                    let next_line_row = row.next_row();
11488                    let indent = snapshot.indent_size_for_line(next_line_row);
11489                    let mut join_start_column = indent.len;
11490
11491                    if let Some(language_scope) =
11492                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11493                    {
11494                        let line_end =
11495                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11496                        let line_text_after_indent = snapshot
11497                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11498                            .collect::<String>();
11499
11500                        if !line_text_after_indent.is_empty() {
11501                            let block_prefix = language_scope
11502                                .block_comment()
11503                                .map(|c| c.prefix.as_ref())
11504                                .filter(|p| !p.is_empty());
11505                            let doc_prefix = language_scope
11506                                .documentation_comment()
11507                                .map(|c| c.prefix.as_ref())
11508                                .filter(|p| !p.is_empty());
11509                            let all_prefixes = language_scope
11510                                .line_comment_prefixes()
11511                                .iter()
11512                                .map(|p| p.as_ref())
11513                                .chain(block_prefix)
11514                                .chain(doc_prefix)
11515                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11516
11517                            let mut longest_prefix_len = None;
11518                            for prefix in all_prefixes {
11519                                let trimmed = prefix.trim_end();
11520                                if line_text_after_indent.starts_with(trimmed) {
11521                                    let candidate_len =
11522                                        if line_text_after_indent.starts_with(prefix) {
11523                                            prefix.len()
11524                                        } else {
11525                                            trimmed.len()
11526                                        };
11527                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11528                                        longest_prefix_len = Some(candidate_len);
11529                                    }
11530                                }
11531                            }
11532
11533                            if let Some(prefix_len) = longest_prefix_len {
11534                                join_start_column =
11535                                    join_start_column.saturating_add(prefix_len as u32);
11536                            }
11537                        }
11538                    }
11539
11540                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11541
11542                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11543                        && insert_whitespace
11544                    {
11545                        " "
11546                    } else {
11547                        ""
11548                    };
11549
11550                    this.buffer.update(cx, |buffer, cx| {
11551                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11552                    });
11553                }
11554            }
11555
11556            this.change_selections(Default::default(), window, cx, |s| {
11557                s.select_anchor_ranges(cursor_positions)
11558            });
11559        });
11560    }
11561
11562    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11563        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11564        self.join_lines_impl(true, window, cx);
11565    }
11566
11567    pub fn sort_lines_case_sensitive(
11568        &mut self,
11569        _: &SortLinesCaseSensitive,
11570        window: &mut Window,
11571        cx: &mut Context<Self>,
11572    ) {
11573        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11574    }
11575
11576    pub fn sort_lines_by_length(
11577        &mut self,
11578        _: &SortLinesByLength,
11579        window: &mut Window,
11580        cx: &mut Context<Self>,
11581    ) {
11582        self.manipulate_immutable_lines(window, cx, |lines| {
11583            lines.sort_by_key(|&line| line.chars().count())
11584        })
11585    }
11586
11587    pub fn sort_lines_case_insensitive(
11588        &mut self,
11589        _: &SortLinesCaseInsensitive,
11590        window: &mut Window,
11591        cx: &mut Context<Self>,
11592    ) {
11593        self.manipulate_immutable_lines(window, cx, |lines| {
11594            lines.sort_by_key(|line| line.to_lowercase())
11595        })
11596    }
11597
11598    pub fn unique_lines_case_insensitive(
11599        &mut self,
11600        _: &UniqueLinesCaseInsensitive,
11601        window: &mut Window,
11602        cx: &mut Context<Self>,
11603    ) {
11604        self.manipulate_immutable_lines(window, cx, |lines| {
11605            let mut seen = HashSet::default();
11606            lines.retain(|line| seen.insert(line.to_lowercase()));
11607        })
11608    }
11609
11610    pub fn unique_lines_case_sensitive(
11611        &mut self,
11612        _: &UniqueLinesCaseSensitive,
11613        window: &mut Window,
11614        cx: &mut Context<Self>,
11615    ) {
11616        self.manipulate_immutable_lines(window, cx, |lines| {
11617            let mut seen = HashSet::default();
11618            lines.retain(|line| seen.insert(*line));
11619        })
11620    }
11621
11622    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11623        let snapshot = self.buffer.read(cx).snapshot(cx);
11624        for selection in self.selections.disjoint_anchors_arc().iter() {
11625            if snapshot
11626                .language_at(selection.start)
11627                .and_then(|lang| lang.config().wrap_characters.as_ref())
11628                .is_some()
11629            {
11630                return true;
11631            }
11632        }
11633        false
11634    }
11635
11636    fn wrap_selections_in_tag(
11637        &mut self,
11638        _: &WrapSelectionsInTag,
11639        window: &mut Window,
11640        cx: &mut Context<Self>,
11641    ) {
11642        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11643
11644        let snapshot = self.buffer.read(cx).snapshot(cx);
11645
11646        let mut edits = Vec::new();
11647        let mut boundaries = Vec::new();
11648
11649        for selection in self
11650            .selections
11651            .all_adjusted(&self.display_snapshot(cx))
11652            .iter()
11653        {
11654            let Some(wrap_config) = snapshot
11655                .language_at(selection.start)
11656                .and_then(|lang| lang.config().wrap_characters.clone())
11657            else {
11658                continue;
11659            };
11660
11661            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11662            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11663
11664            let start_before = snapshot.anchor_before(selection.start);
11665            let end_after = snapshot.anchor_after(selection.end);
11666
11667            edits.push((start_before..start_before, open_tag));
11668            edits.push((end_after..end_after, close_tag));
11669
11670            boundaries.push((
11671                start_before,
11672                end_after,
11673                wrap_config.start_prefix.len(),
11674                wrap_config.end_suffix.len(),
11675            ));
11676        }
11677
11678        if edits.is_empty() {
11679            return;
11680        }
11681
11682        self.transact(window, cx, |this, window, cx| {
11683            let buffer = this.buffer.update(cx, |buffer, cx| {
11684                buffer.edit(edits, None, cx);
11685                buffer.snapshot(cx)
11686            });
11687
11688            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11689            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11690                boundaries.into_iter()
11691            {
11692                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11693                let close_offset = end_after
11694                    .to_offset(&buffer)
11695                    .saturating_sub_usize(end_suffix_len);
11696                new_selections.push(open_offset..open_offset);
11697                new_selections.push(close_offset..close_offset);
11698            }
11699
11700            this.change_selections(Default::default(), window, cx, |s| {
11701                s.select_ranges(new_selections);
11702            });
11703
11704            this.request_autoscroll(Autoscroll::fit(), cx);
11705        });
11706    }
11707
11708    pub fn toggle_read_only(
11709        &mut self,
11710        _: &workspace::ToggleReadOnlyFile,
11711        _: &mut Window,
11712        cx: &mut Context<Self>,
11713    ) {
11714        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11715            buffer.update(cx, |buffer, cx| {
11716                buffer.set_capability(
11717                    match buffer.capability() {
11718                        Capability::ReadWrite => Capability::Read,
11719                        Capability::Read => Capability::ReadWrite,
11720                        Capability::ReadOnly => Capability::ReadOnly,
11721                    },
11722                    cx,
11723                );
11724            })
11725        }
11726    }
11727
11728    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11729        let Some(project) = self.project.clone() else {
11730            return;
11731        };
11732        let task = self.reload(project, window, cx);
11733        self.detach_and_notify_err(task, window, cx);
11734    }
11735
11736    pub fn restore_file(
11737        &mut self,
11738        _: &::git::RestoreFile,
11739        window: &mut Window,
11740        cx: &mut Context<Self>,
11741    ) {
11742        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11743        let mut buffer_ids = HashSet::default();
11744        let snapshot = self.buffer().read(cx).snapshot(cx);
11745        for selection in self
11746            .selections
11747            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11748        {
11749            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11750        }
11751
11752        let ranges = buffer_ids
11753            .into_iter()
11754            .flat_map(|buffer_id| snapshot.range_for_buffer(buffer_id))
11755            .collect::<Vec<_>>();
11756
11757        self.restore_hunks_in_ranges(ranges, window, cx);
11758    }
11759
11760    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11761        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11762        let selections = self
11763            .selections
11764            .all(&self.display_snapshot(cx))
11765            .into_iter()
11766            .map(|s| s.range())
11767            .collect();
11768        self.restore_hunks_in_ranges(selections, window, cx);
11769    }
11770
11771    /// Restores the diff hunks in the editor's selections and moves the cursor
11772    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11773    /// not all diff hunks are expanded.
11774    pub fn restore_and_next(
11775        &mut self,
11776        _: &::git::RestoreAndNext,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) {
11780        let selections = self
11781            .selections
11782            .all(&self.display_snapshot(cx))
11783            .into_iter()
11784            .map(|selection| selection.range())
11785            .collect();
11786
11787        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11788        self.restore_hunks_in_ranges(selections, window, cx);
11789
11790        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11791        let wrap_around = !all_diff_hunks_expanded;
11792        let snapshot = self.snapshot(window, cx);
11793        let position = self
11794            .selections
11795            .newest::<Point>(&snapshot.display_snapshot)
11796            .head();
11797
11798        self.go_to_hunk_before_or_after_position(
11799            &snapshot,
11800            position,
11801            Direction::Next,
11802            wrap_around,
11803            window,
11804            cx,
11805        );
11806    }
11807
11808    pub fn restore_hunks_in_ranges(
11809        &mut self,
11810        ranges: Vec<Range<Point>>,
11811        window: &mut Window,
11812        cx: &mut Context<Editor>,
11813    ) {
11814        if self.delegate_stage_and_restore {
11815            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11816            if !hunks.is_empty() {
11817                cx.emit(EditorEvent::RestoreRequested { hunks });
11818            }
11819            return;
11820        }
11821        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11822        self.transact(window, cx, |editor, window, cx| {
11823            editor.restore_diff_hunks(hunks, cx);
11824            let selections = editor
11825                .selections
11826                .all::<MultiBufferOffset>(&editor.display_snapshot(cx));
11827            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
11828                s.select(selections);
11829            });
11830        });
11831    }
11832
11833    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11834        let mut revert_changes = HashMap::default();
11835        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11836        for (buffer_id, hunks) in &chunk_by {
11837            let hunks = hunks.collect::<Vec<_>>();
11838            for hunk in &hunks {
11839                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11840            }
11841            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11842        }
11843        if !revert_changes.is_empty() {
11844            self.buffer().update(cx, |multi_buffer, cx| {
11845                for (buffer_id, changes) in revert_changes {
11846                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11847                        buffer.update(cx, |buffer, cx| {
11848                            buffer.edit(
11849                                changes
11850                                    .into_iter()
11851                                    .map(|(range, text)| (range, text.to_string())),
11852                                None,
11853                                cx,
11854                            );
11855                        });
11856                    }
11857                }
11858            });
11859        }
11860    }
11861
11862    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11863        if let Some(status) = self
11864            .addons
11865            .iter()
11866            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11867        {
11868            return Some(status);
11869        }
11870        self.project
11871            .as_ref()?
11872            .read(cx)
11873            .status_for_buffer_id(buffer_id, cx)
11874    }
11875
11876    pub fn open_active_item_in_terminal(
11877        &mut self,
11878        _: &OpenInTerminal,
11879        window: &mut Window,
11880        cx: &mut Context<Self>,
11881    ) {
11882        if let Some(working_directory) = self.active_buffer(cx).and_then(|buffer| {
11883            let project_path = buffer.read(cx).project_path(cx)?;
11884            let project = self.project()?.read(cx);
11885            let entry = project.entry_for_path(&project_path, cx)?;
11886            let parent = match &entry.canonical_path {
11887                Some(canonical_path) => canonical_path.to_path_buf(),
11888                None => project.absolute_path(&project_path, cx)?,
11889            }
11890            .parent()?
11891            .to_path_buf();
11892            Some(parent)
11893        }) {
11894            window.dispatch_action(
11895                OpenTerminal {
11896                    working_directory,
11897                    local: false,
11898                }
11899                .boxed_clone(),
11900                cx,
11901            );
11902        }
11903    }
11904
11905    fn set_breakpoint_context_menu(
11906        &mut self,
11907        display_row: DisplayRow,
11908        position: Option<Anchor>,
11909        clicked_point: gpui::Point<Pixels>,
11910        window: &mut Window,
11911        cx: &mut Context<Self>,
11912    ) {
11913        let source = self
11914            .buffer
11915            .read(cx)
11916            .snapshot(cx)
11917            .anchor_before(Point::new(display_row.0, 0u32));
11918
11919        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11920
11921        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11922            self,
11923            source,
11924            clicked_point,
11925            context_menu,
11926            window,
11927            cx,
11928        );
11929    }
11930
11931    fn add_edit_breakpoint_block(
11932        &mut self,
11933        anchor: Anchor,
11934        breakpoint: &Breakpoint,
11935        edit_action: BreakpointPromptEditAction,
11936        window: &mut Window,
11937        cx: &mut Context<Self>,
11938    ) {
11939        let weak_editor = cx.weak_entity();
11940        let bp_prompt = cx.new(|cx| {
11941            BreakpointPromptEditor::new(
11942                weak_editor,
11943                anchor,
11944                breakpoint.clone(),
11945                edit_action,
11946                window,
11947                cx,
11948            )
11949        });
11950
11951        let height = bp_prompt.update(cx, |this, cx| {
11952            this.prompt
11953                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11954        });
11955        let cloned_prompt = bp_prompt.clone();
11956        let blocks = vec![BlockProperties {
11957            style: BlockStyle::Sticky,
11958            placement: BlockPlacement::Above(anchor),
11959            height: Some(height),
11960            render: Arc::new(move |cx| {
11961                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11962                cloned_prompt.clone().into_any_element()
11963            }),
11964            priority: 0,
11965        }];
11966
11967        let focus_handle = bp_prompt.focus_handle(cx);
11968        window.focus(&focus_handle, cx);
11969
11970        let block_ids = self.insert_blocks(blocks, None, cx);
11971        bp_prompt.update(cx, |prompt, _| {
11972            prompt.add_block_ids(block_ids);
11973        });
11974    }
11975
11976    pub(crate) fn breakpoint_at_row(
11977        &self,
11978        row: u32,
11979        window: &mut Window,
11980        cx: &mut Context<Self>,
11981    ) -> Option<(Anchor, Breakpoint)> {
11982        let snapshot = self.snapshot(window, cx);
11983        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11984
11985        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11986    }
11987
11988    pub(crate) fn breakpoint_at_anchor(
11989        &self,
11990        breakpoint_position: Anchor,
11991        snapshot: &EditorSnapshot,
11992        cx: &mut Context<Self>,
11993    ) -> Option<(Anchor, Breakpoint)> {
11994        let (breakpoint_position, _) = snapshot
11995            .buffer_snapshot()
11996            .anchor_to_buffer_anchor(breakpoint_position)?;
11997        let buffer = self.buffer.read(cx).buffer(breakpoint_position.buffer_id)?;
11998
11999        let buffer_snapshot = buffer.read(cx).snapshot();
12000
12001        let row = buffer_snapshot
12002            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position)
12003            .row;
12004
12005        let line_len = buffer_snapshot.line_len(row);
12006        let anchor_end = buffer_snapshot.anchor_after(Point::new(row, line_len));
12007
12008        self.breakpoint_store
12009            .as_ref()?
12010            .read_with(cx, |breakpoint_store, cx| {
12011                breakpoint_store
12012                    .breakpoints(
12013                        &buffer,
12014                        Some(breakpoint_position..anchor_end),
12015                        &buffer_snapshot,
12016                        cx,
12017                    )
12018                    .next()
12019                    .and_then(|(bp, _)| {
12020                        let breakpoint_row = buffer_snapshot
12021                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
12022                            .row;
12023
12024                        if breakpoint_row == row {
12025                            snapshot
12026                                .buffer_snapshot()
12027                                .anchor_in_excerpt(bp.position)
12028                                .map(|position| (position, bp.bp.clone()))
12029                        } else {
12030                            None
12031                        }
12032                    })
12033            })
12034    }
12035
12036    pub fn edit_log_breakpoint(
12037        &mut self,
12038        _: &EditLogBreakpoint,
12039        window: &mut Window,
12040        cx: &mut Context<Self>,
12041    ) {
12042        if self.breakpoint_store.is_none() {
12043            return;
12044        }
12045
12046        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12047            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
12048                message: None,
12049                state: BreakpointState::Enabled,
12050                condition: None,
12051                hit_condition: None,
12052            });
12053
12054            self.add_edit_breakpoint_block(
12055                anchor,
12056                &breakpoint,
12057                BreakpointPromptEditAction::Log,
12058                window,
12059                cx,
12060            );
12061        }
12062    }
12063
12064    fn breakpoints_at_cursors(
12065        &self,
12066        window: &mut Window,
12067        cx: &mut Context<Self>,
12068    ) -> Vec<(Anchor, Option<Breakpoint>)> {
12069        let snapshot = self.snapshot(window, cx);
12070        let cursors = self
12071            .selections
12072            .disjoint_anchors_arc()
12073            .iter()
12074            .map(|selection| {
12075                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
12076
12077                let breakpoint_position = self
12078                    .breakpoint_at_row(cursor_position.row, window, cx)
12079                    .map(|bp| bp.0)
12080                    .unwrap_or_else(|| {
12081                        snapshot
12082                            .display_snapshot
12083                            .buffer_snapshot()
12084                            .anchor_after(Point::new(cursor_position.row, 0))
12085                    });
12086
12087                let breakpoint = self
12088                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
12089                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
12090
12091                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
12092            })
12093            // 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.
12094            .collect::<HashMap<Anchor, _>>();
12095
12096        cursors.into_iter().collect()
12097    }
12098
12099    pub fn enable_breakpoint(
12100        &mut self,
12101        _: &crate::actions::EnableBreakpoint,
12102        window: &mut Window,
12103        cx: &mut Context<Self>,
12104    ) {
12105        if self.breakpoint_store.is_none() {
12106            return;
12107        }
12108
12109        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12110            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
12111                continue;
12112            };
12113            self.edit_breakpoint_at_anchor(
12114                anchor,
12115                breakpoint,
12116                BreakpointEditAction::InvertState,
12117                cx,
12118            );
12119        }
12120    }
12121
12122    pub fn align_selections(
12123        &mut self,
12124        _: &crate::actions::AlignSelections,
12125        window: &mut Window,
12126        cx: &mut Context<Self>,
12127    ) {
12128        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12129
12130        let display_snapshot = self.display_snapshot(cx);
12131
12132        struct CursorData {
12133            anchor: Anchor,
12134            point: Point,
12135        }
12136        let cursor_data: Vec<CursorData> = self
12137            .selections
12138            .disjoint_anchors()
12139            .iter()
12140            .map(|selection| {
12141                let anchor = if selection.reversed {
12142                    selection.head()
12143                } else {
12144                    selection.tail()
12145                };
12146                CursorData {
12147                    anchor: anchor,
12148                    point: anchor.to_point(&display_snapshot.buffer_snapshot()),
12149                }
12150            })
12151            .collect();
12152
12153        let rows_anchors_count: Vec<usize> = cursor_data
12154            .iter()
12155            .map(|cursor| cursor.point.row)
12156            .chunk_by(|&row| row)
12157            .into_iter()
12158            .map(|(_, group)| group.count())
12159            .collect();
12160        let max_columns = rows_anchors_count.iter().max().copied().unwrap_or(0);
12161        let mut rows_column_offset = vec![0; rows_anchors_count.len()];
12162        let mut edits = Vec::new();
12163
12164        for column_idx in 0..max_columns {
12165            let mut cursor_index = 0;
12166
12167            // Calculate target_column => position that the selections will go
12168            let mut target_column = 0;
12169            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12170                // Skip rows that don't have this column
12171                if column_idx >= *cursor_count {
12172                    cursor_index += cursor_count;
12173                    continue;
12174                }
12175
12176                let point = &cursor_data[cursor_index + column_idx].point;
12177                let adjusted_column = point.column + rows_column_offset[row_idx];
12178                if adjusted_column > target_column {
12179                    target_column = adjusted_column;
12180                }
12181                cursor_index += cursor_count;
12182            }
12183
12184            // Collect edits for this column
12185            cursor_index = 0;
12186            for (row_idx, cursor_count) in rows_anchors_count.iter().enumerate() {
12187                // Skip rows that don't have this column
12188                if column_idx >= *cursor_count {
12189                    cursor_index += *cursor_count;
12190                    continue;
12191                }
12192
12193                let point = &cursor_data[cursor_index + column_idx].point;
12194                let spaces_needed = target_column - point.column - rows_column_offset[row_idx];
12195                if spaces_needed > 0 {
12196                    let anchor = cursor_data[cursor_index + column_idx]
12197                        .anchor
12198                        .bias_left(&display_snapshot);
12199                    edits.push((anchor..anchor, " ".repeat(spaces_needed as usize)));
12200                }
12201                rows_column_offset[row_idx] += spaces_needed;
12202
12203                cursor_index += *cursor_count;
12204            }
12205        }
12206
12207        if !edits.is_empty() {
12208            self.transact(window, cx, |editor, _window, cx| {
12209                editor.edit(edits, cx);
12210            });
12211        }
12212    }
12213
12214    pub fn disable_breakpoint(
12215        &mut self,
12216        _: &crate::actions::DisableBreakpoint,
12217        window: &mut Window,
12218        cx: &mut Context<Self>,
12219    ) {
12220        if self.breakpoint_store.is_none() {
12221            return;
12222        }
12223
12224        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12225            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
12226                continue;
12227            };
12228            self.edit_breakpoint_at_anchor(
12229                anchor,
12230                breakpoint,
12231                BreakpointEditAction::InvertState,
12232                cx,
12233            );
12234        }
12235    }
12236
12237    pub fn toggle_breakpoint(
12238        &mut self,
12239        _: &crate::actions::ToggleBreakpoint,
12240        window: &mut Window,
12241        cx: &mut Context<Self>,
12242    ) {
12243        if self.breakpoint_store.is_none() {
12244            return;
12245        }
12246
12247        let snapshot = self.snapshot(window, cx);
12248        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
12249            if self.gutter_breakpoint_indicator.0.is_some() {
12250                let display_row = anchor
12251                    .to_point(snapshot.buffer_snapshot())
12252                    .to_display_point(&snapshot.display_snapshot)
12253                    .row();
12254                self.update_breakpoint_collision_on_toggle(
12255                    display_row,
12256                    &BreakpointEditAction::Toggle,
12257                );
12258            }
12259
12260            if let Some(breakpoint) = breakpoint {
12261                self.edit_breakpoint_at_anchor(
12262                    anchor,
12263                    breakpoint,
12264                    BreakpointEditAction::Toggle,
12265                    cx,
12266                );
12267            } else {
12268                self.edit_breakpoint_at_anchor(
12269                    anchor,
12270                    Breakpoint::new_standard(),
12271                    BreakpointEditAction::Toggle,
12272                    cx,
12273                );
12274            }
12275        }
12276    }
12277
12278    fn update_breakpoint_collision_on_toggle(
12279        &mut self,
12280        display_row: DisplayRow,
12281        edit_action: &BreakpointEditAction,
12282    ) {
12283        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
12284            if breakpoint_indicator.display_row == display_row
12285                && matches!(edit_action, BreakpointEditAction::Toggle)
12286            {
12287                breakpoint_indicator.collides_with_existing_breakpoint =
12288                    !breakpoint_indicator.collides_with_existing_breakpoint;
12289            }
12290        }
12291    }
12292
12293    pub fn edit_breakpoint_at_anchor(
12294        &mut self,
12295        breakpoint_position: Anchor,
12296        breakpoint: Breakpoint,
12297        edit_action: BreakpointEditAction,
12298        cx: &mut Context<Self>,
12299    ) {
12300        let Some(breakpoint_store) = &self.breakpoint_store else {
12301            return;
12302        };
12303        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
12304        let Some((position, _)) = buffer_snapshot.anchor_to_buffer_anchor(breakpoint_position)
12305        else {
12306            return;
12307        };
12308        let Some(buffer) = self.buffer.read(cx).buffer(position.buffer_id) else {
12309            return;
12310        };
12311
12312        breakpoint_store.update(cx, |breakpoint_store, cx| {
12313            breakpoint_store.toggle_breakpoint(
12314                buffer,
12315                BreakpointWithPosition {
12316                    position,
12317                    bp: breakpoint,
12318                },
12319                edit_action,
12320                cx,
12321            );
12322        });
12323
12324        cx.notify();
12325    }
12326
12327    #[cfg(any(test, feature = "test-support"))]
12328    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
12329        self.breakpoint_store.clone()
12330    }
12331
12332    pub fn prepare_restore_change(
12333        &self,
12334        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
12335        hunk: &MultiBufferDiffHunk,
12336        cx: &mut App,
12337    ) -> Option<()> {
12338        if hunk.is_created_file() {
12339            return None;
12340        }
12341        let multi_buffer = self.buffer.read(cx);
12342        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
12343        let diff_snapshot = multi_buffer_snapshot.diff_for_buffer_id(hunk.buffer_id)?;
12344        let original_text = diff_snapshot
12345            .base_text()
12346            .as_rope()
12347            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
12348        let buffer = multi_buffer.buffer(hunk.buffer_id)?;
12349        let buffer = buffer.read(cx);
12350        let buffer_snapshot = buffer.snapshot();
12351        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
12352        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
12353            probe
12354                .0
12355                .start
12356                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
12357                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
12358        }) {
12359            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
12360            Some(())
12361        } else {
12362            None
12363        }
12364    }
12365
12366    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
12367        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
12368    }
12369
12370    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
12371        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
12372    }
12373
12374    pub fn rotate_selections_forward(
12375        &mut self,
12376        _: &RotateSelectionsForward,
12377        window: &mut Window,
12378        cx: &mut Context<Self>,
12379    ) {
12380        self.rotate_selections(window, cx, false)
12381    }
12382
12383    pub fn rotate_selections_backward(
12384        &mut self,
12385        _: &RotateSelectionsBackward,
12386        window: &mut Window,
12387        cx: &mut Context<Self>,
12388    ) {
12389        self.rotate_selections(window, cx, true)
12390    }
12391
12392    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12393        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12394        let display_snapshot = self.display_snapshot(cx);
12395        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12396
12397        if selections.len() < 2 {
12398            return;
12399        }
12400
12401        let (edits, new_selections) = {
12402            let buffer = self.buffer.read(cx).read(cx);
12403            let has_selections = selections.iter().any(|s| !s.is_empty());
12404            if has_selections {
12405                let mut selected_texts: Vec<String> = selections
12406                    .iter()
12407                    .map(|selection| {
12408                        buffer
12409                            .text_for_range(selection.start..selection.end)
12410                            .collect()
12411                    })
12412                    .collect();
12413
12414                if reverse {
12415                    selected_texts.rotate_left(1);
12416                } else {
12417                    selected_texts.rotate_right(1);
12418                }
12419
12420                let mut offset_delta: i64 = 0;
12421                let mut new_selections = Vec::new();
12422                let edits: Vec<_> = selections
12423                    .iter()
12424                    .zip(selected_texts.iter())
12425                    .map(|(selection, new_text)| {
12426                        let old_len = (selection.end.0 - selection.start.0) as i64;
12427                        let new_len = new_text.len() as i64;
12428                        let adjusted_start =
12429                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12430                        let adjusted_end =
12431                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12432
12433                        new_selections.push(Selection {
12434                            id: selection.id,
12435                            start: adjusted_start,
12436                            end: adjusted_end,
12437                            reversed: selection.reversed,
12438                            goal: selection.goal,
12439                        });
12440
12441                        offset_delta += new_len - old_len;
12442                        (selection.start..selection.end, new_text.clone())
12443                    })
12444                    .collect();
12445                (edits, new_selections)
12446            } else {
12447                let mut all_rows: Vec<u32> = selections
12448                    .iter()
12449                    .map(|selection| buffer.offset_to_point(selection.start).row)
12450                    .collect();
12451                all_rows.sort_unstable();
12452                all_rows.dedup();
12453
12454                if all_rows.len() < 2 {
12455                    return;
12456                }
12457
12458                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12459                    .iter()
12460                    .map(|&row| {
12461                        let start = Point::new(row, 0);
12462                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12463                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12464                    })
12465                    .collect();
12466
12467                let mut line_texts: Vec<String> = line_ranges
12468                    .iter()
12469                    .map(|range| buffer.text_for_range(range.clone()).collect())
12470                    .collect();
12471
12472                if reverse {
12473                    line_texts.rotate_left(1);
12474                } else {
12475                    line_texts.rotate_right(1);
12476                }
12477
12478                let edits = line_ranges
12479                    .iter()
12480                    .zip(line_texts.iter())
12481                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12482                    .collect();
12483
12484                let num_rows = all_rows.len();
12485                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12486                    .iter()
12487                    .enumerate()
12488                    .map(|(i, &row)| (row, i))
12489                    .collect();
12490
12491                // Compute new line start offsets after rotation (handles CRLF)
12492                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12493                let first_line_start = line_ranges[0].start.0;
12494                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12495                for text in line_texts.iter().take(num_rows - 1) {
12496                    let prev_start = *new_line_starts.last().unwrap();
12497                    new_line_starts.push(prev_start + text.len() + newline_len);
12498                }
12499
12500                let new_selections = selections
12501                    .iter()
12502                    .map(|selection| {
12503                        let point = buffer.offset_to_point(selection.start);
12504                        let old_index = row_to_index[&point.row];
12505                        let new_index = if reverse {
12506                            (old_index + num_rows - 1) % num_rows
12507                        } else {
12508                            (old_index + 1) % num_rows
12509                        };
12510                        let new_offset =
12511                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12512                        Selection {
12513                            id: selection.id,
12514                            start: new_offset,
12515                            end: new_offset,
12516                            reversed: selection.reversed,
12517                            goal: selection.goal,
12518                        }
12519                    })
12520                    .collect();
12521
12522                (edits, new_selections)
12523            }
12524        };
12525
12526        self.transact(window, cx, |this, window, cx| {
12527            this.buffer.update(cx, |buffer, cx| {
12528                buffer.edit(edits, None, cx);
12529            });
12530            this.change_selections(Default::default(), window, cx, |s| {
12531                s.select(new_selections);
12532            });
12533        });
12534    }
12535
12536    fn manipulate_lines<M>(
12537        &mut self,
12538        window: &mut Window,
12539        cx: &mut Context<Self>,
12540        mut manipulate: M,
12541    ) where
12542        M: FnMut(&str) -> LineManipulationResult,
12543    {
12544        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12545
12546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12547        let buffer = self.buffer.read(cx).snapshot(cx);
12548
12549        let mut edits = Vec::new();
12550
12551        let selections = self.selections.all::<Point>(&display_map);
12552        let mut selections = selections.iter().peekable();
12553        let mut contiguous_row_selections = Vec::new();
12554        let mut new_selections = Vec::new();
12555        let mut added_lines = 0;
12556        let mut removed_lines = 0;
12557
12558        while let Some(selection) = selections.next() {
12559            let (start_row, end_row) = consume_contiguous_rows(
12560                &mut contiguous_row_selections,
12561                selection,
12562                &display_map,
12563                &mut selections,
12564            );
12565
12566            let start_point = Point::new(start_row.0, 0);
12567            let end_point = Point::new(
12568                end_row.previous_row().0,
12569                buffer.line_len(end_row.previous_row()),
12570            );
12571            let text = buffer
12572                .text_for_range(start_point..end_point)
12573                .collect::<String>();
12574
12575            let LineManipulationResult {
12576                new_text,
12577                line_count_before,
12578                line_count_after,
12579            } = manipulate(&text);
12580
12581            edits.push((start_point..end_point, new_text));
12582
12583            // Selections must change based on added and removed line count
12584            let start_row =
12585                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12586            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12587            new_selections.push(Selection {
12588                id: selection.id,
12589                start: start_row,
12590                end: end_row,
12591                goal: SelectionGoal::None,
12592                reversed: selection.reversed,
12593            });
12594
12595            if line_count_after > line_count_before {
12596                added_lines += line_count_after - line_count_before;
12597            } else if line_count_before > line_count_after {
12598                removed_lines += line_count_before - line_count_after;
12599            }
12600        }
12601
12602        self.transact(window, cx, |this, window, cx| {
12603            let buffer = this.buffer.update(cx, |buffer, cx| {
12604                buffer.edit(edits, None, cx);
12605                buffer.snapshot(cx)
12606            });
12607
12608            // Recalculate offsets on newly edited buffer
12609            let new_selections = new_selections
12610                .iter()
12611                .map(|s| {
12612                    let start_point = Point::new(s.start.0, 0);
12613                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12614                    Selection {
12615                        id: s.id,
12616                        start: buffer.point_to_offset(start_point),
12617                        end: buffer.point_to_offset(end_point),
12618                        goal: s.goal,
12619                        reversed: s.reversed,
12620                    }
12621                })
12622                .collect();
12623
12624            this.change_selections(Default::default(), window, cx, |s| {
12625                s.select(new_selections);
12626            });
12627
12628            this.request_autoscroll(Autoscroll::fit(), cx);
12629        });
12630    }
12631
12632    fn manipulate_immutable_lines<Fn>(
12633        &mut self,
12634        window: &mut Window,
12635        cx: &mut Context<Self>,
12636        mut callback: Fn,
12637    ) where
12638        Fn: FnMut(&mut Vec<&str>),
12639    {
12640        self.manipulate_lines(window, cx, |text| {
12641            let mut lines: Vec<&str> = text.split('\n').collect();
12642            let line_count_before = lines.len();
12643
12644            callback(&mut lines);
12645
12646            LineManipulationResult {
12647                new_text: lines.join("\n"),
12648                line_count_before,
12649                line_count_after: lines.len(),
12650            }
12651        });
12652    }
12653
12654    fn manipulate_mutable_lines<Fn>(
12655        &mut self,
12656        window: &mut Window,
12657        cx: &mut Context<Self>,
12658        mut callback: Fn,
12659    ) where
12660        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12661    {
12662        self.manipulate_lines(window, cx, |text| {
12663            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12664            let line_count_before = lines.len();
12665
12666            callback(&mut lines);
12667
12668            LineManipulationResult {
12669                new_text: lines.join("\n"),
12670                line_count_before,
12671                line_count_after: lines.len(),
12672            }
12673        });
12674    }
12675
12676    pub fn convert_indentation_to_spaces(
12677        &mut self,
12678        _: &ConvertIndentationToSpaces,
12679        window: &mut Window,
12680        cx: &mut Context<Self>,
12681    ) {
12682        let settings = self.buffer.read(cx).language_settings(cx);
12683        let tab_size = settings.tab_size.get() as usize;
12684
12685        self.manipulate_mutable_lines(window, cx, |lines| {
12686            // Allocates a reasonably sized scratch buffer once for the whole loop
12687            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12688            // Avoids recomputing spaces that could be inserted many times
12689            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12690                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12691                .collect();
12692
12693            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12694                let mut chars = line.as_ref().chars();
12695                let mut col = 0;
12696                let mut changed = false;
12697
12698                for ch in chars.by_ref() {
12699                    match ch {
12700                        ' ' => {
12701                            reindented_line.push(' ');
12702                            col += 1;
12703                        }
12704                        '\t' => {
12705                            // \t are converted to spaces depending on the current column
12706                            let spaces_len = tab_size - (col % tab_size);
12707                            reindented_line.extend(&space_cache[spaces_len - 1]);
12708                            col += spaces_len;
12709                            changed = true;
12710                        }
12711                        _ => {
12712                            // If we dont append before break, the character is consumed
12713                            reindented_line.push(ch);
12714                            break;
12715                        }
12716                    }
12717                }
12718
12719                if !changed {
12720                    reindented_line.clear();
12721                    continue;
12722                }
12723                // Append the rest of the line and replace old reference with new one
12724                reindented_line.extend(chars);
12725                *line = Cow::Owned(reindented_line.clone());
12726                reindented_line.clear();
12727            }
12728        });
12729    }
12730
12731    pub fn convert_indentation_to_tabs(
12732        &mut self,
12733        _: &ConvertIndentationToTabs,
12734        window: &mut Window,
12735        cx: &mut Context<Self>,
12736    ) {
12737        let settings = self.buffer.read(cx).language_settings(cx);
12738        let tab_size = settings.tab_size.get() as usize;
12739
12740        self.manipulate_mutable_lines(window, cx, |lines| {
12741            // Allocates a reasonably sized buffer once for the whole loop
12742            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12743            // Avoids recomputing spaces that could be inserted many times
12744            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12745                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12746                .collect();
12747
12748            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12749                let mut chars = line.chars();
12750                let mut spaces_count = 0;
12751                let mut first_non_indent_char = None;
12752                let mut changed = false;
12753
12754                for ch in chars.by_ref() {
12755                    match ch {
12756                        ' ' => {
12757                            // Keep track of spaces. Append \t when we reach tab_size
12758                            spaces_count += 1;
12759                            changed = true;
12760                            if spaces_count == tab_size {
12761                                reindented_line.push('\t');
12762                                spaces_count = 0;
12763                            }
12764                        }
12765                        '\t' => {
12766                            reindented_line.push('\t');
12767                            spaces_count = 0;
12768                        }
12769                        _ => {
12770                            // Dont append it yet, we might have remaining spaces
12771                            first_non_indent_char = Some(ch);
12772                            break;
12773                        }
12774                    }
12775                }
12776
12777                if !changed {
12778                    reindented_line.clear();
12779                    continue;
12780                }
12781                // Remaining spaces that didn't make a full tab stop
12782                if spaces_count > 0 {
12783                    reindented_line.extend(&space_cache[spaces_count - 1]);
12784                }
12785                // If we consume an extra character that was not indentation, add it back
12786                if let Some(extra_char) = first_non_indent_char {
12787                    reindented_line.push(extra_char);
12788                }
12789                // Append the rest of the line and replace old reference with new one
12790                reindented_line.extend(chars);
12791                *line = Cow::Owned(reindented_line.clone());
12792                reindented_line.clear();
12793            }
12794        });
12795    }
12796
12797    pub fn convert_to_upper_case(
12798        &mut self,
12799        _: &ConvertToUpperCase,
12800        window: &mut Window,
12801        cx: &mut Context<Self>,
12802    ) {
12803        self.manipulate_text(window, cx, |text| text.to_uppercase())
12804    }
12805
12806    pub fn convert_to_lower_case(
12807        &mut self,
12808        _: &ConvertToLowerCase,
12809        window: &mut Window,
12810        cx: &mut Context<Self>,
12811    ) {
12812        self.manipulate_text(window, cx, |text| text.to_lowercase())
12813    }
12814
12815    pub fn convert_to_title_case(
12816        &mut self,
12817        _: &ConvertToTitleCase,
12818        window: &mut Window,
12819        cx: &mut Context<Self>,
12820    ) {
12821        self.manipulate_text(window, cx, |text| {
12822            Self::convert_text_case(text, Case::Title)
12823        })
12824    }
12825
12826    pub fn convert_to_snake_case(
12827        &mut self,
12828        _: &ConvertToSnakeCase,
12829        window: &mut Window,
12830        cx: &mut Context<Self>,
12831    ) {
12832        self.manipulate_text(window, cx, |text| {
12833            Self::convert_text_case(text, Case::Snake)
12834        })
12835    }
12836
12837    pub fn convert_to_kebab_case(
12838        &mut self,
12839        _: &ConvertToKebabCase,
12840        window: &mut Window,
12841        cx: &mut Context<Self>,
12842    ) {
12843        self.manipulate_text(window, cx, |text| {
12844            Self::convert_text_case(text, Case::Kebab)
12845        })
12846    }
12847
12848    pub fn convert_to_upper_camel_case(
12849        &mut self,
12850        _: &ConvertToUpperCamelCase,
12851        window: &mut Window,
12852        cx: &mut Context<Self>,
12853    ) {
12854        self.manipulate_text(window, cx, |text| {
12855            Self::convert_text_case(text, Case::UpperCamel)
12856        })
12857    }
12858
12859    pub fn convert_to_lower_camel_case(
12860        &mut self,
12861        _: &ConvertToLowerCamelCase,
12862        window: &mut Window,
12863        cx: &mut Context<Self>,
12864    ) {
12865        self.manipulate_text(window, cx, |text| {
12866            Self::convert_text_case(text, Case::Camel)
12867        })
12868    }
12869
12870    pub fn convert_to_opposite_case(
12871        &mut self,
12872        _: &ConvertToOppositeCase,
12873        window: &mut Window,
12874        cx: &mut Context<Self>,
12875    ) {
12876        self.manipulate_text(window, cx, |text| {
12877            text.chars()
12878                .fold(String::with_capacity(text.len()), |mut t, c| {
12879                    if c.is_uppercase() {
12880                        t.extend(c.to_lowercase());
12881                    } else {
12882                        t.extend(c.to_uppercase());
12883                    }
12884                    t
12885                })
12886        })
12887    }
12888
12889    pub fn convert_to_sentence_case(
12890        &mut self,
12891        _: &ConvertToSentenceCase,
12892        window: &mut Window,
12893        cx: &mut Context<Self>,
12894    ) {
12895        self.manipulate_text(window, cx, |text| {
12896            Self::convert_text_case(text, Case::Sentence)
12897        })
12898    }
12899
12900    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12901        self.manipulate_text(window, cx, |text| {
12902            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12903            if has_upper_case_characters {
12904                text.to_lowercase()
12905            } else {
12906                text.to_uppercase()
12907            }
12908        })
12909    }
12910
12911    pub fn convert_to_rot13(
12912        &mut self,
12913        _: &ConvertToRot13,
12914        window: &mut Window,
12915        cx: &mut Context<Self>,
12916    ) {
12917        self.manipulate_text(window, cx, |text| {
12918            text.chars()
12919                .map(|c| match c {
12920                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12921                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12922                    _ => c,
12923                })
12924                .collect()
12925        })
12926    }
12927
12928    fn convert_text_case(text: &str, case: Case) -> String {
12929        text.lines()
12930            .map(|line| {
12931                let trimmed_start = line.trim_start();
12932                let leading = &line[..line.len() - trimmed_start.len()];
12933                let trimmed = trimmed_start.trim_end();
12934                let trailing = &trimmed_start[trimmed.len()..];
12935                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12936            })
12937            .join("\n")
12938    }
12939
12940    pub fn convert_to_rot47(
12941        &mut self,
12942        _: &ConvertToRot47,
12943        window: &mut Window,
12944        cx: &mut Context<Self>,
12945    ) {
12946        self.manipulate_text(window, cx, |text| {
12947            text.chars()
12948                .map(|c| {
12949                    let code_point = c as u32;
12950                    if code_point >= 33 && code_point <= 126 {
12951                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12952                    }
12953                    c
12954                })
12955                .collect()
12956        })
12957    }
12958
12959    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12960    where
12961        Fn: FnMut(&str) -> String,
12962    {
12963        let buffer = self.buffer.read(cx).snapshot(cx);
12964
12965        let mut new_selections = Vec::new();
12966        let mut edits = Vec::new();
12967        let mut selection_adjustment = 0isize;
12968
12969        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12970            let selection_is_empty = selection.is_empty();
12971
12972            let (start, end) = if selection_is_empty {
12973                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12974                (word_range.start, word_range.end)
12975            } else {
12976                (
12977                    buffer.point_to_offset(selection.start),
12978                    buffer.point_to_offset(selection.end),
12979                )
12980            };
12981
12982            let text = buffer.text_for_range(start..end).collect::<String>();
12983            let old_length = text.len() as isize;
12984            let text = callback(&text);
12985
12986            new_selections.push(Selection {
12987                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12988                end: MultiBufferOffset(
12989                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12990                ),
12991                goal: SelectionGoal::None,
12992                id: selection.id,
12993                reversed: selection.reversed,
12994            });
12995
12996            selection_adjustment += old_length - text.len() as isize;
12997
12998            edits.push((start..end, text));
12999        }
13000
13001        self.transact(window, cx, |this, window, cx| {
13002            this.buffer.update(cx, |buffer, cx| {
13003                buffer.edit(edits, None, cx);
13004            });
13005
13006            this.change_selections(Default::default(), window, cx, |s| {
13007                s.select(new_selections);
13008            });
13009
13010            this.request_autoscroll(Autoscroll::fit(), cx);
13011        });
13012    }
13013
13014    pub fn move_selection_on_drop(
13015        &mut self,
13016        selection: &Selection<Anchor>,
13017        target: DisplayPoint,
13018        is_cut: bool,
13019        window: &mut Window,
13020        cx: &mut Context<Self>,
13021    ) {
13022        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13023        let buffer = display_map.buffer_snapshot();
13024        let mut edits = Vec::new();
13025        let insert_point = display_map
13026            .clip_point(target, Bias::Left)
13027            .to_point(&display_map);
13028        let text = buffer
13029            .text_for_range(selection.start..selection.end)
13030            .collect::<String>();
13031        if is_cut {
13032            edits.push(((selection.start..selection.end), String::new()));
13033        }
13034        let insert_anchor = buffer.anchor_before(insert_point);
13035        edits.push(((insert_anchor..insert_anchor), text));
13036        let last_edit_start = insert_anchor.bias_left(buffer);
13037        let last_edit_end = insert_anchor.bias_right(buffer);
13038        self.transact(window, cx, |this, window, cx| {
13039            this.buffer.update(cx, |buffer, cx| {
13040                buffer.edit(edits, None, cx);
13041            });
13042            this.change_selections(Default::default(), window, cx, |s| {
13043                s.select_anchor_ranges([last_edit_start..last_edit_end]);
13044            });
13045        });
13046    }
13047
13048    pub fn clear_selection_drag_state(&mut self) {
13049        self.selection_drag_state = SelectionDragState::None;
13050    }
13051
13052    pub fn duplicate(
13053        &mut self,
13054        upwards: bool,
13055        whole_lines: bool,
13056        window: &mut Window,
13057        cx: &mut Context<Self>,
13058    ) {
13059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13060
13061        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13062        let buffer = display_map.buffer_snapshot();
13063        let selections = self.selections.all::<Point>(&display_map);
13064
13065        let mut edits = Vec::new();
13066        let mut selections_iter = selections.iter().peekable();
13067        while let Some(selection) = selections_iter.next() {
13068            let mut rows = selection.spanned_rows(false, &display_map);
13069            // duplicate line-wise
13070            if whole_lines || selection.start == selection.end {
13071                // Avoid duplicating the same lines twice.
13072                while let Some(next_selection) = selections_iter.peek() {
13073                    let next_rows = next_selection.spanned_rows(false, &display_map);
13074                    if next_rows.start < rows.end {
13075                        rows.end = next_rows.end;
13076                        selections_iter.next().unwrap();
13077                    } else {
13078                        break;
13079                    }
13080                }
13081
13082                // Copy the text from the selected row region and splice it either at the start
13083                // or end of the region.
13084                let start = Point::new(rows.start.0, 0);
13085                let end = Point::new(
13086                    rows.end.previous_row().0,
13087                    buffer.line_len(rows.end.previous_row()),
13088                );
13089
13090                let mut text = buffer.text_for_range(start..end).collect::<String>();
13091
13092                let insert_location = if upwards {
13093                    // When duplicating upward, we need to insert before the current line.
13094                    // If we're on the last line and it doesn't end with a newline,
13095                    // we need to add a newline before the duplicated content.
13096                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
13097                        && buffer.max_point().column > 0
13098                        && !text.ends_with('\n');
13099
13100                    if needs_leading_newline {
13101                        text.insert(0, '\n');
13102                        end
13103                    } else {
13104                        text.push('\n');
13105                        Point::new(rows.start.0, 0)
13106                    }
13107                } else {
13108                    text.push('\n');
13109                    start
13110                };
13111                edits.push((insert_location..insert_location, text));
13112            } else {
13113                // duplicate character-wise
13114                let start = selection.start;
13115                let end = selection.end;
13116                let text = buffer.text_for_range(start..end).collect::<String>();
13117                edits.push((selection.end..selection.end, text));
13118            }
13119        }
13120
13121        self.transact(window, cx, |this, window, cx| {
13122            this.buffer.update(cx, |buffer, cx| {
13123                buffer.edit(edits, None, cx);
13124            });
13125
13126            // When duplicating upward with whole lines, move the cursor to the duplicated line
13127            if upwards && whole_lines {
13128                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
13129
13130                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13131                    let mut new_ranges = Vec::new();
13132                    let selections = s.all::<Point>(&display_map);
13133                    let mut selections_iter = selections.iter().peekable();
13134
13135                    while let Some(first_selection) = selections_iter.next() {
13136                        // Group contiguous selections together to find the total row span
13137                        let mut group_selections = vec![first_selection];
13138                        let mut rows = first_selection.spanned_rows(false, &display_map);
13139
13140                        while let Some(next_selection) = selections_iter.peek() {
13141                            let next_rows = next_selection.spanned_rows(false, &display_map);
13142                            if next_rows.start < rows.end {
13143                                rows.end = next_rows.end;
13144                                group_selections.push(selections_iter.next().unwrap());
13145                            } else {
13146                                break;
13147                            }
13148                        }
13149
13150                        let row_count = rows.end.0 - rows.start.0;
13151
13152                        // Move all selections in this group up by the total number of duplicated rows
13153                        for selection in group_selections {
13154                            let new_start = Point::new(
13155                                selection.start.row.saturating_sub(row_count),
13156                                selection.start.column,
13157                            );
13158
13159                            let new_end = Point::new(
13160                                selection.end.row.saturating_sub(row_count),
13161                                selection.end.column,
13162                            );
13163
13164                            new_ranges.push(new_start..new_end);
13165                        }
13166                    }
13167
13168                    s.select_ranges(new_ranges);
13169                });
13170            }
13171
13172            this.request_autoscroll(Autoscroll::fit(), cx);
13173        });
13174    }
13175
13176    pub fn duplicate_line_up(
13177        &mut self,
13178        _: &DuplicateLineUp,
13179        window: &mut Window,
13180        cx: &mut Context<Self>,
13181    ) {
13182        self.duplicate(true, true, window, cx);
13183    }
13184
13185    pub fn duplicate_line_down(
13186        &mut self,
13187        _: &DuplicateLineDown,
13188        window: &mut Window,
13189        cx: &mut Context<Self>,
13190    ) {
13191        self.duplicate(false, true, window, cx);
13192    }
13193
13194    pub fn duplicate_selection(
13195        &mut self,
13196        _: &DuplicateSelection,
13197        window: &mut Window,
13198        cx: &mut Context<Self>,
13199    ) {
13200        self.duplicate(false, false, window, cx);
13201    }
13202
13203    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
13204        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13205        if self.mode.is_single_line() {
13206            cx.propagate();
13207            return;
13208        }
13209
13210        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13211        let buffer = self.buffer.read(cx).snapshot(cx);
13212
13213        let mut edits = Vec::new();
13214        let mut unfold_ranges = Vec::new();
13215        let mut refold_creases = Vec::new();
13216
13217        let selections = self.selections.all::<Point>(&display_map);
13218        let mut selections = selections.iter().peekable();
13219        let mut contiguous_row_selections = Vec::new();
13220        let mut new_selections = Vec::new();
13221
13222        while let Some(selection) = selections.next() {
13223            // Find all the selections that span a contiguous row range
13224            let (start_row, end_row) = consume_contiguous_rows(
13225                &mut contiguous_row_selections,
13226                selection,
13227                &display_map,
13228                &mut selections,
13229            );
13230
13231            // Move the text spanned by the row range to be before the line preceding the row range
13232            if start_row.0 > 0 {
13233                let range_to_move = Point::new(
13234                    start_row.previous_row().0,
13235                    buffer.line_len(start_row.previous_row()),
13236                )
13237                    ..Point::new(
13238                        end_row.previous_row().0,
13239                        buffer.line_len(end_row.previous_row()),
13240                    );
13241                let insertion_point = display_map
13242                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
13243                    .0;
13244
13245                // Don't move lines across excerpts
13246                if buffer
13247                    .excerpt_containing(insertion_point..range_to_move.end)
13248                    .is_some()
13249                {
13250                    let text = buffer
13251                        .text_for_range(range_to_move.clone())
13252                        .flat_map(|s| s.chars())
13253                        .skip(1)
13254                        .chain(['\n'])
13255                        .collect::<String>();
13256
13257                    edits.push((
13258                        buffer.anchor_after(range_to_move.start)
13259                            ..buffer.anchor_before(range_to_move.end),
13260                        String::new(),
13261                    ));
13262                    let insertion_anchor = buffer.anchor_after(insertion_point);
13263                    edits.push((insertion_anchor..insertion_anchor, text));
13264
13265                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
13266
13267                    // Move selections up
13268                    new_selections.extend(contiguous_row_selections.drain(..).map(
13269                        |mut selection| {
13270                            selection.start.row -= row_delta;
13271                            selection.end.row -= row_delta;
13272                            selection
13273                        },
13274                    ));
13275
13276                    // Move folds up
13277                    unfold_ranges.push(range_to_move.clone());
13278                    for fold in display_map.folds_in_range(
13279                        buffer.anchor_before(range_to_move.start)
13280                            ..buffer.anchor_after(range_to_move.end),
13281                    ) {
13282                        let mut start = fold.range.start.to_point(&buffer);
13283                        let mut end = fold.range.end.to_point(&buffer);
13284                        start.row -= row_delta;
13285                        end.row -= row_delta;
13286                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13287                    }
13288                }
13289            }
13290
13291            // If we didn't move line(s), preserve the existing selections
13292            new_selections.append(&mut contiguous_row_selections);
13293        }
13294
13295        self.transact(window, cx, |this, window, cx| {
13296            this.unfold_ranges(&unfold_ranges, true, true, cx);
13297            this.buffer.update(cx, |buffer, cx| {
13298                for (range, text) in edits {
13299                    buffer.edit([(range, text)], None, cx);
13300                }
13301            });
13302            this.fold_creases(refold_creases, true, window, cx);
13303            this.change_selections(Default::default(), window, cx, |s| {
13304                s.select(new_selections);
13305            })
13306        });
13307    }
13308
13309    pub fn move_line_down(
13310        &mut self,
13311        _: &MoveLineDown,
13312        window: &mut Window,
13313        cx: &mut Context<Self>,
13314    ) {
13315        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13316        if self.mode.is_single_line() {
13317            cx.propagate();
13318            return;
13319        }
13320
13321        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
13322        let buffer = self.buffer.read(cx).snapshot(cx);
13323
13324        let mut edits = Vec::new();
13325        let mut unfold_ranges = Vec::new();
13326        let mut refold_creases = Vec::new();
13327
13328        let selections = self.selections.all::<Point>(&display_map);
13329        let mut selections = selections.iter().peekable();
13330        let mut contiguous_row_selections = Vec::new();
13331        let mut new_selections = Vec::new();
13332
13333        while let Some(selection) = selections.next() {
13334            // Find all the selections that span a contiguous row range
13335            let (start_row, end_row) = consume_contiguous_rows(
13336                &mut contiguous_row_selections,
13337                selection,
13338                &display_map,
13339                &mut selections,
13340            );
13341
13342            // Move the text spanned by the row range to be after the last line of the row range
13343            if end_row.0 <= buffer.max_point().row {
13344                let range_to_move =
13345                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
13346                let insertion_point = display_map
13347                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
13348                    .0;
13349
13350                // Don't move lines across excerpt boundaries
13351                if buffer
13352                    .excerpt_containing(range_to_move.start..insertion_point)
13353                    .is_some()
13354                {
13355                    let mut text = String::from("\n");
13356                    text.extend(buffer.text_for_range(range_to_move.clone()));
13357                    text.pop(); // Drop trailing newline
13358                    edits.push((
13359                        buffer.anchor_after(range_to_move.start)
13360                            ..buffer.anchor_before(range_to_move.end),
13361                        String::new(),
13362                    ));
13363                    let insertion_anchor = buffer.anchor_after(insertion_point);
13364                    edits.push((insertion_anchor..insertion_anchor, text));
13365
13366                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
13367
13368                    // Move selections down
13369                    new_selections.extend(contiguous_row_selections.drain(..).map(
13370                        |mut selection| {
13371                            selection.start.row += row_delta;
13372                            selection.end.row += row_delta;
13373                            selection
13374                        },
13375                    ));
13376
13377                    // Move folds down
13378                    unfold_ranges.push(range_to_move.clone());
13379                    for fold in display_map.folds_in_range(
13380                        buffer.anchor_before(range_to_move.start)
13381                            ..buffer.anchor_after(range_to_move.end),
13382                    ) {
13383                        let mut start = fold.range.start.to_point(&buffer);
13384                        let mut end = fold.range.end.to_point(&buffer);
13385                        start.row += row_delta;
13386                        end.row += row_delta;
13387                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13388                    }
13389                }
13390            }
13391
13392            // If we didn't move line(s), preserve the existing selections
13393            new_selections.append(&mut contiguous_row_selections);
13394        }
13395
13396        self.transact(window, cx, |this, window, cx| {
13397            this.unfold_ranges(&unfold_ranges, true, true, cx);
13398            this.buffer.update(cx, |buffer, cx| {
13399                for (range, text) in edits {
13400                    buffer.edit([(range, text)], None, cx);
13401                }
13402            });
13403            this.fold_creases(refold_creases, true, window, cx);
13404            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13405        });
13406    }
13407
13408    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13409        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13410        let text_layout_details = &self.text_layout_details(window, cx);
13411        self.transact(window, cx, |this, window, cx| {
13412            let edits = this.change_selections(Default::default(), window, cx, |s| {
13413                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13414                s.move_with(&mut |display_map, selection| {
13415                    if !selection.is_empty() {
13416                        return;
13417                    }
13418
13419                    let mut head = selection.head();
13420                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13421                    if head.column() == display_map.line_len(head.row()) {
13422                        transpose_offset = display_map
13423                            .buffer_snapshot()
13424                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13425                    }
13426
13427                    if transpose_offset == MultiBufferOffset(0) {
13428                        return;
13429                    }
13430
13431                    *head.column_mut() += 1;
13432                    head = display_map.clip_point(head, Bias::Right);
13433                    let goal = SelectionGoal::HorizontalPosition(
13434                        display_map
13435                            .x_for_display_point(head, text_layout_details)
13436                            .into(),
13437                    );
13438                    selection.collapse_to(head, goal);
13439
13440                    let transpose_start = display_map
13441                        .buffer_snapshot()
13442                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13443                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13444                        let transpose_end = display_map
13445                            .buffer_snapshot()
13446                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13447                        if let Some(ch) = display_map
13448                            .buffer_snapshot()
13449                            .chars_at(transpose_start)
13450                            .next()
13451                        {
13452                            edits.push((transpose_start..transpose_offset, String::new()));
13453                            edits.push((transpose_end..transpose_end, ch.to_string()));
13454                        }
13455                    }
13456                });
13457                edits
13458            });
13459            this.buffer
13460                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13461            let selections = this
13462                .selections
13463                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13464            this.change_selections(Default::default(), window, cx, |s| {
13465                s.select(selections);
13466            });
13467        });
13468    }
13469
13470    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13471        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13472        if self.mode.is_single_line() {
13473            cx.propagate();
13474            return;
13475        }
13476
13477        self.rewrap_impl(RewrapOptions::default(), cx)
13478    }
13479
13480    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13481        let buffer = self.buffer.read(cx).snapshot(cx);
13482        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13483
13484        #[derive(Clone, Debug, PartialEq)]
13485        enum CommentFormat {
13486            /// single line comment, with prefix for line
13487            Line(String),
13488            /// single line within a block comment, with prefix for line
13489            BlockLine(String),
13490            /// a single line of a block comment that includes the initial delimiter
13491            BlockCommentWithStart(BlockCommentConfig),
13492            /// a single line of a block comment that includes the ending delimiter
13493            BlockCommentWithEnd(BlockCommentConfig),
13494        }
13495
13496        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13497        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13498            let language_settings = buffer.language_settings_at(selection.head(), cx);
13499            let language_scope = buffer.language_scope_at(selection.head());
13500
13501            let indent_and_prefix_for_row =
13502                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13503                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13504                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13505                        &language_scope
13506                    {
13507                        let indent_end = Point::new(row, indent.len);
13508                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13509                        let line_text_after_indent = buffer
13510                            .text_for_range(indent_end..line_end)
13511                            .collect::<String>();
13512
13513                        let is_within_comment_override = buffer
13514                            .language_scope_at(indent_end)
13515                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13516                        let comment_delimiters = if is_within_comment_override {
13517                            // we are within a comment syntax node, but we don't
13518                            // yet know what kind of comment: block, doc or line
13519                            match (
13520                                language_scope.documentation_comment(),
13521                                language_scope.block_comment(),
13522                            ) {
13523                                (Some(config), _) | (_, Some(config))
13524                                    if buffer.contains_str_at(indent_end, &config.start) =>
13525                                {
13526                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13527                                }
13528                                (Some(config), _) | (_, Some(config))
13529                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13530                                {
13531                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13532                                }
13533                                (Some(config), _) | (_, Some(config))
13534                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13535                                {
13536                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13537                                }
13538                                (_, _) => language_scope
13539                                    .line_comment_prefixes()
13540                                    .iter()
13541                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13542                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13543                            }
13544                        } else {
13545                            // we not in an overridden comment node, but we may
13546                            // be within a non-overridden line comment node
13547                            language_scope
13548                                .line_comment_prefixes()
13549                                .iter()
13550                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13551                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13552                        };
13553
13554                        let rewrap_prefix = language_scope
13555                            .rewrap_prefixes()
13556                            .iter()
13557                            .find_map(|prefix_regex| {
13558                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13559                                    if mat.start() == 0 {
13560                                        Some(mat.as_str().to_string())
13561                                    } else {
13562                                        None
13563                                    }
13564                                })
13565                            })
13566                            .flatten();
13567                        (comment_delimiters, rewrap_prefix)
13568                    } else {
13569                        (None, None)
13570                    };
13571                    (indent, comment_prefix, rewrap_prefix)
13572                };
13573
13574            let mut start_row = selection.start.row;
13575            let mut end_row = selection.end.row;
13576
13577            if selection.is_empty() {
13578                let cursor_row = selection.start.row;
13579
13580                let (mut indent_size, comment_prefix, _) = indent_and_prefix_for_row(cursor_row);
13581                let line_prefix = match &comment_prefix {
13582                    Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13583                        Some(prefix.as_str())
13584                    }
13585                    Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13586                        prefix, ..
13587                    })) => Some(prefix.as_ref()),
13588                    Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13589                        start: _,
13590                        end: _,
13591                        prefix,
13592                        tab_size,
13593                    })) => {
13594                        indent_size.len += tab_size;
13595                        Some(prefix.as_ref())
13596                    }
13597                    None => None,
13598                };
13599                let indent_prefix = indent_size.chars().collect::<String>();
13600                let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13601
13602                'expand_upwards: while start_row > 0 {
13603                    let prev_row = start_row - 1;
13604                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13605                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13606                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13607                    {
13608                        start_row = prev_row;
13609                    } else {
13610                        break 'expand_upwards;
13611                    }
13612                }
13613
13614                'expand_downwards: while end_row < buffer.max_point().row {
13615                    let next_row = end_row + 1;
13616                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13617                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13618                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13619                    {
13620                        end_row = next_row;
13621                    } else {
13622                        break 'expand_downwards;
13623                    }
13624                }
13625            }
13626
13627            let mut non_blank_rows_iter = (start_row..=end_row)
13628                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13629                .peekable();
13630
13631            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13632                row
13633            } else {
13634                return Vec::new();
13635            };
13636
13637            let mut ranges = Vec::new();
13638
13639            let mut current_range_start = first_row;
13640            let mut prev_row = first_row;
13641            let (
13642                mut current_range_indent,
13643                mut current_range_comment_delimiters,
13644                mut current_range_rewrap_prefix,
13645            ) = indent_and_prefix_for_row(first_row);
13646
13647            for row in non_blank_rows_iter.skip(1) {
13648                let has_paragraph_break = row > prev_row + 1;
13649
13650                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13651                    indent_and_prefix_for_row(row);
13652
13653                let has_indent_change = row_indent != current_range_indent;
13654                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13655
13656                let has_boundary_change = has_comment_change
13657                    || row_rewrap_prefix.is_some()
13658                    || (has_indent_change && current_range_comment_delimiters.is_some());
13659
13660                if has_paragraph_break || has_boundary_change {
13661                    ranges.push((
13662                        language_settings.clone(),
13663                        Point::new(current_range_start, 0)
13664                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13665                        current_range_indent,
13666                        current_range_comment_delimiters.clone(),
13667                        current_range_rewrap_prefix.clone(),
13668                    ));
13669                    current_range_start = row;
13670                    current_range_indent = row_indent;
13671                    current_range_comment_delimiters = row_comment_delimiters;
13672                    current_range_rewrap_prefix = row_rewrap_prefix;
13673                }
13674                prev_row = row;
13675            }
13676
13677            ranges.push((
13678                language_settings.clone(),
13679                Point::new(current_range_start, 0)
13680                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13681                current_range_indent,
13682                current_range_comment_delimiters,
13683                current_range_rewrap_prefix,
13684            ));
13685
13686            ranges
13687        });
13688
13689        let mut edits = Vec::new();
13690        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13691
13692        for (language_settings, wrap_range, mut indent_size, comment_prefix, rewrap_prefix) in
13693            wrap_ranges
13694        {
13695            let start_row = wrap_range.start.row;
13696            let end_row = wrap_range.end.row;
13697
13698            // Skip selections that overlap with a range that has already been rewrapped.
13699            let selection_range = start_row..end_row;
13700            if rewrapped_row_ranges
13701                .iter()
13702                .any(|range| range.overlaps(&selection_range))
13703            {
13704                continue;
13705            }
13706
13707            let tab_size = language_settings.tab_size;
13708
13709            let (line_prefix, inside_comment) = match &comment_prefix {
13710                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13711                    (Some(prefix.as_str()), true)
13712                }
13713                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13714                    (Some(prefix.as_ref()), true)
13715                }
13716                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13717                    start: _,
13718                    end: _,
13719                    prefix,
13720                    tab_size,
13721                })) => {
13722                    indent_size.len += tab_size;
13723                    (Some(prefix.as_ref()), true)
13724                }
13725                None => (None, false),
13726            };
13727            let indent_prefix = indent_size.chars().collect::<String>();
13728            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13729
13730            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13731                RewrapBehavior::InComments => inside_comment,
13732                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13733                RewrapBehavior::Anywhere => true,
13734            };
13735
13736            let should_rewrap = options.override_language_settings
13737                || allow_rewrap_based_on_language
13738                || self.hard_wrap.is_some();
13739            if !should_rewrap {
13740                continue;
13741            }
13742
13743            let start = Point::new(start_row, 0);
13744            let start_offset = ToOffset::to_offset(&start, &buffer);
13745            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13746            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13747            let mut first_line_delimiter = None;
13748            let mut last_line_delimiter = None;
13749            let Some(lines_without_prefixes) = selection_text
13750                .lines()
13751                .enumerate()
13752                .map(|(ix, line)| {
13753                    let line_trimmed = line.trim_start();
13754                    if rewrap_prefix.is_some() && ix > 0 {
13755                        Ok(line_trimmed)
13756                    } else if let Some(
13757                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13758                            start,
13759                            prefix,
13760                            end,
13761                            tab_size,
13762                        })
13763                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13764                            start,
13765                            prefix,
13766                            end,
13767                            tab_size,
13768                        }),
13769                    ) = &comment_prefix
13770                    {
13771                        let line_trimmed = line_trimmed
13772                            .strip_prefix(start.as_ref())
13773                            .map(|s| {
13774                                let mut indent_size = indent_size;
13775                                indent_size.len -= tab_size;
13776                                let indent_prefix: String = indent_size.chars().collect();
13777                                first_line_delimiter = Some((indent_prefix, start));
13778                                s.trim_start()
13779                            })
13780                            .unwrap_or(line_trimmed);
13781                        let line_trimmed = line_trimmed
13782                            .strip_suffix(end.as_ref())
13783                            .map(|s| {
13784                                last_line_delimiter = Some(end);
13785                                s.trim_end()
13786                            })
13787                            .unwrap_or(line_trimmed);
13788                        let line_trimmed = line_trimmed
13789                            .strip_prefix(prefix.as_ref())
13790                            .unwrap_or(line_trimmed);
13791                        Ok(line_trimmed)
13792                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13793                        line_trimmed.strip_prefix(prefix).with_context(|| {
13794                            format!("line did not start with prefix {prefix:?}: {line:?}")
13795                        })
13796                    } else {
13797                        line_trimmed
13798                            .strip_prefix(&line_prefix.trim_start())
13799                            .with_context(|| {
13800                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13801                            })
13802                    }
13803                })
13804                .collect::<Result<Vec<_>, _>>()
13805                .log_err()
13806            else {
13807                continue;
13808            };
13809
13810            let wrap_column = options.line_length.or(self.hard_wrap).unwrap_or_else(|| {
13811                buffer
13812                    .language_settings_at(Point::new(start_row, 0), cx)
13813                    .preferred_line_length as usize
13814            });
13815
13816            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13817                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13818            } else {
13819                line_prefix.clone()
13820            };
13821
13822            let wrapped_text = {
13823                let mut wrapped_text = wrap_with_prefix(
13824                    line_prefix,
13825                    subsequent_lines_prefix,
13826                    lines_without_prefixes.join("\n"),
13827                    wrap_column,
13828                    tab_size,
13829                    options.preserve_existing_whitespace,
13830                );
13831
13832                if let Some((indent, delimiter)) = first_line_delimiter {
13833                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13834                }
13835                if let Some(last_line) = last_line_delimiter {
13836                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13837                }
13838
13839                wrapped_text
13840            };
13841
13842            // TODO: should always use char-based diff while still supporting cursor behavior that
13843            // matches vim.
13844            let mut diff_options = DiffOptions::default();
13845            if options.override_language_settings {
13846                diff_options.max_word_diff_len = 0;
13847                diff_options.max_word_diff_line_count = 0;
13848            } else {
13849                diff_options.max_word_diff_len = usize::MAX;
13850                diff_options.max_word_diff_line_count = usize::MAX;
13851            }
13852
13853            for (old_range, new_text) in
13854                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13855            {
13856                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13857                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13858                edits.push((edit_start..edit_end, new_text));
13859            }
13860
13861            rewrapped_row_ranges.push(start_row..=end_row);
13862        }
13863
13864        self.buffer
13865            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13866    }
13867
13868    pub fn cut_common(
13869        &mut self,
13870        cut_no_selection_line: bool,
13871        window: &mut Window,
13872        cx: &mut Context<Self>,
13873    ) -> ClipboardItem {
13874        let mut text = String::new();
13875        let buffer = self.buffer.read(cx).snapshot(cx);
13876        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13877        let mut clipboard_selections = Vec::with_capacity(selections.len());
13878        {
13879            let max_point = buffer.max_point();
13880            let mut is_first = true;
13881            let mut prev_selection_was_entire_line = false;
13882            for selection in &mut selections {
13883                let is_entire_line =
13884                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13885                if is_entire_line {
13886                    selection.start = Point::new(selection.start.row, 0);
13887                    if !selection.is_empty() && selection.end.column == 0 {
13888                        selection.end = cmp::min(max_point, selection.end);
13889                    } else {
13890                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13891                    }
13892                    selection.goal = SelectionGoal::None;
13893                }
13894                if is_first {
13895                    is_first = false;
13896                } else if !prev_selection_was_entire_line {
13897                    text += "\n";
13898                }
13899                prev_selection_was_entire_line = is_entire_line;
13900                let mut len = 0;
13901                for chunk in buffer.text_for_range(selection.start..selection.end) {
13902                    text.push_str(chunk);
13903                    len += chunk.len();
13904                }
13905
13906                clipboard_selections.push(ClipboardSelection::for_buffer(
13907                    len,
13908                    is_entire_line,
13909                    selection.range(),
13910                    &buffer,
13911                    self.project.as_ref(),
13912                    cx,
13913                ));
13914            }
13915        }
13916
13917        self.transact(window, cx, |this, window, cx| {
13918            this.change_selections(Default::default(), window, cx, |s| {
13919                s.select(selections);
13920            });
13921            this.insert("", window, cx);
13922        });
13923        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13924    }
13925
13926    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13927        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13928        let item = self.cut_common(true, window, cx);
13929        cx.write_to_clipboard(item);
13930    }
13931
13932    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13933        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13934        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13935            s.move_with(&mut |snapshot, sel| {
13936                if sel.is_empty() {
13937                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13938                }
13939                if sel.is_empty() {
13940                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13941                }
13942            });
13943        });
13944        let item = self.cut_common(false, window, cx);
13945        cx.set_global(KillRing(item))
13946    }
13947
13948    pub fn kill_ring_yank(
13949        &mut self,
13950        _: &KillRingYank,
13951        window: &mut Window,
13952        cx: &mut Context<Self>,
13953    ) {
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13955        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13956            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13957                (kill_ring.text().to_string(), kill_ring.metadata_json())
13958            } else {
13959                return;
13960            }
13961        } else {
13962            return;
13963        };
13964        self.do_paste(&text, metadata, false, window, cx);
13965    }
13966
13967    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13968        self.do_copy(true, cx);
13969    }
13970
13971    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13972        self.do_copy(false, cx);
13973    }
13974
13975    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13976        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13977        let buffer = self.buffer.read(cx).read(cx);
13978        let mut text = String::new();
13979        let mut clipboard_selections = Vec::with_capacity(selections.len());
13980
13981        let max_point = buffer.max_point();
13982        let mut is_first = true;
13983        for selection in &selections {
13984            let mut start = selection.start;
13985            let mut end = selection.end;
13986            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13987            let mut add_trailing_newline = false;
13988            if is_entire_line {
13989                start = Point::new(start.row, 0);
13990                let next_line_start = Point::new(end.row + 1, 0);
13991                if next_line_start <= max_point {
13992                    end = next_line_start;
13993                } else {
13994                    // We're on the last line without a trailing newline.
13995                    // Copy to the end of the line and add a newline afterwards.
13996                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13997                    add_trailing_newline = true;
13998                }
13999            }
14000
14001            let mut trimmed_selections = Vec::new();
14002            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
14003                let row = MultiBufferRow(start.row);
14004                let first_indent = buffer.indent_size_for_line(row);
14005                if first_indent.len == 0 || start.column > first_indent.len {
14006                    trimmed_selections.push(start..end);
14007                } else {
14008                    trimmed_selections.push(
14009                        Point::new(row.0, first_indent.len)
14010                            ..Point::new(row.0, buffer.line_len(row)),
14011                    );
14012                    for row in start.row + 1..=end.row {
14013                        let mut line_len = buffer.line_len(MultiBufferRow(row));
14014                        if row == end.row {
14015                            line_len = end.column;
14016                        }
14017                        if line_len == 0 {
14018                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
14019                            continue;
14020                        }
14021                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
14022                        if row_indent_size.len >= first_indent.len {
14023                            trimmed_selections
14024                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
14025                        } else {
14026                            trimmed_selections.clear();
14027                            trimmed_selections.push(start..end);
14028                            break;
14029                        }
14030                    }
14031                }
14032            } else {
14033                trimmed_selections.push(start..end);
14034            }
14035
14036            let is_multiline_trim = trimmed_selections.len() > 1;
14037            let mut selection_len: usize = 0;
14038            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
14039
14040            for trimmed_range in trimmed_selections {
14041                if is_first {
14042                    is_first = false;
14043                } else if is_multiline_trim || !prev_selection_was_entire_line {
14044                    text.push('\n');
14045                    if is_multiline_trim {
14046                        selection_len += 1;
14047                    }
14048                }
14049                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
14050                    text.push_str(chunk);
14051                    selection_len += chunk.len();
14052                }
14053                if add_trailing_newline {
14054                    text.push('\n');
14055                    selection_len += 1;
14056                }
14057            }
14058
14059            clipboard_selections.push(ClipboardSelection::for_buffer(
14060                selection_len,
14061                is_entire_line,
14062                start..end,
14063                &buffer,
14064                self.project.as_ref(),
14065                cx,
14066            ));
14067        }
14068
14069        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
14070            text,
14071            clipboard_selections,
14072        ));
14073    }
14074
14075    pub fn do_paste(
14076        &mut self,
14077        text: &String,
14078        clipboard_selections: Option<Vec<ClipboardSelection>>,
14079        handle_entire_lines: bool,
14080        window: &mut Window,
14081        cx: &mut Context<Self>,
14082    ) {
14083        if self.read_only(cx) {
14084            return;
14085        }
14086
14087        self.finalize_last_transaction(cx);
14088
14089        let clipboard_text = Cow::Borrowed(text.as_str());
14090
14091        self.transact(window, cx, |this, window, cx| {
14092            let had_active_edit_prediction = this.has_active_edit_prediction();
14093            let display_map = this.display_snapshot(cx);
14094            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
14095            let cursor_offset = this
14096                .selections
14097                .last::<MultiBufferOffset>(&display_map)
14098                .head();
14099
14100            if let Some(mut clipboard_selections) = clipboard_selections {
14101                let all_selections_were_entire_line =
14102                    clipboard_selections.iter().all(|s| s.is_entire_line);
14103                let first_selection_indent_column =
14104                    clipboard_selections.first().map(|s| s.first_line_indent);
14105                if clipboard_selections.len() != old_selections.len() {
14106                    clipboard_selections.drain(..);
14107                }
14108                let mut auto_indent_on_paste = true;
14109
14110                this.buffer.update(cx, |buffer, cx| {
14111                    let snapshot = buffer.read(cx);
14112                    auto_indent_on_paste = snapshot
14113                        .language_settings_at(cursor_offset, cx)
14114                        .auto_indent_on_paste;
14115
14116                    let mut start_offset = 0;
14117                    let mut edits = Vec::new();
14118                    let mut original_indent_columns = Vec::new();
14119                    for (ix, selection) in old_selections.iter().enumerate() {
14120                        let to_insert;
14121                        let entire_line;
14122                        let original_indent_column;
14123                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
14124                            let end_offset = start_offset + clipboard_selection.len;
14125                            to_insert = &clipboard_text[start_offset..end_offset];
14126                            entire_line = clipboard_selection.is_entire_line;
14127                            start_offset = if entire_line {
14128                                end_offset
14129                            } else {
14130                                end_offset + 1
14131                            };
14132                            original_indent_column = Some(clipboard_selection.first_line_indent);
14133                        } else {
14134                            to_insert = &*clipboard_text;
14135                            entire_line = all_selections_were_entire_line;
14136                            original_indent_column = first_selection_indent_column
14137                        }
14138
14139                        let (range, to_insert) =
14140                            if selection.is_empty() && handle_entire_lines && entire_line {
14141                                // If the corresponding selection was empty when this slice of the
14142                                // clipboard text was written, then the entire line containing the
14143                                // selection was copied. If this selection is also currently empty,
14144                                // then paste the line before the current line of the buffer.
14145                                let column = selection.start.to_point(&snapshot).column as usize;
14146                                let line_start = selection.start - column;
14147                                (line_start..line_start, Cow::Borrowed(to_insert))
14148                            } else {
14149                                let language = snapshot.language_at(selection.head());
14150                                let range = selection.range();
14151                                if let Some(language) = language
14152                                    && language.name() == "Markdown"
14153                                {
14154                                    edit_for_markdown_paste(
14155                                        &snapshot,
14156                                        range,
14157                                        to_insert,
14158                                        url::Url::parse(to_insert).ok(),
14159                                    )
14160                                } else {
14161                                    (range, Cow::Borrowed(to_insert))
14162                                }
14163                            };
14164
14165                        edits.push((range, to_insert));
14166                        original_indent_columns.push(original_indent_column);
14167                    }
14168                    drop(snapshot);
14169
14170                    buffer.edit(
14171                        edits,
14172                        if auto_indent_on_paste {
14173                            Some(AutoindentMode::Block {
14174                                original_indent_columns,
14175                            })
14176                        } else {
14177                            None
14178                        },
14179                        cx,
14180                    );
14181                });
14182
14183                let selections = this
14184                    .selections
14185                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
14186                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
14187            } else {
14188                let url = url::Url::parse(&clipboard_text).ok();
14189
14190                let auto_indent_mode = if !clipboard_text.is_empty() {
14191                    Some(AutoindentMode::Block {
14192                        original_indent_columns: Vec::new(),
14193                    })
14194                } else {
14195                    None
14196                };
14197
14198                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
14199                    let snapshot = buffer.snapshot(cx);
14200
14201                    let anchors = old_selections
14202                        .iter()
14203                        .map(|s| {
14204                            let anchor = snapshot.anchor_after(s.head());
14205                            s.map(|_| anchor)
14206                        })
14207                        .collect::<Vec<_>>();
14208
14209                    let mut edits = Vec::new();
14210
14211                    // When pasting text without metadata (e.g. copied from an
14212                    // external editor using multiple cursors) and the number of
14213                    // lines matches the number of selections, distribute one
14214                    // line per cursor instead of pasting the whole text at each.
14215                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
14216                    let distribute_lines =
14217                        old_selections.len() > 1 && lines.len() == old_selections.len();
14218
14219                    for (ix, selection) in old_selections.iter().enumerate() {
14220                        let language = snapshot.language_at(selection.head());
14221                        let range = selection.range();
14222
14223                        let text_for_cursor: &str = if distribute_lines {
14224                            lines[ix]
14225                        } else {
14226                            &clipboard_text
14227                        };
14228
14229                        let (edit_range, edit_text) = if let Some(language) = language
14230                            && language.name() == "Markdown"
14231                        {
14232                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
14233                        } else {
14234                            (range, Cow::Borrowed(text_for_cursor))
14235                        };
14236
14237                        edits.push((edit_range, edit_text));
14238                    }
14239
14240                    drop(snapshot);
14241                    buffer.edit(edits, auto_indent_mode, cx);
14242
14243                    anchors
14244                });
14245
14246                this.change_selections(Default::default(), window, cx, |s| {
14247                    s.select_anchors(selection_anchors);
14248                });
14249            }
14250
14251            //   🤔                 |    ..     | show_in_menu |
14252            // | ..                  |   true        true
14253            // | had_edit_prediction |   false       true
14254
14255            let trigger_in_words =
14256                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
14257
14258            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
14259        });
14260    }
14261
14262    pub fn diff_clipboard_with_selection(
14263        &mut self,
14264        _: &DiffClipboardWithSelection,
14265        window: &mut Window,
14266        cx: &mut Context<Self>,
14267    ) {
14268        let selections = self
14269            .selections
14270            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
14271
14272        if selections.is_empty() {
14273            log::warn!("There should always be at least one selection in Zed. This is a bug.");
14274            return;
14275        };
14276
14277        let clipboard_text = cx.read_from_clipboard().and_then(|item| {
14278            item.entries().iter().find_map(|entry| match entry {
14279                ClipboardEntry::String(text) => Some(text.text().to_string()),
14280                _ => None,
14281            })
14282        });
14283
14284        let Some(clipboard_text) = clipboard_text else {
14285            log::warn!("Clipboard doesn't contain text.");
14286            return;
14287        };
14288
14289        window.dispatch_action(
14290            Box::new(DiffClipboardWithSelectionData {
14291                clipboard_text,
14292                editor: cx.entity(),
14293            }),
14294            cx,
14295        );
14296    }
14297
14298    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
14299        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14300        if let Some(item) = cx.read_from_clipboard() {
14301            let clipboard_string = item.entries().iter().find_map(|entry| match entry {
14302                ClipboardEntry::String(s) => Some(s),
14303                _ => None,
14304            });
14305            match clipboard_string {
14306                Some(clipboard_string) => self.do_paste(
14307                    clipboard_string.text(),
14308                    clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
14309                    true,
14310                    window,
14311                    cx,
14312                ),
14313                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
14314            }
14315        }
14316    }
14317
14318    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
14319        if self.read_only(cx) {
14320            return;
14321        }
14322
14323        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14324
14325        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
14326            if let Some((selections, _)) =
14327                self.selection_history.transaction(transaction_id).cloned()
14328            {
14329                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14330                    s.select_anchors(selections.to_vec());
14331                });
14332            } else {
14333                log::error!(
14334                    "No entry in selection_history found for undo. \
14335                     This may correspond to a bug where undo does not update the selection. \
14336                     If this is occurring, please add details to \
14337                     https://github.com/zed-industries/zed/issues/22692"
14338                );
14339            }
14340            self.request_autoscroll(Autoscroll::fit(), cx);
14341            self.unmark_text(window, cx);
14342            self.refresh_edit_prediction(true, false, window, cx);
14343            cx.emit(EditorEvent::Edited { transaction_id });
14344            cx.emit(EditorEvent::TransactionUndone { transaction_id });
14345        }
14346    }
14347
14348    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
14349        if self.read_only(cx) {
14350            return;
14351        }
14352
14353        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14354
14355        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
14356            if let Some((_, Some(selections))) =
14357                self.selection_history.transaction(transaction_id).cloned()
14358            {
14359                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
14360                    s.select_anchors(selections.to_vec());
14361                });
14362            } else {
14363                log::error!(
14364                    "No entry in selection_history found for redo. \
14365                     This may correspond to a bug where undo does not update the selection. \
14366                     If this is occurring, please add details to \
14367                     https://github.com/zed-industries/zed/issues/22692"
14368                );
14369            }
14370            self.request_autoscroll(Autoscroll::fit(), cx);
14371            self.unmark_text(window, cx);
14372            self.refresh_edit_prediction(true, false, window, cx);
14373            cx.emit(EditorEvent::Edited { transaction_id });
14374        }
14375    }
14376
14377    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
14378        self.buffer
14379            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
14380    }
14381
14382    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
14383        self.buffer
14384            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
14385    }
14386
14387    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
14388        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14389        self.change_selections(Default::default(), window, cx, |s| {
14390            s.move_with(&mut |map, selection| {
14391                let cursor = if selection.is_empty() {
14392                    movement::left(map, selection.start)
14393                } else {
14394                    selection.start
14395                };
14396                selection.collapse_to(cursor, SelectionGoal::None);
14397            });
14398        })
14399    }
14400
14401    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14402        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14403        self.change_selections(Default::default(), window, cx, |s| {
14404            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14405        })
14406    }
14407
14408    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14409        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14410        self.change_selections(Default::default(), window, cx, |s| {
14411            s.move_with(&mut |map, selection| {
14412                let cursor = if selection.is_empty() {
14413                    movement::right(map, selection.end)
14414                } else {
14415                    selection.end
14416                };
14417                selection.collapse_to(cursor, SelectionGoal::None)
14418            });
14419        })
14420    }
14421
14422    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14423        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14424        self.change_selections(Default::default(), window, cx, |s| {
14425            s.move_heads_with(&mut |map, head, _| {
14426                (movement::right(map, head), SelectionGoal::None)
14427            });
14428        });
14429    }
14430
14431    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14432        if self.take_rename(true, window, cx).is_some() {
14433            return;
14434        }
14435
14436        if self.mode.is_single_line() {
14437            cx.propagate();
14438            return;
14439        }
14440
14441        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14442
14443        let text_layout_details = &self.text_layout_details(window, cx);
14444        let selection_count = self.selections.count();
14445        let first_selection = self.selections.first_anchor();
14446
14447        self.change_selections(Default::default(), window, cx, |s| {
14448            s.move_with(&mut |map, selection| {
14449                if !selection.is_empty() {
14450                    selection.goal = SelectionGoal::None;
14451                }
14452                let (cursor, goal) = movement::up(
14453                    map,
14454                    selection.start,
14455                    selection.goal,
14456                    false,
14457                    text_layout_details,
14458                );
14459                selection.collapse_to(cursor, goal);
14460            });
14461        });
14462
14463        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14464        {
14465            cx.propagate();
14466        }
14467    }
14468
14469    pub fn move_up_by_lines(
14470        &mut self,
14471        action: &MoveUpByLines,
14472        window: &mut Window,
14473        cx: &mut Context<Self>,
14474    ) {
14475        if self.take_rename(true, window, cx).is_some() {
14476            return;
14477        }
14478
14479        if self.mode.is_single_line() {
14480            cx.propagate();
14481            return;
14482        }
14483
14484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14485
14486        let text_layout_details = &self.text_layout_details(window, cx);
14487
14488        self.change_selections(Default::default(), window, cx, |s| {
14489            s.move_with(&mut |map, selection| {
14490                if !selection.is_empty() {
14491                    selection.goal = SelectionGoal::None;
14492                }
14493                let (cursor, goal) = movement::up_by_rows(
14494                    map,
14495                    selection.start,
14496                    action.lines,
14497                    selection.goal,
14498                    false,
14499                    text_layout_details,
14500                );
14501                selection.collapse_to(cursor, goal);
14502            });
14503        })
14504    }
14505
14506    pub fn move_down_by_lines(
14507        &mut self,
14508        action: &MoveDownByLines,
14509        window: &mut Window,
14510        cx: &mut Context<Self>,
14511    ) {
14512        if self.take_rename(true, window, cx).is_some() {
14513            return;
14514        }
14515
14516        if self.mode.is_single_line() {
14517            cx.propagate();
14518            return;
14519        }
14520
14521        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14522
14523        let text_layout_details = &self.text_layout_details(window, cx);
14524
14525        self.change_selections(Default::default(), window, cx, |s| {
14526            s.move_with(&mut |map, selection| {
14527                if !selection.is_empty() {
14528                    selection.goal = SelectionGoal::None;
14529                }
14530                let (cursor, goal) = movement::down_by_rows(
14531                    map,
14532                    selection.start,
14533                    action.lines,
14534                    selection.goal,
14535                    false,
14536                    text_layout_details,
14537                );
14538                selection.collapse_to(cursor, goal);
14539            });
14540        })
14541    }
14542
14543    pub fn select_down_by_lines(
14544        &mut self,
14545        action: &SelectDownByLines,
14546        window: &mut Window,
14547        cx: &mut Context<Self>,
14548    ) {
14549        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14550        let text_layout_details = &self.text_layout_details(window, cx);
14551        self.change_selections(Default::default(), window, cx, |s| {
14552            s.move_heads_with(&mut |map, head, goal| {
14553                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14554            })
14555        })
14556    }
14557
14558    pub fn select_up_by_lines(
14559        &mut self,
14560        action: &SelectUpByLines,
14561        window: &mut Window,
14562        cx: &mut Context<Self>,
14563    ) {
14564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14565        let text_layout_details = &self.text_layout_details(window, cx);
14566        self.change_selections(Default::default(), window, cx, |s| {
14567            s.move_heads_with(&mut |map, head, goal| {
14568                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14569            })
14570        })
14571    }
14572
14573    pub fn select_page_up(
14574        &mut self,
14575        _: &SelectPageUp,
14576        window: &mut Window,
14577        cx: &mut Context<Self>,
14578    ) {
14579        let Some(row_count) = self.visible_row_count() else {
14580            return;
14581        };
14582
14583        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14584
14585        let text_layout_details = &self.text_layout_details(window, cx);
14586
14587        self.change_selections(Default::default(), window, cx, |s| {
14588            s.move_heads_with(&mut |map, head, goal| {
14589                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14590            })
14591        })
14592    }
14593
14594    pub fn move_page_up(
14595        &mut self,
14596        action: &MovePageUp,
14597        window: &mut Window,
14598        cx: &mut Context<Self>,
14599    ) {
14600        if self.take_rename(true, window, cx).is_some() {
14601            return;
14602        }
14603
14604        if self
14605            .context_menu
14606            .borrow_mut()
14607            .as_mut()
14608            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14609            .unwrap_or(false)
14610        {
14611            return;
14612        }
14613
14614        if matches!(self.mode, EditorMode::SingleLine) {
14615            cx.propagate();
14616            return;
14617        }
14618
14619        let Some(row_count) = self.visible_row_count() else {
14620            return;
14621        };
14622
14623        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14624
14625        let effects = if action.center_cursor {
14626            SelectionEffects::scroll(Autoscroll::center())
14627        } else {
14628            SelectionEffects::default()
14629        };
14630
14631        let text_layout_details = &self.text_layout_details(window, cx);
14632
14633        self.change_selections(effects, window, cx, |s| {
14634            s.move_with(&mut |map, selection| {
14635                if !selection.is_empty() {
14636                    selection.goal = SelectionGoal::None;
14637                }
14638                let (cursor, goal) = movement::up_by_rows(
14639                    map,
14640                    selection.end,
14641                    row_count,
14642                    selection.goal,
14643                    false,
14644                    text_layout_details,
14645                );
14646                selection.collapse_to(cursor, goal);
14647            });
14648        });
14649    }
14650
14651    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14652        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14653        let text_layout_details = &self.text_layout_details(window, cx);
14654        self.change_selections(Default::default(), window, cx, |s| {
14655            s.move_heads_with(&mut |map, head, goal| {
14656                movement::up(map, head, goal, false, text_layout_details)
14657            })
14658        })
14659    }
14660
14661    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14662        self.take_rename(true, window, cx);
14663
14664        if self.mode.is_single_line() {
14665            cx.propagate();
14666            return;
14667        }
14668
14669        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14670
14671        let text_layout_details = &self.text_layout_details(window, cx);
14672        let selection_count = self.selections.count();
14673        let first_selection = self.selections.first_anchor();
14674
14675        self.change_selections(Default::default(), window, cx, |s| {
14676            s.move_with(&mut |map, selection| {
14677                if !selection.is_empty() {
14678                    selection.goal = SelectionGoal::None;
14679                }
14680                let (cursor, goal) = movement::down(
14681                    map,
14682                    selection.end,
14683                    selection.goal,
14684                    false,
14685                    text_layout_details,
14686                );
14687                selection.collapse_to(cursor, goal);
14688            });
14689        });
14690
14691        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14692        {
14693            cx.propagate();
14694        }
14695    }
14696
14697    pub fn select_page_down(
14698        &mut self,
14699        _: &SelectPageDown,
14700        window: &mut Window,
14701        cx: &mut Context<Self>,
14702    ) {
14703        let Some(row_count) = self.visible_row_count() else {
14704            return;
14705        };
14706
14707        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14708
14709        let text_layout_details = &self.text_layout_details(window, cx);
14710
14711        self.change_selections(Default::default(), window, cx, |s| {
14712            s.move_heads_with(&mut |map, head, goal| {
14713                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14714            })
14715        })
14716    }
14717
14718    pub fn move_page_down(
14719        &mut self,
14720        action: &MovePageDown,
14721        window: &mut Window,
14722        cx: &mut Context<Self>,
14723    ) {
14724        if self.take_rename(true, window, cx).is_some() {
14725            return;
14726        }
14727
14728        if self
14729            .context_menu
14730            .borrow_mut()
14731            .as_mut()
14732            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14733            .unwrap_or(false)
14734        {
14735            return;
14736        }
14737
14738        if matches!(self.mode, EditorMode::SingleLine) {
14739            cx.propagate();
14740            return;
14741        }
14742
14743        let Some(row_count) = self.visible_row_count() else {
14744            return;
14745        };
14746
14747        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14748
14749        let effects = if action.center_cursor {
14750            SelectionEffects::scroll(Autoscroll::center())
14751        } else {
14752            SelectionEffects::default()
14753        };
14754
14755        let text_layout_details = &self.text_layout_details(window, cx);
14756        self.change_selections(effects, window, cx, |s| {
14757            s.move_with(&mut |map, selection| {
14758                if !selection.is_empty() {
14759                    selection.goal = SelectionGoal::None;
14760                }
14761                let (cursor, goal) = movement::down_by_rows(
14762                    map,
14763                    selection.end,
14764                    row_count,
14765                    selection.goal,
14766                    false,
14767                    text_layout_details,
14768                );
14769                selection.collapse_to(cursor, goal);
14770            });
14771        });
14772    }
14773
14774    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14775        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14776        let text_layout_details = &self.text_layout_details(window, cx);
14777        self.change_selections(Default::default(), window, cx, |s| {
14778            s.move_heads_with(&mut |map, head, goal| {
14779                movement::down(map, head, goal, false, text_layout_details)
14780            })
14781        });
14782    }
14783
14784    pub fn context_menu_first(
14785        &mut self,
14786        _: &ContextMenuFirst,
14787        window: &mut Window,
14788        cx: &mut Context<Self>,
14789    ) {
14790        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14791            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14792        }
14793    }
14794
14795    pub fn context_menu_prev(
14796        &mut self,
14797        _: &ContextMenuPrevious,
14798        window: &mut Window,
14799        cx: &mut Context<Self>,
14800    ) {
14801        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14802            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14803        }
14804    }
14805
14806    pub fn context_menu_next(
14807        &mut self,
14808        _: &ContextMenuNext,
14809        window: &mut Window,
14810        cx: &mut Context<Self>,
14811    ) {
14812        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14813            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14814        }
14815    }
14816
14817    pub fn context_menu_last(
14818        &mut self,
14819        _: &ContextMenuLast,
14820        window: &mut Window,
14821        cx: &mut Context<Self>,
14822    ) {
14823        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14824            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14825        }
14826    }
14827
14828    pub fn signature_help_prev(
14829        &mut self,
14830        _: &SignatureHelpPrevious,
14831        _: &mut Window,
14832        cx: &mut Context<Self>,
14833    ) {
14834        if let Some(popover) = self.signature_help_state.popover_mut() {
14835            if popover.current_signature == 0 {
14836                popover.current_signature = popover.signatures.len() - 1;
14837            } else {
14838                popover.current_signature -= 1;
14839            }
14840            cx.notify();
14841        }
14842    }
14843
14844    pub fn signature_help_next(
14845        &mut self,
14846        _: &SignatureHelpNext,
14847        _: &mut Window,
14848        cx: &mut Context<Self>,
14849    ) {
14850        if let Some(popover) = self.signature_help_state.popover_mut() {
14851            if popover.current_signature + 1 == popover.signatures.len() {
14852                popover.current_signature = 0;
14853            } else {
14854                popover.current_signature += 1;
14855            }
14856            cx.notify();
14857        }
14858    }
14859
14860    pub fn move_to_previous_word_start(
14861        &mut self,
14862        _: &MoveToPreviousWordStart,
14863        window: &mut Window,
14864        cx: &mut Context<Self>,
14865    ) {
14866        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14867        self.change_selections(Default::default(), window, cx, |s| {
14868            s.move_cursors_with(&mut |map, head, _| {
14869                (
14870                    movement::previous_word_start(map, head),
14871                    SelectionGoal::None,
14872                )
14873            });
14874        })
14875    }
14876
14877    pub fn move_to_previous_subword_start(
14878        &mut self,
14879        _: &MoveToPreviousSubwordStart,
14880        window: &mut Window,
14881        cx: &mut Context<Self>,
14882    ) {
14883        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14884        self.change_selections(Default::default(), window, cx, |s| {
14885            s.move_cursors_with(&mut |map, head, _| {
14886                (
14887                    movement::previous_subword_start(map, head),
14888                    SelectionGoal::None,
14889                )
14890            });
14891        })
14892    }
14893
14894    pub fn select_to_previous_word_start(
14895        &mut self,
14896        _: &SelectToPreviousWordStart,
14897        window: &mut Window,
14898        cx: &mut Context<Self>,
14899    ) {
14900        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14901        self.change_selections(Default::default(), window, cx, |s| {
14902            s.move_heads_with(&mut |map, head, _| {
14903                (
14904                    movement::previous_word_start(map, head),
14905                    SelectionGoal::None,
14906                )
14907            });
14908        })
14909    }
14910
14911    pub fn select_to_previous_subword_start(
14912        &mut self,
14913        _: &SelectToPreviousSubwordStart,
14914        window: &mut Window,
14915        cx: &mut Context<Self>,
14916    ) {
14917        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14918        self.change_selections(Default::default(), window, cx, |s| {
14919            s.move_heads_with(&mut |map, head, _| {
14920                (
14921                    movement::previous_subword_start(map, head),
14922                    SelectionGoal::None,
14923                )
14924            });
14925        })
14926    }
14927
14928    pub fn delete_to_previous_word_start(
14929        &mut self,
14930        action: &DeleteToPreviousWordStart,
14931        window: &mut Window,
14932        cx: &mut Context<Self>,
14933    ) {
14934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14935        self.transact(window, cx, |this, window, cx| {
14936            this.select_autoclose_pair(window, cx);
14937            this.change_selections(Default::default(), window, cx, |s| {
14938                s.move_with(&mut |map, selection| {
14939                    if selection.is_empty() {
14940                        let mut cursor = if action.ignore_newlines {
14941                            movement::previous_word_start(map, selection.head())
14942                        } else {
14943                            movement::previous_word_start_or_newline(map, selection.head())
14944                        };
14945                        cursor = movement::adjust_greedy_deletion(
14946                            map,
14947                            selection.head(),
14948                            cursor,
14949                            action.ignore_brackets,
14950                        );
14951                        selection.set_head(cursor, SelectionGoal::None);
14952                    }
14953                });
14954            });
14955            this.insert("", window, cx);
14956        });
14957    }
14958
14959    pub fn delete_to_previous_subword_start(
14960        &mut self,
14961        action: &DeleteToPreviousSubwordStart,
14962        window: &mut Window,
14963        cx: &mut Context<Self>,
14964    ) {
14965        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14966        self.transact(window, cx, |this, window, cx| {
14967            this.select_autoclose_pair(window, cx);
14968            this.change_selections(Default::default(), window, cx, |s| {
14969                s.move_with(&mut |map, selection| {
14970                    if selection.is_empty() {
14971                        let mut cursor = if action.ignore_newlines {
14972                            movement::previous_subword_start(map, selection.head())
14973                        } else {
14974                            movement::previous_subword_start_or_newline(map, selection.head())
14975                        };
14976                        cursor = movement::adjust_greedy_deletion(
14977                            map,
14978                            selection.head(),
14979                            cursor,
14980                            action.ignore_brackets,
14981                        );
14982                        selection.set_head(cursor, SelectionGoal::None);
14983                    }
14984                });
14985            });
14986            this.insert("", window, cx);
14987        });
14988    }
14989
14990    pub fn move_to_next_word_end(
14991        &mut self,
14992        _: &MoveToNextWordEnd,
14993        window: &mut Window,
14994        cx: &mut Context<Self>,
14995    ) {
14996        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14997        self.change_selections(Default::default(), window, cx, |s| {
14998            s.move_cursors_with(&mut |map, head, _| {
14999                (movement::next_word_end(map, head), SelectionGoal::None)
15000            });
15001        })
15002    }
15003
15004    pub fn move_to_next_subword_end(
15005        &mut self,
15006        _: &MoveToNextSubwordEnd,
15007        window: &mut Window,
15008        cx: &mut Context<Self>,
15009    ) {
15010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15011        self.change_selections(Default::default(), window, cx, |s| {
15012            s.move_cursors_with(&mut |map, head, _| {
15013                (movement::next_subword_end(map, head), SelectionGoal::None)
15014            });
15015        })
15016    }
15017
15018    pub fn select_to_next_word_end(
15019        &mut self,
15020        _: &SelectToNextWordEnd,
15021        window: &mut Window,
15022        cx: &mut Context<Self>,
15023    ) {
15024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15025        self.change_selections(Default::default(), window, cx, |s| {
15026            s.move_heads_with(&mut |map, head, _| {
15027                (movement::next_word_end(map, head), SelectionGoal::None)
15028            });
15029        })
15030    }
15031
15032    pub fn select_to_next_subword_end(
15033        &mut self,
15034        _: &SelectToNextSubwordEnd,
15035        window: &mut Window,
15036        cx: &mut Context<Self>,
15037    ) {
15038        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15039        self.change_selections(Default::default(), window, cx, |s| {
15040            s.move_heads_with(&mut |map, head, _| {
15041                (movement::next_subword_end(map, head), SelectionGoal::None)
15042            });
15043        })
15044    }
15045
15046    pub fn delete_to_next_word_end(
15047        &mut self,
15048        action: &DeleteToNextWordEnd,
15049        window: &mut Window,
15050        cx: &mut Context<Self>,
15051    ) {
15052        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15053        self.transact(window, cx, |this, window, cx| {
15054            this.change_selections(Default::default(), window, cx, |s| {
15055                s.move_with(&mut |map, selection| {
15056                    if selection.is_empty() {
15057                        let mut cursor = if action.ignore_newlines {
15058                            movement::next_word_end(map, selection.head())
15059                        } else {
15060                            movement::next_word_end_or_newline(map, selection.head())
15061                        };
15062                        cursor = movement::adjust_greedy_deletion(
15063                            map,
15064                            selection.head(),
15065                            cursor,
15066                            action.ignore_brackets,
15067                        );
15068                        selection.set_head(cursor, SelectionGoal::None);
15069                    }
15070                });
15071            });
15072            this.insert("", window, cx);
15073        });
15074    }
15075
15076    pub fn delete_to_next_subword_end(
15077        &mut self,
15078        action: &DeleteToNextSubwordEnd,
15079        window: &mut Window,
15080        cx: &mut Context<Self>,
15081    ) {
15082        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15083        self.transact(window, cx, |this, window, cx| {
15084            this.change_selections(Default::default(), window, cx, |s| {
15085                s.move_with(&mut |map, selection| {
15086                    if selection.is_empty() {
15087                        let mut cursor = if action.ignore_newlines {
15088                            movement::next_subword_end(map, selection.head())
15089                        } else {
15090                            movement::next_subword_end_or_newline(map, selection.head())
15091                        };
15092                        cursor = movement::adjust_greedy_deletion(
15093                            map,
15094                            selection.head(),
15095                            cursor,
15096                            action.ignore_brackets,
15097                        );
15098                        selection.set_head(cursor, SelectionGoal::None);
15099                    }
15100                });
15101            });
15102            this.insert("", window, cx);
15103        });
15104    }
15105
15106    pub fn move_to_beginning_of_line(
15107        &mut self,
15108        action: &MoveToBeginningOfLine,
15109        window: &mut Window,
15110        cx: &mut Context<Self>,
15111    ) {
15112        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15113        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15114        self.change_selections(Default::default(), window, cx, |s| {
15115            s.move_cursors_with(&mut |map, head, _| {
15116                (
15117                    movement::indented_line_beginning(
15118                        map,
15119                        head,
15120                        action.stop_at_soft_wraps,
15121                        stop_at_indent,
15122                    ),
15123                    SelectionGoal::None,
15124                )
15125            });
15126        })
15127    }
15128
15129    pub fn select_to_beginning_of_line(
15130        &mut self,
15131        action: &SelectToBeginningOfLine,
15132        window: &mut Window,
15133        cx: &mut Context<Self>,
15134    ) {
15135        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
15136        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15137        self.change_selections(Default::default(), window, cx, |s| {
15138            s.move_heads_with(&mut |map, head, _| {
15139                (
15140                    movement::indented_line_beginning(
15141                        map,
15142                        head,
15143                        action.stop_at_soft_wraps,
15144                        stop_at_indent,
15145                    ),
15146                    SelectionGoal::None,
15147                )
15148            });
15149        });
15150    }
15151
15152    pub fn delete_to_beginning_of_line(
15153        &mut self,
15154        action: &DeleteToBeginningOfLine,
15155        window: &mut Window,
15156        cx: &mut Context<Self>,
15157    ) {
15158        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15159        self.transact(window, cx, |this, window, cx| {
15160            this.change_selections(Default::default(), window, cx, |s| {
15161                s.move_with(&mut |_, selection| {
15162                    selection.reversed = true;
15163                });
15164            });
15165
15166            this.select_to_beginning_of_line(
15167                &SelectToBeginningOfLine {
15168                    stop_at_soft_wraps: false,
15169                    stop_at_indent: action.stop_at_indent,
15170                },
15171                window,
15172                cx,
15173            );
15174            this.backspace(&Backspace, window, cx);
15175        });
15176    }
15177
15178    pub fn move_to_end_of_line(
15179        &mut self,
15180        action: &MoveToEndOfLine,
15181        window: &mut Window,
15182        cx: &mut Context<Self>,
15183    ) {
15184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15185        self.change_selections(Default::default(), window, cx, |s| {
15186            s.move_cursors_with(&mut |map, head, _| {
15187                (
15188                    movement::line_end(map, head, action.stop_at_soft_wraps),
15189                    SelectionGoal::None,
15190                )
15191            });
15192        })
15193    }
15194
15195    pub fn select_to_end_of_line(
15196        &mut self,
15197        action: &SelectToEndOfLine,
15198        window: &mut Window,
15199        cx: &mut Context<Self>,
15200    ) {
15201        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15202        self.change_selections(Default::default(), window, cx, |s| {
15203            s.move_heads_with(&mut |map, head, _| {
15204                (
15205                    movement::line_end(map, head, action.stop_at_soft_wraps),
15206                    SelectionGoal::None,
15207                )
15208            });
15209        })
15210    }
15211
15212    pub fn delete_to_end_of_line(
15213        &mut self,
15214        _: &DeleteToEndOfLine,
15215        window: &mut Window,
15216        cx: &mut Context<Self>,
15217    ) {
15218        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15219        self.transact(window, cx, |this, window, cx| {
15220            this.select_to_end_of_line(
15221                &SelectToEndOfLine {
15222                    stop_at_soft_wraps: false,
15223                },
15224                window,
15225                cx,
15226            );
15227            this.delete(&Delete, window, cx);
15228        });
15229    }
15230
15231    pub fn cut_to_end_of_line(
15232        &mut self,
15233        action: &CutToEndOfLine,
15234        window: &mut Window,
15235        cx: &mut Context<Self>,
15236    ) {
15237        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15238        self.transact(window, cx, |this, window, cx| {
15239            this.select_to_end_of_line(
15240                &SelectToEndOfLine {
15241                    stop_at_soft_wraps: false,
15242                },
15243                window,
15244                cx,
15245            );
15246            if !action.stop_at_newlines {
15247                this.change_selections(Default::default(), window, cx, |s| {
15248                    s.move_with(&mut |_, sel| {
15249                        if sel.is_empty() {
15250                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
15251                        }
15252                    });
15253                });
15254            }
15255            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
15256            let item = this.cut_common(false, window, cx);
15257            cx.write_to_clipboard(item);
15258        });
15259    }
15260
15261    pub fn move_to_start_of_paragraph(
15262        &mut self,
15263        _: &MoveToStartOfParagraph,
15264        window: &mut Window,
15265        cx: &mut Context<Self>,
15266    ) {
15267        if matches!(self.mode, EditorMode::SingleLine) {
15268            cx.propagate();
15269            return;
15270        }
15271        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15272        self.change_selections(Default::default(), window, cx, |s| {
15273            s.move_with(&mut |map, selection| {
15274                selection.collapse_to(
15275                    movement::start_of_paragraph(map, selection.head(), 1),
15276                    SelectionGoal::None,
15277                )
15278            });
15279        })
15280    }
15281
15282    pub fn move_to_end_of_paragraph(
15283        &mut self,
15284        _: &MoveToEndOfParagraph,
15285        window: &mut Window,
15286        cx: &mut Context<Self>,
15287    ) {
15288        if matches!(self.mode, EditorMode::SingleLine) {
15289            cx.propagate();
15290            return;
15291        }
15292        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15293        self.change_selections(Default::default(), window, cx, |s| {
15294            s.move_with(&mut |map, selection| {
15295                selection.collapse_to(
15296                    movement::end_of_paragraph(map, selection.head(), 1),
15297                    SelectionGoal::None,
15298                )
15299            });
15300        })
15301    }
15302
15303    pub fn select_to_start_of_paragraph(
15304        &mut self,
15305        _: &SelectToStartOfParagraph,
15306        window: &mut Window,
15307        cx: &mut Context<Self>,
15308    ) {
15309        if matches!(self.mode, EditorMode::SingleLine) {
15310            cx.propagate();
15311            return;
15312        }
15313        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15314        self.change_selections(Default::default(), window, cx, |s| {
15315            s.move_heads_with(&mut |map, head, _| {
15316                (
15317                    movement::start_of_paragraph(map, head, 1),
15318                    SelectionGoal::None,
15319                )
15320            });
15321        })
15322    }
15323
15324    pub fn select_to_end_of_paragraph(
15325        &mut self,
15326        _: &SelectToEndOfParagraph,
15327        window: &mut Window,
15328        cx: &mut Context<Self>,
15329    ) {
15330        if matches!(self.mode, EditorMode::SingleLine) {
15331            cx.propagate();
15332            return;
15333        }
15334        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15335        self.change_selections(Default::default(), window, cx, |s| {
15336            s.move_heads_with(&mut |map, head, _| {
15337                (
15338                    movement::end_of_paragraph(map, head, 1),
15339                    SelectionGoal::None,
15340                )
15341            });
15342        })
15343    }
15344
15345    pub fn move_to_start_of_excerpt(
15346        &mut self,
15347        _: &MoveToStartOfExcerpt,
15348        window: &mut Window,
15349        cx: &mut Context<Self>,
15350    ) {
15351        if matches!(self.mode, EditorMode::SingleLine) {
15352            cx.propagate();
15353            return;
15354        }
15355        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15356        self.change_selections(Default::default(), window, cx, |s| {
15357            s.move_with(&mut |map, selection| {
15358                selection.collapse_to(
15359                    movement::start_of_excerpt(
15360                        map,
15361                        selection.head(),
15362                        workspace::searchable::Direction::Prev,
15363                    ),
15364                    SelectionGoal::None,
15365                )
15366            });
15367        })
15368    }
15369
15370    pub fn move_to_start_of_next_excerpt(
15371        &mut self,
15372        _: &MoveToStartOfNextExcerpt,
15373        window: &mut Window,
15374        cx: &mut Context<Self>,
15375    ) {
15376        if matches!(self.mode, EditorMode::SingleLine) {
15377            cx.propagate();
15378            return;
15379        }
15380
15381        self.change_selections(Default::default(), window, cx, |s| {
15382            s.move_with(&mut |map, selection| {
15383                selection.collapse_to(
15384                    movement::start_of_excerpt(
15385                        map,
15386                        selection.head(),
15387                        workspace::searchable::Direction::Next,
15388                    ),
15389                    SelectionGoal::None,
15390                )
15391            });
15392        })
15393    }
15394
15395    pub fn move_to_end_of_excerpt(
15396        &mut self,
15397        _: &MoveToEndOfExcerpt,
15398        window: &mut Window,
15399        cx: &mut Context<Self>,
15400    ) {
15401        if matches!(self.mode, EditorMode::SingleLine) {
15402            cx.propagate();
15403            return;
15404        }
15405        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15406        self.change_selections(Default::default(), window, cx, |s| {
15407            s.move_with(&mut |map, selection| {
15408                selection.collapse_to(
15409                    movement::end_of_excerpt(
15410                        map,
15411                        selection.head(),
15412                        workspace::searchable::Direction::Next,
15413                    ),
15414                    SelectionGoal::None,
15415                )
15416            });
15417        })
15418    }
15419
15420    pub fn move_to_end_of_previous_excerpt(
15421        &mut self,
15422        _: &MoveToEndOfPreviousExcerpt,
15423        window: &mut Window,
15424        cx: &mut Context<Self>,
15425    ) {
15426        if matches!(self.mode, EditorMode::SingleLine) {
15427            cx.propagate();
15428            return;
15429        }
15430        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15431        self.change_selections(Default::default(), window, cx, |s| {
15432            s.move_with(&mut |map, selection| {
15433                selection.collapse_to(
15434                    movement::end_of_excerpt(
15435                        map,
15436                        selection.head(),
15437                        workspace::searchable::Direction::Prev,
15438                    ),
15439                    SelectionGoal::None,
15440                )
15441            });
15442        })
15443    }
15444
15445    pub fn select_to_start_of_excerpt(
15446        &mut self,
15447        _: &SelectToStartOfExcerpt,
15448        window: &mut Window,
15449        cx: &mut Context<Self>,
15450    ) {
15451        if matches!(self.mode, EditorMode::SingleLine) {
15452            cx.propagate();
15453            return;
15454        }
15455        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15456        self.change_selections(Default::default(), window, cx, |s| {
15457            s.move_heads_with(&mut |map, head, _| {
15458                (
15459                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15460                    SelectionGoal::None,
15461                )
15462            });
15463        })
15464    }
15465
15466    pub fn select_to_start_of_next_excerpt(
15467        &mut self,
15468        _: &SelectToStartOfNextExcerpt,
15469        window: &mut Window,
15470        cx: &mut Context<Self>,
15471    ) {
15472        if matches!(self.mode, EditorMode::SingleLine) {
15473            cx.propagate();
15474            return;
15475        }
15476        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15477        self.change_selections(Default::default(), window, cx, |s| {
15478            s.move_heads_with(&mut |map, head, _| {
15479                (
15480                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15481                    SelectionGoal::None,
15482                )
15483            });
15484        })
15485    }
15486
15487    pub fn select_to_end_of_excerpt(
15488        &mut self,
15489        _: &SelectToEndOfExcerpt,
15490        window: &mut Window,
15491        cx: &mut Context<Self>,
15492    ) {
15493        if matches!(self.mode, EditorMode::SingleLine) {
15494            cx.propagate();
15495            return;
15496        }
15497        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15498        self.change_selections(Default::default(), window, cx, |s| {
15499            s.move_heads_with(&mut |map, head, _| {
15500                (
15501                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15502                    SelectionGoal::None,
15503                )
15504            });
15505        })
15506    }
15507
15508    pub fn select_to_end_of_previous_excerpt(
15509        &mut self,
15510        _: &SelectToEndOfPreviousExcerpt,
15511        window: &mut Window,
15512        cx: &mut Context<Self>,
15513    ) {
15514        if matches!(self.mode, EditorMode::SingleLine) {
15515            cx.propagate();
15516            return;
15517        }
15518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15519        self.change_selections(Default::default(), window, cx, |s| {
15520            s.move_heads_with(&mut |map, head, _| {
15521                (
15522                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15523                    SelectionGoal::None,
15524                )
15525            });
15526        })
15527    }
15528
15529    pub fn move_to_beginning(
15530        &mut self,
15531        _: &MoveToBeginning,
15532        window: &mut Window,
15533        cx: &mut Context<Self>,
15534    ) {
15535        if matches!(self.mode, EditorMode::SingleLine) {
15536            cx.propagate();
15537            return;
15538        }
15539        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15540        self.change_selections(Default::default(), window, cx, |s| {
15541            s.select_ranges(vec![Anchor::Min..Anchor::Min]);
15542        });
15543    }
15544
15545    pub fn select_to_beginning(
15546        &mut self,
15547        _: &SelectToBeginning,
15548        window: &mut Window,
15549        cx: &mut Context<Self>,
15550    ) {
15551        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15552        selection.set_head(Point::zero(), SelectionGoal::None);
15553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15554        self.change_selections(Default::default(), window, cx, |s| {
15555            s.select(vec![selection]);
15556        });
15557    }
15558
15559    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15560        if matches!(self.mode, EditorMode::SingleLine) {
15561            cx.propagate();
15562            return;
15563        }
15564        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15565        let cursor = self.buffer.read(cx).read(cx).len();
15566        self.change_selections(Default::default(), window, cx, |s| {
15567            s.select_ranges(vec![cursor..cursor])
15568        });
15569    }
15570
15571    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15572        self.nav_history = nav_history;
15573    }
15574
15575    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15576        self.nav_history.as_ref()
15577    }
15578
15579    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15580        self.push_to_nav_history(
15581            self.selections.newest_anchor().head(),
15582            None,
15583            false,
15584            true,
15585            cx,
15586        );
15587    }
15588
15589    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15590        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15591        let buffer = self.buffer.read(cx).read(cx);
15592        let cursor_position = cursor_anchor.to_point(&buffer);
15593        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15594        let scroll_top_row = scroll_anchor.top_row(&buffer);
15595        drop(buffer);
15596
15597        NavigationData {
15598            cursor_anchor,
15599            cursor_position,
15600            scroll_anchor,
15601            scroll_top_row,
15602        }
15603    }
15604
15605    fn navigation_entry(
15606        &self,
15607        cursor_anchor: Anchor,
15608        cx: &mut Context<Self>,
15609    ) -> Option<NavigationEntry> {
15610        let Some(history) = self.nav_history.clone() else {
15611            return None;
15612        };
15613        let data = self.navigation_data(cursor_anchor, cx);
15614        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15615    }
15616
15617    fn push_to_nav_history(
15618        &mut self,
15619        cursor_anchor: Anchor,
15620        new_position: Option<Point>,
15621        is_deactivate: bool,
15622        always: bool,
15623        cx: &mut Context<Self>,
15624    ) {
15625        let data = self.navigation_data(cursor_anchor, cx);
15626        if let Some(nav_history) = self.nav_history.as_mut() {
15627            if let Some(new_position) = new_position {
15628                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15629                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15630                    return;
15631                }
15632            }
15633
15634            let cursor_row = data.cursor_position.row;
15635            nav_history.push(Some(data), Some(cursor_row), cx);
15636            cx.emit(EditorEvent::PushedToNavHistory {
15637                anchor: cursor_anchor,
15638                is_deactivate,
15639            })
15640        }
15641    }
15642
15643    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15644        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15645        let buffer = self.buffer.read(cx).snapshot(cx);
15646        let mut selection = self
15647            .selections
15648            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15649        selection.set_head(buffer.len(), SelectionGoal::None);
15650        self.change_selections(Default::default(), window, cx, |s| {
15651            s.select(vec![selection]);
15652        });
15653    }
15654
15655    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15656        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15657        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15658            s.select_ranges(vec![Anchor::Min..Anchor::Max]);
15659        });
15660    }
15661
15662    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15663        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15664        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15665        let mut selections = self.selections.all::<Point>(&display_map);
15666        let max_point = display_map.buffer_snapshot().max_point();
15667        for selection in &mut selections {
15668            let rows = selection.spanned_rows(true, &display_map);
15669            selection.start = Point::new(rows.start.0, 0);
15670            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15671            selection.reversed = false;
15672        }
15673        self.change_selections(Default::default(), window, cx, |s| {
15674            s.select(selections);
15675        });
15676    }
15677
15678    pub fn split_selection_into_lines(
15679        &mut self,
15680        action: &SplitSelectionIntoLines,
15681        window: &mut Window,
15682        cx: &mut Context<Self>,
15683    ) {
15684        let selections = self
15685            .selections
15686            .all::<Point>(&self.display_snapshot(cx))
15687            .into_iter()
15688            .map(|selection| selection.start..selection.end)
15689            .collect::<Vec<_>>();
15690        self.unfold_ranges(&selections, true, false, cx);
15691
15692        let mut new_selection_ranges = Vec::new();
15693        {
15694            let buffer = self.buffer.read(cx).read(cx);
15695            for selection in selections {
15696                for row in selection.start.row..selection.end.row {
15697                    let line_start = Point::new(row, 0);
15698                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15699
15700                    if action.keep_selections {
15701                        // Keep the selection range for each line
15702                        let selection_start = if row == selection.start.row {
15703                            selection.start
15704                        } else {
15705                            line_start
15706                        };
15707                        new_selection_ranges.push(selection_start..line_end);
15708                    } else {
15709                        // Collapse to cursor at end of line
15710                        new_selection_ranges.push(line_end..line_end);
15711                    }
15712                }
15713
15714                let is_multiline_selection = selection.start.row != selection.end.row;
15715                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15716                // so this action feels more ergonomic when paired with other selection operations
15717                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15718                if !should_skip_last {
15719                    if action.keep_selections {
15720                        if is_multiline_selection {
15721                            let line_start = Point::new(selection.end.row, 0);
15722                            new_selection_ranges.push(line_start..selection.end);
15723                        } else {
15724                            new_selection_ranges.push(selection.start..selection.end);
15725                        }
15726                    } else {
15727                        new_selection_ranges.push(selection.end..selection.end);
15728                    }
15729                }
15730            }
15731        }
15732        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15733            s.select_ranges(new_selection_ranges);
15734        });
15735    }
15736
15737    pub fn add_selection_above(
15738        &mut self,
15739        action: &AddSelectionAbove,
15740        window: &mut Window,
15741        cx: &mut Context<Self>,
15742    ) {
15743        self.add_selection(true, action.skip_soft_wrap, window, cx);
15744    }
15745
15746    pub fn add_selection_below(
15747        &mut self,
15748        action: &AddSelectionBelow,
15749        window: &mut Window,
15750        cx: &mut Context<Self>,
15751    ) {
15752        self.add_selection(false, action.skip_soft_wrap, window, cx);
15753    }
15754
15755    fn add_selection(
15756        &mut self,
15757        above: bool,
15758        skip_soft_wrap: bool,
15759        window: &mut Window,
15760        cx: &mut Context<Self>,
15761    ) {
15762        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15763
15764        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15765        let all_selections = self.selections.all::<Point>(&display_map);
15766        let text_layout_details = self.text_layout_details(window, cx);
15767
15768        let (mut columnar_selections, new_selections_to_columnarize) = {
15769            if let Some(state) = self.add_selections_state.as_ref() {
15770                let columnar_selection_ids: HashSet<_> = state
15771                    .groups
15772                    .iter()
15773                    .flat_map(|group| group.stack.iter())
15774                    .copied()
15775                    .collect();
15776
15777                all_selections
15778                    .into_iter()
15779                    .partition(|s| columnar_selection_ids.contains(&s.id))
15780            } else {
15781                (Vec::new(), all_selections)
15782            }
15783        };
15784
15785        let mut state = self
15786            .add_selections_state
15787            .take()
15788            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15789
15790        for selection in new_selections_to_columnarize {
15791            let range = selection.display_range(&display_map).sorted();
15792            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15793            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15794            let positions = start_x.min(end_x)..start_x.max(end_x);
15795            let mut stack = Vec::new();
15796            for row in range.start.row().0..=range.end.row().0 {
15797                if let Some(selection) = self.selections.build_columnar_selection(
15798                    &display_map,
15799                    DisplayRow(row),
15800                    &positions,
15801                    selection.reversed,
15802                    &text_layout_details,
15803                ) {
15804                    stack.push(selection.id);
15805                    columnar_selections.push(selection);
15806                }
15807            }
15808            if !stack.is_empty() {
15809                if above {
15810                    stack.reverse();
15811                }
15812                state.groups.push(AddSelectionsGroup { above, stack });
15813            }
15814        }
15815
15816        let mut final_selections = Vec::new();
15817        let end_row = if above {
15818            DisplayRow(0)
15819        } else {
15820            display_map.max_point().row()
15821        };
15822
15823        // When `skip_soft_wrap` is true, we use UTF-16 columns instead of pixel
15824        // positions to place new selections, so we need to keep track of the
15825        // column range of the oldest selection in each group, because
15826        // intermediate selections may have been clamped to shorter lines.
15827        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15828            let mut map = HashMap::default();
15829            for group in state.groups.iter() {
15830                if let Some(oldest_id) = group.stack.first() {
15831                    if let Some(oldest_selection) =
15832                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15833                    {
15834                        let snapshot = display_map.buffer_snapshot();
15835                        let start_col =
15836                            snapshot.point_to_point_utf16(oldest_selection.start).column;
15837                        let end_col = snapshot.point_to_point_utf16(oldest_selection.end).column;
15838                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15839                        for id in &group.stack {
15840                            map.insert(*id, goal_columns.clone());
15841                        }
15842                    }
15843                }
15844            }
15845            map
15846        } else {
15847            HashMap::default()
15848        };
15849
15850        let mut last_added_item_per_group = HashMap::default();
15851        for group in state.groups.iter_mut() {
15852            if let Some(last_id) = group.stack.last() {
15853                last_added_item_per_group.insert(*last_id, group);
15854            }
15855        }
15856
15857        for selection in columnar_selections {
15858            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15859                if above == group.above {
15860                    let range = selection.display_range(&display_map).sorted();
15861                    debug_assert_eq!(range.start.row(), range.end.row());
15862                    let row = range.start.row();
15863                    let positions =
15864                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15865                            Pixels::from(start)..Pixels::from(end)
15866                        } else {
15867                            let start_x =
15868                                display_map.x_for_display_point(range.start, &text_layout_details);
15869                            let end_x =
15870                                display_map.x_for_display_point(range.end, &text_layout_details);
15871                            start_x.min(end_x)..start_x.max(end_x)
15872                        };
15873
15874                    let maybe_new_selection = if skip_soft_wrap {
15875                        let goal_columns = goal_columns_by_selection_id
15876                            .remove(&selection.id)
15877                            .unwrap_or_else(|| {
15878                                let snapshot = display_map.buffer_snapshot();
15879                                let start_col =
15880                                    snapshot.point_to_point_utf16(selection.start).column;
15881                                let end_col = snapshot.point_to_point_utf16(selection.end).column;
15882                                start_col.min(end_col)..start_col.max(end_col)
15883                            });
15884                        self.selections.find_next_columnar_selection_by_buffer_row(
15885                            &display_map,
15886                            row,
15887                            end_row,
15888                            above,
15889                            &goal_columns,
15890                            selection.reversed,
15891                            &text_layout_details,
15892                        )
15893                    } else {
15894                        self.selections.find_next_columnar_selection_by_display_row(
15895                            &display_map,
15896                            row,
15897                            end_row,
15898                            above,
15899                            &positions,
15900                            selection.reversed,
15901                            &text_layout_details,
15902                        )
15903                    };
15904
15905                    if let Some(new_selection) = maybe_new_selection {
15906                        group.stack.push(new_selection.id);
15907                        if above {
15908                            final_selections.push(new_selection);
15909                            final_selections.push(selection);
15910                        } else {
15911                            final_selections.push(selection);
15912                            final_selections.push(new_selection);
15913                        }
15914                    } else {
15915                        final_selections.push(selection);
15916                    }
15917                } else {
15918                    group.stack.pop();
15919                }
15920            } else {
15921                final_selections.push(selection);
15922            }
15923        }
15924
15925        self.change_selections(Default::default(), window, cx, |s| {
15926            s.select(final_selections);
15927        });
15928
15929        let final_selection_ids: HashSet<_> = self
15930            .selections
15931            .all::<Point>(&display_map)
15932            .iter()
15933            .map(|s| s.id)
15934            .collect();
15935        state.groups.retain_mut(|group| {
15936            // selections might get merged above so we remove invalid items from stacks
15937            group.stack.retain(|id| final_selection_ids.contains(id));
15938
15939            // single selection in stack can be treated as initial state
15940            group.stack.len() > 1
15941        });
15942
15943        if !state.groups.is_empty() {
15944            self.add_selections_state = Some(state);
15945        }
15946    }
15947
15948    pub fn insert_snippet_at_selections(
15949        &mut self,
15950        action: &InsertSnippet,
15951        window: &mut Window,
15952        cx: &mut Context<Self>,
15953    ) {
15954        self.try_insert_snippet_at_selections(action, window, cx)
15955            .log_err();
15956    }
15957
15958    fn try_insert_snippet_at_selections(
15959        &mut self,
15960        action: &InsertSnippet,
15961        window: &mut Window,
15962        cx: &mut Context<Self>,
15963    ) -> Result<()> {
15964        let insertion_ranges = self
15965            .selections
15966            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15967            .into_iter()
15968            .map(|selection| selection.range())
15969            .collect_vec();
15970
15971        let snippet = if let Some(snippet_body) = &action.snippet {
15972            if action.language.is_none() && action.name.is_none() {
15973                Snippet::parse(snippet_body)?
15974            } else {
15975                bail!("`snippet` is mutually exclusive with `language` and `name`")
15976            }
15977        } else if let Some(name) = &action.name {
15978            let project = self.project().context("no project")?;
15979            let snippet_store = project.read(cx).snippets().read(cx);
15980            let snippet = snippet_store
15981                .snippets_for(action.language.clone(), cx)
15982                .into_iter()
15983                .find(|snippet| snippet.name == *name)
15984                .context("snippet not found")?;
15985            Snippet::parse(&snippet.body)?
15986        } else {
15987            // todo(andrew): open modal to select snippet
15988            bail!("`name` or `snippet` is required")
15989        };
15990
15991        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15992    }
15993
15994    fn select_match_ranges(
15995        &mut self,
15996        range: Range<MultiBufferOffset>,
15997        reversed: bool,
15998        replace_newest: bool,
15999        auto_scroll: Option<Autoscroll>,
16000        window: &mut Window,
16001        cx: &mut Context<Editor>,
16002    ) {
16003        self.unfold_ranges(
16004            std::slice::from_ref(&range),
16005            false,
16006            auto_scroll.is_some(),
16007            cx,
16008        );
16009        let effects = if let Some(scroll) = auto_scroll {
16010            SelectionEffects::scroll(scroll)
16011        } else {
16012            SelectionEffects::no_scroll()
16013        };
16014        self.change_selections(effects, window, cx, |s| {
16015            if replace_newest {
16016                s.delete(s.newest_anchor().id);
16017            }
16018            if reversed {
16019                s.insert_range(range.end..range.start);
16020            } else {
16021                s.insert_range(range);
16022            }
16023        });
16024    }
16025
16026    pub fn select_next_match_internal(
16027        &mut self,
16028        display_map: &DisplaySnapshot,
16029        replace_newest: bool,
16030        autoscroll: Option<Autoscroll>,
16031        window: &mut Window,
16032        cx: &mut Context<Self>,
16033    ) -> Result<()> {
16034        let buffer = display_map.buffer_snapshot();
16035        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16036        if let Some(mut select_next_state) = self.select_next_state.take() {
16037            let query = &select_next_state.query;
16038            if !select_next_state.done {
16039                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16040                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16041                let mut next_selected_range = None;
16042
16043                let bytes_after_last_selection =
16044                    buffer.bytes_in_range(last_selection.end..buffer.len());
16045                let bytes_before_first_selection =
16046                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
16047                let query_matches = query
16048                    .stream_find_iter(bytes_after_last_selection)
16049                    .map(|result| (last_selection.end, result))
16050                    .chain(
16051                        query
16052                            .stream_find_iter(bytes_before_first_selection)
16053                            .map(|result| (MultiBufferOffset(0), result)),
16054                    );
16055
16056                for (start_offset, query_match) in query_matches {
16057                    let query_match = query_match.unwrap(); // can only fail due to I/O
16058                    let offset_range =
16059                        start_offset + query_match.start()..start_offset + query_match.end();
16060
16061                    if !select_next_state.wordwise
16062                        || (!buffer.is_inside_word(offset_range.start, None)
16063                            && !buffer.is_inside_word(offset_range.end, None))
16064                    {
16065                        let idx = selections
16066                            .partition_point(|selection| selection.end <= offset_range.start);
16067                        let overlaps = selections
16068                            .get(idx)
16069                            .map_or(false, |selection| selection.start < offset_range.end);
16070
16071                        if !overlaps {
16072                            next_selected_range = Some(offset_range);
16073                            break;
16074                        }
16075                    }
16076                }
16077
16078                if let Some(next_selected_range) = next_selected_range {
16079                    self.select_match_ranges(
16080                        next_selected_range,
16081                        last_selection.reversed,
16082                        replace_newest,
16083                        autoscroll,
16084                        window,
16085                        cx,
16086                    );
16087                } else {
16088                    select_next_state.done = true;
16089                }
16090            }
16091
16092            self.select_next_state = Some(select_next_state);
16093        } else {
16094            let mut only_carets = true;
16095            let mut same_text_selected = true;
16096            let mut selected_text = None;
16097
16098            let mut selections_iter = selections.iter().peekable();
16099            while let Some(selection) = selections_iter.next() {
16100                if selection.start != selection.end {
16101                    only_carets = false;
16102                }
16103
16104                if same_text_selected {
16105                    if selected_text.is_none() {
16106                        selected_text =
16107                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16108                    }
16109
16110                    if let Some(next_selection) = selections_iter.peek() {
16111                        if next_selection.len() == selection.len() {
16112                            let next_selected_text = buffer
16113                                .text_for_range(next_selection.range())
16114                                .collect::<String>();
16115                            if Some(next_selected_text) != selected_text {
16116                                same_text_selected = false;
16117                                selected_text = None;
16118                            }
16119                        } else {
16120                            same_text_selected = false;
16121                            selected_text = None;
16122                        }
16123                    }
16124                }
16125            }
16126
16127            if only_carets {
16128                for selection in &mut selections {
16129                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16130                    selection.start = word_range.start;
16131                    selection.end = word_range.end;
16132                    selection.goal = SelectionGoal::None;
16133                    selection.reversed = false;
16134                    self.select_match_ranges(
16135                        selection.start..selection.end,
16136                        selection.reversed,
16137                        replace_newest,
16138                        autoscroll,
16139                        window,
16140                        cx,
16141                    );
16142                }
16143
16144                if selections.len() == 1 {
16145                    let selection = selections
16146                        .last()
16147                        .expect("ensured that there's only one selection");
16148                    let query = buffer
16149                        .text_for_range(selection.start..selection.end)
16150                        .collect::<String>();
16151                    let is_empty = query.is_empty();
16152                    let select_state = SelectNextState {
16153                        query: self.build_query(&[query], cx)?,
16154                        wordwise: true,
16155                        done: is_empty,
16156                    };
16157                    self.select_next_state = Some(select_state);
16158                } else {
16159                    self.select_next_state = None;
16160                }
16161            } else if let Some(selected_text) = selected_text {
16162                self.select_next_state = Some(SelectNextState {
16163                    query: self.build_query(&[selected_text], cx)?,
16164                    wordwise: false,
16165                    done: false,
16166                });
16167                self.select_next_match_internal(
16168                    display_map,
16169                    replace_newest,
16170                    autoscroll,
16171                    window,
16172                    cx,
16173                )?;
16174            }
16175        }
16176        Ok(())
16177    }
16178
16179    pub fn select_all_matches(
16180        &mut self,
16181        _action: &SelectAllMatches,
16182        window: &mut Window,
16183        cx: &mut Context<Self>,
16184    ) -> Result<()> {
16185        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16186
16187        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16188
16189        self.select_next_match_internal(&display_map, false, None, window, cx)?;
16190        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
16191        else {
16192            return Ok(());
16193        };
16194
16195        let mut new_selections = Vec::new();
16196        let initial_selection = self.selections.oldest::<MultiBufferOffset>(&display_map);
16197        let reversed = initial_selection.reversed;
16198        let buffer = display_map.buffer_snapshot();
16199        let query_matches = select_next_state
16200            .query
16201            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
16202
16203        for query_match in query_matches.into_iter() {
16204            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
16205            let offset_range = if reversed {
16206                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
16207            } else {
16208                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
16209            };
16210
16211            let is_partial_word_match = select_next_state.wordwise
16212                && (buffer.is_inside_word(offset_range.start, None)
16213                    || buffer.is_inside_word(offset_range.end, None));
16214
16215            let is_initial_selection = MultiBufferOffset(query_match.start())
16216                == initial_selection.start
16217                && MultiBufferOffset(query_match.end()) == initial_selection.end;
16218
16219            if !is_partial_word_match && !is_initial_selection {
16220                new_selections.push(offset_range);
16221            }
16222        }
16223
16224        // Ensure that the initial range is the last selection, as
16225        // `MutableSelectionsCollection::select_ranges` makes the last selection
16226        // the newest selection, which the editor then relies on as the primary
16227        // cursor for scroll targeting. Without this, the last match would then
16228        // be automatically focused when the user started editing the selected
16229        // matches.
16230        let initial_directed_range = if reversed {
16231            initial_selection.end..initial_selection.start
16232        } else {
16233            initial_selection.start..initial_selection.end
16234        };
16235        new_selections.push(initial_directed_range);
16236
16237        select_next_state.done = true;
16238        self.unfold_ranges(&new_selections, false, false, cx);
16239        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
16240            selections.select_ranges(new_selections)
16241        });
16242
16243        Ok(())
16244    }
16245
16246    pub fn select_next(
16247        &mut self,
16248        action: &SelectNext,
16249        window: &mut Window,
16250        cx: &mut Context<Self>,
16251    ) -> Result<()> {
16252        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16253        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16254        self.select_next_match_internal(
16255            &display_map,
16256            action.replace_newest,
16257            Some(Autoscroll::newest()),
16258            window,
16259            cx,
16260        )
16261    }
16262
16263    pub fn select_previous(
16264        &mut self,
16265        action: &SelectPrevious,
16266        window: &mut Window,
16267        cx: &mut Context<Self>,
16268    ) -> Result<()> {
16269        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16270        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16271        let buffer = display_map.buffer_snapshot();
16272        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
16273        if let Some(mut select_prev_state) = self.select_prev_state.take() {
16274            let query = &select_prev_state.query;
16275            if !select_prev_state.done {
16276                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
16277                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
16278                let mut next_selected_range = None;
16279                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
16280                let bytes_before_last_selection =
16281                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
16282                let bytes_after_first_selection =
16283                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
16284                let query_matches = query
16285                    .stream_find_iter(bytes_before_last_selection)
16286                    .map(|result| (last_selection.start, result))
16287                    .chain(
16288                        query
16289                            .stream_find_iter(bytes_after_first_selection)
16290                            .map(|result| (buffer.len(), result)),
16291                    );
16292                for (end_offset, query_match) in query_matches {
16293                    let query_match = query_match.unwrap(); // can only fail due to I/O
16294                    let offset_range =
16295                        end_offset - query_match.end()..end_offset - query_match.start();
16296
16297                    if !select_prev_state.wordwise
16298                        || (!buffer.is_inside_word(offset_range.start, None)
16299                            && !buffer.is_inside_word(offset_range.end, None))
16300                    {
16301                        next_selected_range = Some(offset_range);
16302                        break;
16303                    }
16304                }
16305
16306                if let Some(next_selected_range) = next_selected_range {
16307                    self.select_match_ranges(
16308                        next_selected_range,
16309                        last_selection.reversed,
16310                        action.replace_newest,
16311                        Some(Autoscroll::newest()),
16312                        window,
16313                        cx,
16314                    );
16315                } else {
16316                    select_prev_state.done = true;
16317                }
16318            }
16319
16320            self.select_prev_state = Some(select_prev_state);
16321        } else {
16322            let mut only_carets = true;
16323            let mut same_text_selected = true;
16324            let mut selected_text = None;
16325
16326            let mut selections_iter = selections.iter().peekable();
16327            while let Some(selection) = selections_iter.next() {
16328                if selection.start != selection.end {
16329                    only_carets = false;
16330                }
16331
16332                if same_text_selected {
16333                    if selected_text.is_none() {
16334                        selected_text =
16335                            Some(buffer.text_for_range(selection.range()).collect::<String>());
16336                    }
16337
16338                    if let Some(next_selection) = selections_iter.peek() {
16339                        if next_selection.len() == selection.len() {
16340                            let next_selected_text = buffer
16341                                .text_for_range(next_selection.range())
16342                                .collect::<String>();
16343                            if Some(next_selected_text) != selected_text {
16344                                same_text_selected = false;
16345                                selected_text = None;
16346                            }
16347                        } else {
16348                            same_text_selected = false;
16349                            selected_text = None;
16350                        }
16351                    }
16352                }
16353            }
16354
16355            if only_carets {
16356                for selection in &mut selections {
16357                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
16358                    selection.start = word_range.start;
16359                    selection.end = word_range.end;
16360                    selection.goal = SelectionGoal::None;
16361                    selection.reversed = false;
16362                    self.select_match_ranges(
16363                        selection.start..selection.end,
16364                        selection.reversed,
16365                        action.replace_newest,
16366                        Some(Autoscroll::newest()),
16367                        window,
16368                        cx,
16369                    );
16370                }
16371                if selections.len() == 1 {
16372                    let selection = selections
16373                        .last()
16374                        .expect("ensured that there's only one selection");
16375                    let query = buffer
16376                        .text_for_range(selection.start..selection.end)
16377                        .collect::<String>();
16378                    let is_empty = query.is_empty();
16379                    let select_state = SelectNextState {
16380                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
16381                        wordwise: true,
16382                        done: is_empty,
16383                    };
16384                    self.select_prev_state = Some(select_state);
16385                } else {
16386                    self.select_prev_state = None;
16387                }
16388            } else if let Some(selected_text) = selected_text {
16389                self.select_prev_state = Some(SelectNextState {
16390                    query: self
16391                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
16392                    wordwise: false,
16393                    done: false,
16394                });
16395                self.select_previous(action, window, cx)?;
16396            }
16397        }
16398        Ok(())
16399    }
16400
16401    /// Builds an `AhoCorasick` automaton from the provided patterns, while
16402    /// setting the case sensitivity based on the global
16403    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
16404    /// editor's settings.
16405    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
16406    where
16407        I: IntoIterator<Item = P>,
16408        P: AsRef<[u8]>,
16409    {
16410        let case_sensitive = self
16411            .select_next_is_case_sensitive
16412            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16413
16414        let mut builder = AhoCorasickBuilder::new();
16415        builder.ascii_case_insensitive(!case_sensitive);
16416        builder.build(patterns)
16417    }
16418
16419    pub fn find_next_match(
16420        &mut self,
16421        _: &FindNextMatch,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) -> Result<()> {
16425        let selections = self.selections.disjoint_anchors_arc();
16426        match selections.first() {
16427            Some(first) if selections.len() >= 2 => {
16428                self.change_selections(Default::default(), window, cx, |s| {
16429                    s.select_ranges([first.range()]);
16430                });
16431            }
16432            _ => self.select_next(
16433                &SelectNext {
16434                    replace_newest: true,
16435                },
16436                window,
16437                cx,
16438            )?,
16439        }
16440        Ok(())
16441    }
16442
16443    pub fn find_previous_match(
16444        &mut self,
16445        _: &FindPreviousMatch,
16446        window: &mut Window,
16447        cx: &mut Context<Self>,
16448    ) -> Result<()> {
16449        let selections = self.selections.disjoint_anchors_arc();
16450        match selections.last() {
16451            Some(last) if selections.len() >= 2 => {
16452                self.change_selections(Default::default(), window, cx, |s| {
16453                    s.select_ranges([last.range()]);
16454                });
16455            }
16456            _ => self.select_previous(
16457                &SelectPrevious {
16458                    replace_newest: true,
16459                },
16460                window,
16461                cx,
16462            )?,
16463        }
16464        Ok(())
16465    }
16466
16467    pub fn toggle_block_comments(
16468        &mut self,
16469        _: &ToggleBlockComments,
16470        window: &mut Window,
16471        cx: &mut Context<Self>,
16472    ) {
16473        if self.read_only(cx) {
16474            return;
16475        }
16476        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16477        self.transact(window, cx, |this, _window, cx| {
16478            let mut selections = this
16479                .selections
16480                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16481            let mut edits = Vec::new();
16482            let snapshot = this.buffer.read(cx).read(cx);
16483            let empty_str: Arc<str> = Arc::default();
16484            let mut markers_inserted = Vec::new();
16485
16486            for selection in &mut selections {
16487                let start_point = selection.start;
16488                let end_point = selection.end;
16489
16490                let Some(language) =
16491                    snapshot.language_scope_at(Point::new(start_point.row, start_point.column))
16492                else {
16493                    continue;
16494                };
16495
16496                let Some(BlockCommentConfig {
16497                    start: comment_start,
16498                    end: comment_end,
16499                    ..
16500                }) = language.block_comment()
16501                else {
16502                    continue;
16503                };
16504
16505                let prefix_needle = comment_start.trim_end().as_bytes();
16506                let suffix_needle = comment_end.trim_start().as_bytes();
16507
16508                // Collect full lines spanning the selection as the search region
16509                let region_start = Point::new(start_point.row, 0);
16510                let region_end = Point::new(
16511                    end_point.row,
16512                    snapshot.line_len(MultiBufferRow(end_point.row)),
16513                );
16514                let region_bytes: Vec<u8> = snapshot
16515                    .bytes_in_range(region_start..region_end)
16516                    .flatten()
16517                    .copied()
16518                    .collect();
16519
16520                let region_start_offset = snapshot.point_to_offset(region_start);
16521                let start_byte = snapshot.point_to_offset(start_point) - region_start_offset;
16522                let end_byte = snapshot.point_to_offset(end_point) - region_start_offset;
16523
16524                let mut is_commented = false;
16525                let mut prefix_range = start_point..start_point;
16526                let mut suffix_range = end_point..end_point;
16527
16528                // Find rightmost /* at or before the selection end
16529                if let Some(prefix_pos) = region_bytes[..end_byte.min(region_bytes.len())]
16530                    .windows(prefix_needle.len())
16531                    .rposition(|w| w == prefix_needle)
16532                {
16533                    let after_prefix = prefix_pos + prefix_needle.len();
16534
16535                    // Find the first */ after that /*
16536                    if let Some(suffix_pos) = region_bytes[after_prefix..]
16537                        .windows(suffix_needle.len())
16538                        .position(|w| w == suffix_needle)
16539                        .map(|p| p + after_prefix)
16540                    {
16541                        let suffix_end = suffix_pos + suffix_needle.len();
16542
16543                        // Case 1: /* ... */ surrounds the selection
16544                        let markers_surround = prefix_pos <= start_byte
16545                            && suffix_end >= end_byte
16546                            && start_byte < suffix_end;
16547
16548                        // Case 2: selection contains /* ... */ (only whitespace padding)
16549                        let selection_contains = start_byte <= prefix_pos
16550                            && suffix_end <= end_byte
16551                            && region_bytes[start_byte..prefix_pos]
16552                                .iter()
16553                                .all(|&b| b.is_ascii_whitespace())
16554                            && region_bytes[suffix_end..end_byte]
16555                                .iter()
16556                                .all(|&b| b.is_ascii_whitespace());
16557
16558                        if markers_surround || selection_contains {
16559                            is_commented = true;
16560                            let prefix_pt =
16561                                snapshot.offset_to_point(region_start_offset + prefix_pos);
16562                            let suffix_pt =
16563                                snapshot.offset_to_point(region_start_offset + suffix_pos);
16564                            prefix_range = prefix_pt
16565                                ..Point::new(
16566                                    prefix_pt.row,
16567                                    prefix_pt.column + prefix_needle.len() as u32,
16568                                );
16569                            suffix_range = suffix_pt
16570                                ..Point::new(
16571                                    suffix_pt.row,
16572                                    suffix_pt.column + suffix_needle.len() as u32,
16573                                );
16574                        }
16575                    }
16576                }
16577
16578                if is_commented {
16579                    // Also remove the space after /* and before */
16580                    if snapshot
16581                        .bytes_in_range(prefix_range.end..snapshot.max_point())
16582                        .flatten()
16583                        .next()
16584                        == Some(&b' ')
16585                    {
16586                        prefix_range.end.column += 1;
16587                    }
16588                    if suffix_range.start.column > 0 {
16589                        let before =
16590                            Point::new(suffix_range.start.row, suffix_range.start.column - 1);
16591                        if snapshot
16592                            .bytes_in_range(before..suffix_range.start)
16593                            .flatten()
16594                            .next()
16595                            == Some(&b' ')
16596                        {
16597                            suffix_range.start.column -= 1;
16598                        }
16599                    }
16600
16601                    edits.push((prefix_range, empty_str.clone()));
16602                    edits.push((suffix_range, empty_str.clone()));
16603                } else {
16604                    let prefix: Arc<str> = if comment_start.ends_with(' ') {
16605                        comment_start.clone()
16606                    } else {
16607                        format!("{} ", comment_start).into()
16608                    };
16609                    let suffix: Arc<str> = if comment_end.starts_with(' ') {
16610                        comment_end.clone()
16611                    } else {
16612                        format!(" {}", comment_end).into()
16613                    };
16614
16615                    edits.push((start_point..start_point, prefix.clone()));
16616                    edits.push((end_point..end_point, suffix.clone()));
16617                    markers_inserted.push((
16618                        selection.id,
16619                        prefix.len(),
16620                        suffix.len(),
16621                        selection.is_empty(),
16622                        end_point.row,
16623                    ));
16624                }
16625            }
16626
16627            drop(snapshot);
16628            this.buffer.update(cx, |buffer, cx| {
16629                buffer.edit(edits, None, cx);
16630            });
16631
16632            let mut selections = this
16633                .selections
16634                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16635            for selection in &mut selections {
16636                if let Some((_, prefix_len, suffix_len, was_empty, suffix_row)) = markers_inserted
16637                    .iter()
16638                    .find(|(id, _, _, _, _)| *id == selection.id)
16639                {
16640                    if *was_empty {
16641                        selection.start.column = selection
16642                            .start
16643                            .column
16644                            .saturating_sub((*prefix_len + *suffix_len) as u32);
16645                    } else {
16646                        selection.start.column =
16647                            selection.start.column.saturating_sub(*prefix_len as u32);
16648                        if selection.end.row == *suffix_row {
16649                            selection.end.column += *suffix_len as u32;
16650                        }
16651                    }
16652                }
16653            }
16654            this.change_selections(Default::default(), _window, cx, |s| s.select(selections));
16655        });
16656    }
16657
16658    pub fn toggle_comments(
16659        &mut self,
16660        action: &ToggleComments,
16661        window: &mut Window,
16662        cx: &mut Context<Self>,
16663    ) {
16664        if self.read_only(cx) {
16665            return;
16666        }
16667        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16668        let text_layout_details = &self.text_layout_details(window, cx);
16669        self.transact(window, cx, |this, window, cx| {
16670            let mut selections = this
16671                .selections
16672                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16673            let mut edits = Vec::new();
16674            let mut selection_edit_ranges = Vec::new();
16675            let mut last_toggled_row = None;
16676            let snapshot = this.buffer.read(cx).read(cx);
16677            let empty_str: Arc<str> = Arc::default();
16678            let mut suffixes_inserted = Vec::new();
16679            let ignore_indent = action.ignore_indent;
16680
16681            fn comment_prefix_range(
16682                snapshot: &MultiBufferSnapshot,
16683                row: MultiBufferRow,
16684                comment_prefix: &str,
16685                comment_prefix_whitespace: &str,
16686                ignore_indent: bool,
16687            ) -> Range<Point> {
16688                let indent_size = if ignore_indent {
16689                    0
16690                } else {
16691                    snapshot.indent_size_for_line(row).len
16692                };
16693
16694                let start = Point::new(row.0, indent_size);
16695
16696                let mut line_bytes = snapshot
16697                    .bytes_in_range(start..snapshot.max_point())
16698                    .flatten()
16699                    .copied();
16700
16701                // If this line currently begins with the line comment prefix, then record
16702                // the range containing the prefix.
16703                if line_bytes
16704                    .by_ref()
16705                    .take(comment_prefix.len())
16706                    .eq(comment_prefix.bytes())
16707                {
16708                    // Include any whitespace that matches the comment prefix.
16709                    let matching_whitespace_len = line_bytes
16710                        .zip(comment_prefix_whitespace.bytes())
16711                        .take_while(|(a, b)| a == b)
16712                        .count() as u32;
16713                    let end = Point::new(
16714                        start.row,
16715                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16716                    );
16717                    start..end
16718                } else {
16719                    start..start
16720                }
16721            }
16722
16723            fn comment_suffix_range(
16724                snapshot: &MultiBufferSnapshot,
16725                row: MultiBufferRow,
16726                comment_suffix: &str,
16727                comment_suffix_has_leading_space: bool,
16728            ) -> Range<Point> {
16729                let end = Point::new(row.0, snapshot.line_len(row));
16730                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16731
16732                let mut line_end_bytes = snapshot
16733                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16734                    .flatten()
16735                    .copied();
16736
16737                let leading_space_len = if suffix_start_column > 0
16738                    && line_end_bytes.next() == Some(b' ')
16739                    && comment_suffix_has_leading_space
16740                {
16741                    1
16742                } else {
16743                    0
16744                };
16745
16746                // If this line currently begins with the line comment prefix, then record
16747                // the range containing the prefix.
16748                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16749                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16750                    start..end
16751                } else {
16752                    end..end
16753                }
16754            }
16755
16756            // TODO: Handle selections that cross excerpts
16757            for selection in &mut selections {
16758                let start_column = snapshot
16759                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16760                    .len;
16761                let language = if let Some(language) =
16762                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16763                {
16764                    language
16765                } else {
16766                    continue;
16767                };
16768
16769                selection_edit_ranges.clear();
16770
16771                // If multiple selections contain a given row, avoid processing that
16772                // row more than once.
16773                let mut start_row = MultiBufferRow(selection.start.row);
16774                if last_toggled_row == Some(start_row) {
16775                    start_row = start_row.next_row();
16776                }
16777                let end_row =
16778                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16779                        MultiBufferRow(selection.end.row - 1)
16780                    } else {
16781                        MultiBufferRow(selection.end.row)
16782                    };
16783                last_toggled_row = Some(end_row);
16784
16785                if start_row > end_row {
16786                    continue;
16787                }
16788
16789                // If the language has line comments, toggle those.
16790                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16791
16792                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16793                if ignore_indent {
16794                    full_comment_prefixes = full_comment_prefixes
16795                        .into_iter()
16796                        .map(|s| Arc::from(s.trim_end()))
16797                        .collect();
16798                }
16799
16800                if !full_comment_prefixes.is_empty() {
16801                    let first_prefix = full_comment_prefixes
16802                        .first()
16803                        .expect("prefixes is non-empty");
16804                    let prefix_trimmed_lengths = full_comment_prefixes
16805                        .iter()
16806                        .map(|p| p.trim_end_matches(' ').len())
16807                        .collect::<SmallVec<[usize; 4]>>();
16808
16809                    let mut all_selection_lines_are_comments = true;
16810
16811                    for row in start_row.0..=end_row.0 {
16812                        let row = MultiBufferRow(row);
16813                        if start_row < end_row && snapshot.is_line_blank(row) {
16814                            continue;
16815                        }
16816
16817                        let prefix_range = full_comment_prefixes
16818                            .iter()
16819                            .zip(prefix_trimmed_lengths.iter().copied())
16820                            .map(|(prefix, trimmed_prefix_len)| {
16821                                comment_prefix_range(
16822                                    snapshot.deref(),
16823                                    row,
16824                                    &prefix[..trimmed_prefix_len],
16825                                    &prefix[trimmed_prefix_len..],
16826                                    ignore_indent,
16827                                )
16828                            })
16829                            .max_by_key(|range| range.end.column - range.start.column)
16830                            .expect("prefixes is non-empty");
16831
16832                        if prefix_range.is_empty() {
16833                            all_selection_lines_are_comments = false;
16834                        }
16835
16836                        selection_edit_ranges.push(prefix_range);
16837                    }
16838
16839                    if all_selection_lines_are_comments {
16840                        edits.extend(
16841                            selection_edit_ranges
16842                                .iter()
16843                                .cloned()
16844                                .map(|range| (range, empty_str.clone())),
16845                        );
16846                    } else {
16847                        let min_column = selection_edit_ranges
16848                            .iter()
16849                            .map(|range| range.start.column)
16850                            .min()
16851                            .unwrap_or(0);
16852                        edits.extend(selection_edit_ranges.iter().map(|range| {
16853                            let position = Point::new(range.start.row, min_column);
16854                            (position..position, first_prefix.clone())
16855                        }));
16856                    }
16857                } else if let Some(BlockCommentConfig {
16858                    start: full_comment_prefix,
16859                    end: comment_suffix,
16860                    ..
16861                }) = language.block_comment()
16862                {
16863                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16864                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16865                    let prefix_range = comment_prefix_range(
16866                        snapshot.deref(),
16867                        start_row,
16868                        comment_prefix,
16869                        comment_prefix_whitespace,
16870                        ignore_indent,
16871                    );
16872                    let suffix_range = comment_suffix_range(
16873                        snapshot.deref(),
16874                        end_row,
16875                        comment_suffix.trim_start_matches(' '),
16876                        comment_suffix.starts_with(' '),
16877                    );
16878
16879                    if prefix_range.is_empty() || suffix_range.is_empty() {
16880                        edits.push((
16881                            prefix_range.start..prefix_range.start,
16882                            full_comment_prefix.clone(),
16883                        ));
16884                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16885                        suffixes_inserted.push((end_row, comment_suffix.len()));
16886                    } else {
16887                        edits.push((prefix_range, empty_str.clone()));
16888                        edits.push((suffix_range, empty_str.clone()));
16889                    }
16890                } else {
16891                    continue;
16892                }
16893            }
16894
16895            drop(snapshot);
16896            this.buffer.update(cx, |buffer, cx| {
16897                buffer.edit(edits, None, cx);
16898            });
16899
16900            // Adjust selections so that they end before any comment suffixes that
16901            // were inserted.
16902            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16903            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16904            let snapshot = this.buffer.read(cx).read(cx);
16905            for selection in &mut selections {
16906                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16907                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16908                        Ordering::Less => {
16909                            suffixes_inserted.next();
16910                            continue;
16911                        }
16912                        Ordering::Greater => break,
16913                        Ordering::Equal => {
16914                            if selection.end.column == snapshot.line_len(row) {
16915                                if selection.is_empty() {
16916                                    selection.start.column -= suffix_len as u32;
16917                                }
16918                                selection.end.column -= suffix_len as u32;
16919                            }
16920                            break;
16921                        }
16922                    }
16923                }
16924            }
16925
16926            drop(snapshot);
16927            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16928
16929            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16930            let selections_on_single_row = selections.windows(2).all(|selections| {
16931                selections[0].start.row == selections[1].start.row
16932                    && selections[0].end.row == selections[1].end.row
16933                    && selections[0].start.row == selections[0].end.row
16934            });
16935            let selections_selecting = selections
16936                .iter()
16937                .any(|selection| selection.start != selection.end);
16938            let advance_downwards = action.advance_downwards
16939                && selections_on_single_row
16940                && !selections_selecting
16941                && !matches!(this.mode, EditorMode::SingleLine);
16942
16943            if advance_downwards {
16944                let snapshot = this.buffer.read(cx).snapshot(cx);
16945
16946                this.change_selections(Default::default(), window, cx, |s| {
16947                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16948                        let mut point = display_point.to_point(display_snapshot);
16949                        point.row += 1;
16950                        point = snapshot.clip_point(point, Bias::Left);
16951                        let display_point = point.to_display_point(display_snapshot);
16952                        let goal = SelectionGoal::HorizontalPosition(
16953                            display_snapshot
16954                                .x_for_display_point(display_point, text_layout_details)
16955                                .into(),
16956                        );
16957                        (display_point, goal)
16958                    })
16959                });
16960            }
16961        });
16962    }
16963
16964    pub fn select_enclosing_symbol(
16965        &mut self,
16966        _: &SelectEnclosingSymbol,
16967        window: &mut Window,
16968        cx: &mut Context<Self>,
16969    ) {
16970        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16971
16972        let buffer = self.buffer.read(cx).snapshot(cx);
16973        let old_selections = self
16974            .selections
16975            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16976            .into_boxed_slice();
16977
16978        fn update_selection(
16979            selection: &Selection<MultiBufferOffset>,
16980            buffer_snap: &MultiBufferSnapshot,
16981        ) -> Option<Selection<MultiBufferOffset>> {
16982            let cursor = selection.head();
16983            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16984            for symbol in symbols.iter().rev() {
16985                let start = symbol.range.start.to_offset(buffer_snap);
16986                let end = symbol.range.end.to_offset(buffer_snap);
16987                let new_range = start..end;
16988                if start < selection.start || end > selection.end {
16989                    return Some(Selection {
16990                        id: selection.id,
16991                        start: new_range.start,
16992                        end: new_range.end,
16993                        goal: SelectionGoal::None,
16994                        reversed: selection.reversed,
16995                    });
16996                }
16997            }
16998            None
16999        }
17000
17001        let mut selected_larger_symbol = false;
17002        let new_selections = old_selections
17003            .iter()
17004            .map(|selection| match update_selection(selection, &buffer) {
17005                Some(new_selection) => {
17006                    if new_selection.range() != selection.range() {
17007                        selected_larger_symbol = true;
17008                    }
17009                    new_selection
17010                }
17011                None => selection.clone(),
17012            })
17013            .collect::<Vec<_>>();
17014
17015        if selected_larger_symbol {
17016            self.change_selections(Default::default(), window, cx, |s| {
17017                s.select(new_selections);
17018            });
17019        }
17020    }
17021
17022    pub fn select_larger_syntax_node(
17023        &mut self,
17024        _: &SelectLargerSyntaxNode,
17025        window: &mut Window,
17026        cx: &mut Context<Self>,
17027    ) {
17028        let Some(visible_row_count) = self.visible_row_count() else {
17029            return;
17030        };
17031        let old_selections: Box<[_]> = self
17032            .selections
17033            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17034            .into();
17035        if old_selections.is_empty() {
17036            return;
17037        }
17038
17039        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17040
17041        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17042        let buffer = self.buffer.read(cx).snapshot(cx);
17043
17044        let mut selected_larger_node = false;
17045        let mut new_selections = old_selections
17046            .iter()
17047            .map(|selection| {
17048                let old_range = selection.start..selection.end;
17049
17050                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
17051                    // manually select word at selection
17052                    if ["string_content", "inline"].contains(&node.kind()) {
17053                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
17054                        // ignore if word is already selected
17055                        if !word_range.is_empty() && old_range != word_range {
17056                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
17057                            // only select word if start and end point belongs to same word
17058                            if word_range == last_word_range {
17059                                selected_larger_node = true;
17060                                return Selection {
17061                                    id: selection.id,
17062                                    start: word_range.start,
17063                                    end: word_range.end,
17064                                    goal: SelectionGoal::None,
17065                                    reversed: selection.reversed,
17066                                };
17067                            }
17068                        }
17069                    }
17070                }
17071
17072                let mut new_range = old_range.clone();
17073                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
17074                    new_range = range;
17075                    if !node.is_named() {
17076                        continue;
17077                    }
17078                    if !display_map.intersects_fold(new_range.start)
17079                        && !display_map.intersects_fold(new_range.end)
17080                    {
17081                        break;
17082                    }
17083                }
17084
17085                selected_larger_node |= new_range != old_range;
17086                Selection {
17087                    id: selection.id,
17088                    start: new_range.start,
17089                    end: new_range.end,
17090                    goal: SelectionGoal::None,
17091                    reversed: selection.reversed,
17092                }
17093            })
17094            .collect::<Vec<_>>();
17095
17096        if !selected_larger_node {
17097            return; // don't put this call in the history
17098        }
17099
17100        // scroll based on transformation done to the last selection created by the user
17101        let (last_old, last_new) = old_selections
17102            .last()
17103            .zip(new_selections.last().cloned())
17104            .expect("old_selections isn't empty");
17105
17106        let is_selection_reversed = if new_selections.len() == 1 {
17107            let should_be_reversed = last_old.start != last_new.start;
17108            new_selections.last_mut().expect("checked above").reversed = should_be_reversed;
17109            should_be_reversed
17110        } else {
17111            last_new.reversed
17112        };
17113
17114        if selected_larger_node {
17115            self.select_syntax_node_history.disable_clearing = true;
17116            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17117                s.select(new_selections.clone());
17118            });
17119            self.select_syntax_node_history.disable_clearing = false;
17120        }
17121
17122        let start_row = last_new.start.to_display_point(&display_map).row().0;
17123        let end_row = last_new.end.to_display_point(&display_map).row().0;
17124        let selection_height = end_row - start_row + 1;
17125        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
17126
17127        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
17128        let scroll_behavior = if fits_on_the_screen {
17129            self.request_autoscroll(Autoscroll::fit(), cx);
17130            SelectSyntaxNodeScrollBehavior::FitSelection
17131        } else if is_selection_reversed {
17132            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
17133            SelectSyntaxNodeScrollBehavior::CursorTop
17134        } else {
17135            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
17136            SelectSyntaxNodeScrollBehavior::CursorBottom
17137        };
17138
17139        let old_selections: Box<[Selection<Anchor>]> = old_selections
17140            .iter()
17141            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
17142            .collect();
17143        self.select_syntax_node_history.push((
17144            old_selections,
17145            scroll_behavior,
17146            is_selection_reversed,
17147        ));
17148    }
17149
17150    pub fn select_smaller_syntax_node(
17151        &mut self,
17152        _: &SelectSmallerSyntaxNode,
17153        window: &mut Window,
17154        cx: &mut Context<Self>,
17155    ) {
17156        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17157
17158        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
17159            self.select_syntax_node_history.pop()
17160        {
17161            if let Some(selection) = selections.last_mut() {
17162                selection.reversed = is_selection_reversed;
17163            }
17164
17165            let snapshot = self.buffer.read(cx).snapshot(cx);
17166            let selections: Vec<Selection<MultiBufferOffset>> = selections
17167                .iter()
17168                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
17169                .collect();
17170
17171            self.select_syntax_node_history.disable_clearing = true;
17172            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
17173                s.select(selections);
17174            });
17175            self.select_syntax_node_history.disable_clearing = false;
17176
17177            match scroll_behavior {
17178                SelectSyntaxNodeScrollBehavior::CursorTop => {
17179                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
17180                }
17181                SelectSyntaxNodeScrollBehavior::FitSelection => {
17182                    self.request_autoscroll(Autoscroll::fit(), cx);
17183                }
17184                SelectSyntaxNodeScrollBehavior::CursorBottom => {
17185                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
17186                }
17187            }
17188        }
17189    }
17190
17191    pub fn unwrap_syntax_node(
17192        &mut self,
17193        _: &UnwrapSyntaxNode,
17194        window: &mut Window,
17195        cx: &mut Context<Self>,
17196    ) {
17197        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17198
17199        let buffer = self.buffer.read(cx).snapshot(cx);
17200        let selections = self
17201            .selections
17202            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17203            .into_iter()
17204            // subtracting the offset requires sorting
17205            .sorted_by_key(|i| i.start);
17206
17207        let full_edits = selections
17208            .into_iter()
17209            .filter_map(|selection| {
17210                let child = if selection.is_empty()
17211                    && let Some((_, ancestor_range)) =
17212                        buffer.syntax_ancestor(selection.start..selection.end)
17213                {
17214                    ancestor_range
17215                } else {
17216                    selection.range()
17217                };
17218
17219                let mut parent = child.clone();
17220                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
17221                    parent = ancestor_range;
17222                    if parent.start < child.start || parent.end > child.end {
17223                        break;
17224                    }
17225                }
17226
17227                if parent == child {
17228                    return None;
17229                }
17230                let text = buffer.text_for_range(child).collect::<String>();
17231                Some((selection.id, parent, text))
17232            })
17233            .collect::<Vec<_>>();
17234        if full_edits.is_empty() {
17235            return;
17236        }
17237
17238        self.transact(window, cx, |this, window, cx| {
17239            this.buffer.update(cx, |buffer, cx| {
17240                buffer.edit(
17241                    full_edits
17242                        .iter()
17243                        .map(|(_, p, t)| (p.clone(), t.clone()))
17244                        .collect::<Vec<_>>(),
17245                    None,
17246                    cx,
17247                );
17248            });
17249            this.change_selections(Default::default(), window, cx, |s| {
17250                let mut offset = 0;
17251                let mut selections = vec![];
17252                for (id, parent, text) in full_edits {
17253                    let start = parent.start - offset;
17254                    offset += (parent.end - parent.start) - text.len();
17255                    selections.push(Selection {
17256                        id,
17257                        start,
17258                        end: start + text.len(),
17259                        reversed: false,
17260                        goal: Default::default(),
17261                    });
17262                }
17263                s.select(selections);
17264            });
17265        });
17266    }
17267
17268    pub fn select_next_syntax_node(
17269        &mut self,
17270        _: &SelectNextSyntaxNode,
17271        window: &mut Window,
17272        cx: &mut Context<Self>,
17273    ) {
17274        let old_selections = self.selections.all_anchors(&self.display_snapshot(cx));
17275        if old_selections.is_empty() {
17276            return;
17277        }
17278
17279        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17280
17281        let buffer = self.buffer.read(cx).snapshot(cx);
17282        let mut selected_sibling = false;
17283
17284        let new_selections = old_selections
17285            .iter()
17286            .map(|selection| {
17287                let old_range =
17288                    selection.start.to_offset(&buffer)..selection.end.to_offset(&buffer);
17289                if let Some(results) = buffer.map_excerpt_ranges(
17290                    old_range,
17291                    |buf, _excerpt_range, input_buffer_range| {
17292                        let Some(node) = buf.syntax_next_sibling(input_buffer_range) else {
17293                            return Vec::new();
17294                        };
17295                        vec![(
17296                            BufferOffset(node.byte_range().start)
17297                                ..BufferOffset(node.byte_range().end),
17298                            (),
17299                        )]
17300                    },
17301                ) && let [(new_range, _)] = results.as_slice()
17302                {
17303                    selected_sibling = true;
17304                    let new_range =
17305                        buffer.anchor_after(new_range.start)..buffer.anchor_before(new_range.end);
17306                    Selection {
17307                        id: selection.id,
17308                        start: new_range.start,
17309                        end: new_range.end,
17310                        goal: SelectionGoal::None,
17311                        reversed: selection.reversed,
17312                    }
17313                } else {
17314                    selection.clone()
17315                }
17316            })
17317            .collect::<Vec<_>>();
17318
17319        if selected_sibling {
17320            self.change_selections(
17321                SelectionEffects::scroll(Autoscroll::fit()),
17322                window,
17323                cx,
17324                |s| {
17325                    s.select(new_selections);
17326                },
17327            );
17328        }
17329    }
17330
17331    pub fn select_prev_syntax_node(
17332        &mut self,
17333        _: &SelectPreviousSyntaxNode,
17334        window: &mut Window,
17335        cx: &mut Context<Self>,
17336    ) {
17337        let old_selections: Arc<[_]> = self.selections.all_anchors(&self.display_snapshot(cx));
17338
17339        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17340
17341        let multibuffer_snapshot = self.buffer.read(cx).snapshot(cx);
17342        let mut selected_sibling = false;
17343
17344        let new_selections = old_selections
17345            .iter()
17346            .map(|selection| {
17347                let old_range = selection.start.to_offset(&multibuffer_snapshot)
17348                    ..selection.end.to_offset(&multibuffer_snapshot);
17349                if let Some(results) = multibuffer_snapshot.map_excerpt_ranges(
17350                    old_range,
17351                    |buf, _excerpt_range, input_buffer_range| {
17352                        let Some(node) = buf.syntax_prev_sibling(input_buffer_range) else {
17353                            return Vec::new();
17354                        };
17355                        vec![(
17356                            BufferOffset(node.byte_range().start)
17357                                ..BufferOffset(node.byte_range().end),
17358                            (),
17359                        )]
17360                    },
17361                ) && let [(new_range, _)] = results.as_slice()
17362                {
17363                    selected_sibling = true;
17364                    let new_range = multibuffer_snapshot.anchor_after(new_range.start)
17365                        ..multibuffer_snapshot.anchor_before(new_range.end);
17366                    Selection {
17367                        id: selection.id,
17368                        start: new_range.start,
17369                        end: new_range.end,
17370                        goal: SelectionGoal::None,
17371                        reversed: selection.reversed,
17372                    }
17373                } else {
17374                    selection.clone()
17375                }
17376            })
17377            .collect::<Vec<_>>();
17378
17379        if selected_sibling {
17380            self.change_selections(
17381                SelectionEffects::scroll(Autoscroll::fit()),
17382                window,
17383                cx,
17384                |s| {
17385                    s.select(new_selections);
17386                },
17387            );
17388        }
17389    }
17390
17391    pub fn move_to_start_of_larger_syntax_node(
17392        &mut self,
17393        _: &MoveToStartOfLargerSyntaxNode,
17394        window: &mut Window,
17395        cx: &mut Context<Self>,
17396    ) {
17397        self.move_cursors_to_syntax_nodes(window, cx, false);
17398    }
17399
17400    pub fn move_to_end_of_larger_syntax_node(
17401        &mut self,
17402        _: &MoveToEndOfLargerSyntaxNode,
17403        window: &mut Window,
17404        cx: &mut Context<Self>,
17405    ) {
17406        self.move_cursors_to_syntax_nodes(window, cx, true);
17407    }
17408
17409    fn find_syntax_node_boundary(
17410        &self,
17411        selection_pos: MultiBufferOffset,
17412        move_to_end: bool,
17413        display_map: &DisplaySnapshot,
17414        buffer: &MultiBufferSnapshot,
17415    ) -> MultiBufferOffset {
17416        let old_range = selection_pos..selection_pos;
17417        let mut new_pos = selection_pos;
17418        let mut search_range = old_range;
17419        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
17420            search_range = range.clone();
17421            if !node.is_named()
17422                || display_map.intersects_fold(range.start)
17423                || display_map.intersects_fold(range.end)
17424                // If cursor is already at the end of the syntax node, continue searching
17425                || (move_to_end && range.end == selection_pos)
17426                // If cursor is already at the start of the syntax node, continue searching
17427                || (!move_to_end && range.start == selection_pos)
17428            {
17429                continue;
17430            }
17431
17432            // If we found a string_content node, find the largest parent that is still string_content
17433            // Enables us to skip to the end of strings without taking multiple steps inside the string
17434            let (_, final_range) = if node.kind() == "string_content" {
17435                let mut current_node = node;
17436                let mut current_range = range;
17437                while let Some((parent, parent_range)) =
17438                    buffer.syntax_ancestor(current_range.clone())
17439                {
17440                    if parent.kind() == "string_content" {
17441                        current_node = parent;
17442                        current_range = parent_range;
17443                    } else {
17444                        break;
17445                    }
17446                }
17447
17448                (current_node, current_range)
17449            } else {
17450                (node, range)
17451            };
17452
17453            new_pos = if move_to_end {
17454                final_range.end
17455            } else {
17456                final_range.start
17457            };
17458
17459            break;
17460        }
17461
17462        new_pos
17463    }
17464
17465    fn move_cursors_to_syntax_nodes(
17466        &mut self,
17467        window: &mut Window,
17468        cx: &mut Context<Self>,
17469        move_to_end: bool,
17470    ) -> bool {
17471        let old_selections: Box<[_]> = self
17472            .selections
17473            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
17474            .into();
17475        if old_selections.is_empty() {
17476            return false;
17477        }
17478
17479        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17480
17481        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17482        let buffer = self.buffer.read(cx).snapshot(cx);
17483
17484        let mut any_cursor_moved = false;
17485        let new_selections = old_selections
17486            .iter()
17487            .map(|selection| {
17488                if !selection.is_empty() {
17489                    return selection.clone();
17490                }
17491
17492                let selection_pos = selection.head();
17493                let new_pos = self.find_syntax_node_boundary(
17494                    selection_pos,
17495                    move_to_end,
17496                    &display_map,
17497                    &buffer,
17498                );
17499
17500                any_cursor_moved |= new_pos != selection_pos;
17501
17502                Selection {
17503                    id: selection.id,
17504                    start: new_pos,
17505                    end: new_pos,
17506                    goal: SelectionGoal::None,
17507                    reversed: false,
17508                }
17509            })
17510            .collect::<Vec<_>>();
17511
17512        self.change_selections(Default::default(), window, cx, |s| {
17513            s.select(new_selections);
17514        });
17515        self.request_autoscroll(Autoscroll::newest(), cx);
17516
17517        any_cursor_moved
17518    }
17519
17520    pub fn select_to_start_of_larger_syntax_node(
17521        &mut self,
17522        _: &SelectToStartOfLargerSyntaxNode,
17523        window: &mut Window,
17524        cx: &mut Context<Self>,
17525    ) {
17526        self.select_to_syntax_nodes(window, cx, false);
17527    }
17528
17529    pub fn select_to_end_of_larger_syntax_node(
17530        &mut self,
17531        _: &SelectToEndOfLargerSyntaxNode,
17532        window: &mut Window,
17533        cx: &mut Context<Self>,
17534    ) {
17535        self.select_to_syntax_nodes(window, cx, true);
17536    }
17537
17538    fn select_to_syntax_nodes(
17539        &mut self,
17540        window: &mut Window,
17541        cx: &mut Context<Self>,
17542        move_to_end: bool,
17543    ) {
17544        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17545
17546        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
17547        let buffer = self.buffer.read(cx).snapshot(cx);
17548        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
17549
17550        let new_selections = old_selections
17551            .iter()
17552            .map(|selection| {
17553                let new_pos = self.find_syntax_node_boundary(
17554                    selection.head(),
17555                    move_to_end,
17556                    &display_map,
17557                    &buffer,
17558                );
17559
17560                let mut new_selection = selection.clone();
17561                new_selection.set_head(new_pos, SelectionGoal::None);
17562                new_selection
17563            })
17564            .collect::<Vec<_>>();
17565
17566        self.change_selections(Default::default(), window, cx, |s| {
17567            s.select(new_selections);
17568        });
17569    }
17570
17571    pub fn move_to_enclosing_bracket(
17572        &mut self,
17573        _: &MoveToEnclosingBracket,
17574        window: &mut Window,
17575        cx: &mut Context<Self>,
17576    ) {
17577        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17578        self.change_selections(Default::default(), window, cx, |s| {
17579            s.move_offsets_with(&mut |snapshot, selection| {
17580                let Some(enclosing_bracket_ranges) =
17581                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
17582                else {
17583                    return;
17584                };
17585
17586                let mut best_length = usize::MAX;
17587                let mut best_inside = false;
17588                let mut best_in_bracket_range = false;
17589                let mut best_destination = None;
17590                for (open, close) in enclosing_bracket_ranges {
17591                    let close = close.to_inclusive();
17592                    let length = *close.end() - open.start;
17593                    let inside = selection.start >= open.end && selection.end <= *close.start();
17594                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
17595                        || close.contains(&selection.head());
17596
17597                    // If best is next to a bracket and current isn't, skip
17598                    if !in_bracket_range && best_in_bracket_range {
17599                        continue;
17600                    }
17601
17602                    // Prefer smaller lengths unless best is inside and current isn't
17603                    if length > best_length && (best_inside || !inside) {
17604                        continue;
17605                    }
17606
17607                    best_length = length;
17608                    best_inside = inside;
17609                    best_in_bracket_range = in_bracket_range;
17610                    best_destination = Some(
17611                        if close.contains(&selection.start) && close.contains(&selection.end) {
17612                            if inside { open.end } else { open.start }
17613                        } else if inside {
17614                            *close.start()
17615                        } else {
17616                            *close.end()
17617                        },
17618                    );
17619                }
17620
17621                if let Some(destination) = best_destination {
17622                    selection.collapse_to(destination, SelectionGoal::None);
17623                }
17624            })
17625        });
17626    }
17627
17628    pub fn undo_selection(
17629        &mut self,
17630        _: &UndoSelection,
17631        window: &mut Window,
17632        cx: &mut Context<Self>,
17633    ) {
17634        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17635        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17636            self.selection_history.mode = SelectionHistoryMode::Undoing;
17637            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17638                this.end_selection(window, cx);
17639                this.change_selections(
17640                    SelectionEffects::scroll(Autoscroll::newest()),
17641                    window,
17642                    cx,
17643                    |s| s.select_anchors(entry.selections.to_vec()),
17644                );
17645            });
17646            self.selection_history.mode = SelectionHistoryMode::Normal;
17647
17648            self.select_next_state = entry.select_next_state;
17649            self.select_prev_state = entry.select_prev_state;
17650            self.add_selections_state = entry.add_selections_state;
17651        }
17652    }
17653
17654    pub fn redo_selection(
17655        &mut self,
17656        _: &RedoSelection,
17657        window: &mut Window,
17658        cx: &mut Context<Self>,
17659    ) {
17660        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17661        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17662            self.selection_history.mode = SelectionHistoryMode::Redoing;
17663            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17664                this.end_selection(window, cx);
17665                this.change_selections(
17666                    SelectionEffects::scroll(Autoscroll::newest()),
17667                    window,
17668                    cx,
17669                    |s| s.select_anchors(entry.selections.to_vec()),
17670                );
17671            });
17672            self.selection_history.mode = SelectionHistoryMode::Normal;
17673
17674            self.select_next_state = entry.select_next_state;
17675            self.select_prev_state = entry.select_prev_state;
17676            self.add_selections_state = entry.add_selections_state;
17677        }
17678    }
17679
17680    pub fn expand_excerpts(
17681        &mut self,
17682        action: &ExpandExcerpts,
17683        _: &mut Window,
17684        cx: &mut Context<Self>,
17685    ) {
17686        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17687    }
17688
17689    pub fn expand_excerpts_down(
17690        &mut self,
17691        action: &ExpandExcerptsDown,
17692        _: &mut Window,
17693        cx: &mut Context<Self>,
17694    ) {
17695        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17696    }
17697
17698    pub fn expand_excerpts_up(
17699        &mut self,
17700        action: &ExpandExcerptsUp,
17701        _: &mut Window,
17702        cx: &mut Context<Self>,
17703    ) {
17704        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17705    }
17706
17707    pub fn expand_excerpts_for_direction(
17708        &mut self,
17709        lines: u32,
17710        direction: ExpandExcerptDirection,
17711        cx: &mut Context<Self>,
17712    ) {
17713        let selections = self.selections.disjoint_anchors_arc();
17714
17715        let lines = if lines == 0 {
17716            EditorSettings::get_global(cx).expand_excerpt_lines
17717        } else {
17718            lines
17719        };
17720
17721        let snapshot = self.buffer.read(cx).snapshot(cx);
17722        let excerpt_anchors = selections
17723            .iter()
17724            .flat_map(|selection| {
17725                snapshot
17726                    .range_to_buffer_ranges(selection.range())
17727                    .into_iter()
17728                    .filter_map(|(buffer_snapshot, range, _)| {
17729                        snapshot.anchor_in_excerpt(buffer_snapshot.anchor_after(range.start))
17730                    })
17731            })
17732            .collect::<Vec<_>>();
17733
17734        if self.delegate_expand_excerpts {
17735            cx.emit(EditorEvent::ExpandExcerptsRequested {
17736                excerpt_anchors,
17737                lines,
17738                direction,
17739            });
17740            return;
17741        }
17742
17743        self.buffer.update(cx, |buffer, cx| {
17744            buffer.expand_excerpts(excerpt_anchors, lines, direction, cx)
17745        })
17746    }
17747
17748    pub(crate) fn expand_excerpt(
17749        &mut self,
17750        excerpt_anchor: Anchor,
17751        direction: ExpandExcerptDirection,
17752        window: &mut Window,
17753        cx: &mut Context<Self>,
17754    ) {
17755        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17756
17757        if self.delegate_expand_excerpts {
17758            cx.emit(EditorEvent::ExpandExcerptsRequested {
17759                excerpt_anchors: vec![excerpt_anchor],
17760                lines: lines_to_expand,
17761                direction,
17762            });
17763            return;
17764        }
17765
17766        let current_scroll_position = self.scroll_position(cx);
17767        let mut scroll = None;
17768
17769        if direction == ExpandExcerptDirection::Down {
17770            let multi_buffer = self.buffer.read(cx);
17771            let snapshot = multi_buffer.snapshot(cx);
17772            if let Some((buffer_snapshot, excerpt_range)) =
17773                snapshot.excerpt_containing(excerpt_anchor..excerpt_anchor)
17774            {
17775                let excerpt_end_row =
17776                    Point::from_anchor(&excerpt_range.context.end, &buffer_snapshot).row;
17777                let last_row = buffer_snapshot.max_point().row;
17778                let lines_below = last_row.saturating_sub(excerpt_end_row);
17779                if lines_below >= lines_to_expand {
17780                    scroll = Some(
17781                        current_scroll_position
17782                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17783                    );
17784                }
17785            }
17786        }
17787        if direction == ExpandExcerptDirection::Up
17788            && self
17789                .buffer
17790                .read(cx)
17791                .snapshot(cx)
17792                .excerpt_before(excerpt_anchor)
17793                .is_none()
17794        {
17795            scroll = Some(current_scroll_position);
17796        }
17797
17798        self.buffer.update(cx, |buffer, cx| {
17799            buffer.expand_excerpts([excerpt_anchor], lines_to_expand, direction, cx)
17800        });
17801
17802        if let Some(new_scroll_position) = scroll {
17803            self.set_scroll_position(new_scroll_position, window, cx);
17804        }
17805    }
17806
17807    pub fn go_to_singleton_buffer_point(
17808        &mut self,
17809        point: Point,
17810        window: &mut Window,
17811        cx: &mut Context<Self>,
17812    ) {
17813        self.go_to_singleton_buffer_range(point..point, window, cx);
17814    }
17815
17816    pub fn go_to_singleton_buffer_range(
17817        &mut self,
17818        range: Range<Point>,
17819        window: &mut Window,
17820        cx: &mut Context<Self>,
17821    ) {
17822        let multibuffer = self.buffer().read(cx);
17823        if !multibuffer.is_singleton() {
17824            return;
17825        };
17826        let anchor_range = range.to_anchors(&multibuffer.snapshot(cx));
17827        self.change_selections(
17828            SelectionEffects::default().nav_history(true),
17829            window,
17830            cx,
17831            |s| s.select_anchor_ranges([anchor_range]),
17832        );
17833    }
17834
17835    pub fn go_to_diagnostic(
17836        &mut self,
17837        action: &GoToDiagnostic,
17838        window: &mut Window,
17839        cx: &mut Context<Self>,
17840    ) {
17841        if !self.diagnostics_enabled() {
17842            return;
17843        }
17844        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17845        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17846    }
17847
17848    pub fn go_to_prev_diagnostic(
17849        &mut self,
17850        action: &GoToPreviousDiagnostic,
17851        window: &mut Window,
17852        cx: &mut Context<Self>,
17853    ) {
17854        if !self.diagnostics_enabled() {
17855            return;
17856        }
17857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17858        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17859    }
17860
17861    pub fn go_to_diagnostic_impl(
17862        &mut self,
17863        direction: Direction,
17864        severity: GoToDiagnosticSeverityFilter,
17865        window: &mut Window,
17866        cx: &mut Context<Self>,
17867    ) {
17868        let buffer = self.buffer.read(cx).snapshot(cx);
17869        let selection = self
17870            .selections
17871            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17872
17873        let mut active_group_id = None;
17874        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17875            && active_group.active_range.start.to_offset(&buffer) == selection.start
17876        {
17877            active_group_id = Some(active_group.group_id);
17878        }
17879
17880        fn filtered<'a>(
17881            severity: GoToDiagnosticSeverityFilter,
17882            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17883        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17884            diagnostics
17885                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17886                .filter(|entry| entry.range.start != entry.range.end)
17887                .filter(|entry| !entry.diagnostic.is_unnecessary)
17888        }
17889
17890        let before = filtered(
17891            severity,
17892            buffer
17893                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17894                .filter(|entry| entry.range.start <= selection.start),
17895        );
17896        let after = filtered(
17897            severity,
17898            buffer
17899                .diagnostics_in_range(selection.start..buffer.len())
17900                .filter(|entry| entry.range.start >= selection.start),
17901        );
17902
17903        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17904        if direction == Direction::Prev {
17905            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17906            {
17907                for diagnostic in prev_diagnostics.into_iter().rev() {
17908                    if diagnostic.range.start != selection.start
17909                        || active_group_id
17910                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17911                    {
17912                        found = Some(diagnostic);
17913                        break 'outer;
17914                    }
17915                }
17916            }
17917        } else {
17918            for diagnostic in after.chain(before) {
17919                if diagnostic.range.start != selection.start
17920                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17921                {
17922                    found = Some(diagnostic);
17923                    break;
17924                }
17925            }
17926        }
17927        let Some(next_diagnostic) = found else {
17928            return;
17929        };
17930
17931        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17932        let Some((buffer_anchor, _)) = buffer.anchor_to_buffer_anchor(next_diagnostic_start) else {
17933            return;
17934        };
17935        let buffer_id = buffer_anchor.buffer_id;
17936        let snapshot = self.snapshot(window, cx);
17937        if snapshot.intersects_fold(next_diagnostic.range.start) {
17938            self.unfold_ranges(
17939                std::slice::from_ref(&next_diagnostic.range),
17940                true,
17941                false,
17942                cx,
17943            );
17944        }
17945        self.change_selections(Default::default(), window, cx, |s| {
17946            s.select_ranges(vec![
17947                next_diagnostic.range.start..next_diagnostic.range.start,
17948            ])
17949        });
17950        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17951        self.refresh_edit_prediction(false, true, window, cx);
17952    }
17953
17954    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17955        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17956        let snapshot = self.snapshot(window, cx);
17957        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17958        self.go_to_hunk_before_or_after_position(
17959            &snapshot,
17960            selection.head(),
17961            Direction::Next,
17962            true,
17963            window,
17964            cx,
17965        );
17966    }
17967
17968    pub fn go_to_hunk_before_or_after_position(
17969        &mut self,
17970        snapshot: &EditorSnapshot,
17971        position: Point,
17972        direction: Direction,
17973        wrap_around: bool,
17974        window: &mut Window,
17975        cx: &mut Context<Editor>,
17976    ) {
17977        let row = if direction == Direction::Next {
17978            self.hunk_after_position(snapshot, position, wrap_around)
17979                .map(|hunk| hunk.row_range.start)
17980        } else {
17981            self.hunk_before_position(snapshot, position, wrap_around)
17982        };
17983
17984        if let Some(row) = row {
17985            let destination = Point::new(row.0, 0);
17986            let autoscroll = Autoscroll::center();
17987
17988            self.unfold_ranges(&[destination..destination], false, false, cx);
17989            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17990                s.select_ranges([destination..destination]);
17991            });
17992        }
17993    }
17994
17995    fn hunk_after_position(
17996        &mut self,
17997        snapshot: &EditorSnapshot,
17998        position: Point,
17999        wrap_around: bool,
18000    ) -> Option<MultiBufferDiffHunk> {
18001        let result = snapshot
18002            .buffer_snapshot()
18003            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
18004            .find(|hunk| hunk.row_range.start.0 > position.row);
18005
18006        if wrap_around {
18007            result.or_else(|| {
18008                snapshot
18009                    .buffer_snapshot()
18010                    .diff_hunks_in_range(Point::zero()..position)
18011                    .find(|hunk| hunk.row_range.end.0 < position.row)
18012            })
18013        } else {
18014            result
18015        }
18016    }
18017
18018    fn go_to_prev_hunk(
18019        &mut self,
18020        _: &GoToPreviousHunk,
18021        window: &mut Window,
18022        cx: &mut Context<Self>,
18023    ) {
18024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
18025        let snapshot = self.snapshot(window, cx);
18026        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
18027        self.go_to_hunk_before_or_after_position(
18028            &snapshot,
18029            selection.head(),
18030            Direction::Prev,
18031            true,
18032            window,
18033            cx,
18034        );
18035    }
18036
18037    fn hunk_before_position(
18038        &mut self,
18039        snapshot: &EditorSnapshot,
18040        position: Point,
18041        wrap_around: bool,
18042    ) -> Option<MultiBufferRow> {
18043        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
18044
18045        if wrap_around {
18046            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
18047        } else {
18048            result
18049        }
18050    }
18051
18052    fn go_to_next_change(
18053        &mut self,
18054        _: &GoToNextChange,
18055        window: &mut Window,
18056        cx: &mut Context<Self>,
18057    ) {
18058        if let Some(selections) = self
18059            .change_list
18060            .next_change(1, Direction::Next)
18061            .map(|s| s.to_vec())
18062        {
18063            self.change_selections(Default::default(), window, cx, |s| {
18064                let map = s.display_snapshot();
18065                s.select_display_ranges(selections.iter().map(|a| {
18066                    let point = a.to_display_point(&map);
18067                    point..point
18068                }))
18069            })
18070        }
18071    }
18072
18073    fn go_to_previous_change(
18074        &mut self,
18075        _: &GoToPreviousChange,
18076        window: &mut Window,
18077        cx: &mut Context<Self>,
18078    ) {
18079        if let Some(selections) = self
18080            .change_list
18081            .next_change(1, Direction::Prev)
18082            .map(|s| s.to_vec())
18083        {
18084            self.change_selections(Default::default(), window, cx, |s| {
18085                let map = s.display_snapshot();
18086                s.select_display_ranges(selections.iter().map(|a| {
18087                    let point = a.to_display_point(&map);
18088                    point..point
18089                }))
18090            })
18091        }
18092    }
18093
18094    pub fn go_to_next_document_highlight(
18095        &mut self,
18096        _: &GoToNextDocumentHighlight,
18097        window: &mut Window,
18098        cx: &mut Context<Self>,
18099    ) {
18100        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
18101    }
18102
18103    pub fn go_to_prev_document_highlight(
18104        &mut self,
18105        _: &GoToPreviousDocumentHighlight,
18106        window: &mut Window,
18107        cx: &mut Context<Self>,
18108    ) {
18109        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
18110    }
18111
18112    pub fn go_to_document_highlight_before_or_after_position(
18113        &mut self,
18114        direction: Direction,
18115        window: &mut Window,
18116        cx: &mut Context<Editor>,
18117    ) {
18118        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
18119        let snapshot = self.snapshot(window, cx);
18120        let buffer = &snapshot.buffer_snapshot();
18121        let position = self
18122            .selections
18123            .newest::<Point>(&snapshot.display_snapshot)
18124            .head();
18125        let anchor_position = buffer.anchor_after(position);
18126
18127        // Get all document highlights (both read and write)
18128        let mut all_highlights = Vec::new();
18129
18130        if let Some((_, read_highlights)) = self
18131            .background_highlights
18132            .get(&HighlightKey::DocumentHighlightRead)
18133        {
18134            all_highlights.extend(read_highlights.iter());
18135        }
18136
18137        if let Some((_, write_highlights)) = self
18138            .background_highlights
18139            .get(&HighlightKey::DocumentHighlightWrite)
18140        {
18141            all_highlights.extend(write_highlights.iter());
18142        }
18143
18144        if all_highlights.is_empty() {
18145            return;
18146        }
18147
18148        // Sort highlights by position
18149        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
18150
18151        let target_highlight = match direction {
18152            Direction::Next => {
18153                // Find the first highlight after the current position
18154                all_highlights
18155                    .iter()
18156                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
18157            }
18158            Direction::Prev => {
18159                // Find the last highlight before the current position
18160                all_highlights
18161                    .iter()
18162                    .rev()
18163                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
18164            }
18165        };
18166
18167        if let Some(highlight) = target_highlight {
18168            let destination = highlight.start.to_point(buffer);
18169            let autoscroll = Autoscroll::center();
18170
18171            self.unfold_ranges(&[destination..destination], false, false, cx);
18172            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
18173                s.select_ranges([destination..destination]);
18174            });
18175        }
18176    }
18177
18178    fn go_to_line<T: 'static>(
18179        &mut self,
18180        position: Anchor,
18181        highlight_color: Option<Hsla>,
18182        window: &mut Window,
18183        cx: &mut Context<Self>,
18184    ) {
18185        let snapshot = self.snapshot(window, cx).display_snapshot;
18186        let position = position.to_point(&snapshot.buffer_snapshot());
18187        let start = snapshot
18188            .buffer_snapshot()
18189            .clip_point(Point::new(position.row, 0), Bias::Left);
18190        let end = start + Point::new(1, 0);
18191        let start = snapshot.buffer_snapshot().anchor_before(start);
18192        let end = snapshot.buffer_snapshot().anchor_before(end);
18193
18194        self.highlight_rows::<T>(
18195            start..end,
18196            highlight_color
18197                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
18198            Default::default(),
18199            cx,
18200        );
18201
18202        if self.buffer.read(cx).is_singleton() {
18203            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
18204        }
18205    }
18206
18207    pub fn go_to_definition(
18208        &mut self,
18209        _: &GoToDefinition,
18210        window: &mut Window,
18211        cx: &mut Context<Self>,
18212    ) -> Task<Result<Navigated>> {
18213        let definition =
18214            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
18215        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
18216        cx.spawn_in(window, async move |editor, cx| {
18217            if definition.await? == Navigated::Yes {
18218                return Ok(Navigated::Yes);
18219            }
18220            match fallback_strategy {
18221                GoToDefinitionFallback::None => Ok(Navigated::No),
18222                GoToDefinitionFallback::FindAllReferences => {
18223                    match editor.update_in(cx, |editor, window, cx| {
18224                        editor.find_all_references(&FindAllReferences::default(), window, cx)
18225                    })? {
18226                        Some(references) => references.await,
18227                        None => Ok(Navigated::No),
18228                    }
18229                }
18230            }
18231        })
18232    }
18233
18234    pub fn go_to_declaration(
18235        &mut self,
18236        _: &GoToDeclaration,
18237        window: &mut Window,
18238        cx: &mut Context<Self>,
18239    ) -> Task<Result<Navigated>> {
18240        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
18241    }
18242
18243    pub fn go_to_declaration_split(
18244        &mut self,
18245        _: &GoToDeclaration,
18246        window: &mut Window,
18247        cx: &mut Context<Self>,
18248    ) -> Task<Result<Navigated>> {
18249        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
18250    }
18251
18252    pub fn go_to_implementation(
18253        &mut self,
18254        _: &GoToImplementation,
18255        window: &mut Window,
18256        cx: &mut Context<Self>,
18257    ) -> Task<Result<Navigated>> {
18258        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
18259    }
18260
18261    pub fn go_to_implementation_split(
18262        &mut self,
18263        _: &GoToImplementationSplit,
18264        window: &mut Window,
18265        cx: &mut Context<Self>,
18266    ) -> Task<Result<Navigated>> {
18267        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
18268    }
18269
18270    pub fn go_to_type_definition(
18271        &mut self,
18272        _: &GoToTypeDefinition,
18273        window: &mut Window,
18274        cx: &mut Context<Self>,
18275    ) -> Task<Result<Navigated>> {
18276        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
18277    }
18278
18279    pub fn go_to_definition_split(
18280        &mut self,
18281        _: &GoToDefinitionSplit,
18282        window: &mut Window,
18283        cx: &mut Context<Self>,
18284    ) -> Task<Result<Navigated>> {
18285        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
18286    }
18287
18288    pub fn go_to_type_definition_split(
18289        &mut self,
18290        _: &GoToTypeDefinitionSplit,
18291        window: &mut Window,
18292        cx: &mut Context<Self>,
18293    ) -> Task<Result<Navigated>> {
18294        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
18295    }
18296
18297    fn go_to_definition_of_kind(
18298        &mut self,
18299        kind: GotoDefinitionKind,
18300        split: bool,
18301        window: &mut Window,
18302        cx: &mut Context<Self>,
18303    ) -> Task<Result<Navigated>> {
18304        let Some(provider) = self.semantics_provider.clone() else {
18305            return Task::ready(Ok(Navigated::No));
18306        };
18307        let head = self
18308            .selections
18309            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
18310            .head();
18311        let buffer = self.buffer.read(cx);
18312        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
18313            return Task::ready(Ok(Navigated::No));
18314        };
18315        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
18316            return Task::ready(Ok(Navigated::No));
18317        };
18318
18319        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
18320
18321        cx.spawn_in(window, async move |editor, cx| {
18322            let Some(definitions) = definitions.await? else {
18323                return Ok(Navigated::No);
18324            };
18325            let navigated = editor
18326                .update_in(cx, |editor, window, cx| {
18327                    editor.navigate_to_hover_links(
18328                        Some(kind),
18329                        definitions
18330                            .into_iter()
18331                            .filter(|location| {
18332                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
18333                            })
18334                            .map(HoverLink::Text)
18335                            .collect::<Vec<_>>(),
18336                        nav_entry,
18337                        split,
18338                        window,
18339                        cx,
18340                    )
18341                })?
18342                .await?;
18343            anyhow::Ok(navigated)
18344        })
18345    }
18346
18347    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
18348        let selection = self.selections.newest_anchor();
18349        let head = selection.head();
18350        let tail = selection.tail();
18351
18352        let Some((buffer, start_position)) =
18353            self.buffer.read(cx).text_anchor_for_position(head, cx)
18354        else {
18355            return;
18356        };
18357
18358        let end_position = if head != tail {
18359            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
18360                return;
18361            };
18362            Some(pos)
18363        } else {
18364            None
18365        };
18366
18367        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
18368            let url = if let Some(end_pos) = end_position {
18369                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
18370            } else {
18371                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
18372            };
18373
18374            if let Some(url) = url {
18375                cx.update(|window, cx| {
18376                    if parse_zed_link(&url, cx).is_some() {
18377                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18378                    } else {
18379                        cx.open_url(&url);
18380                    }
18381                })?;
18382            }
18383
18384            anyhow::Ok(())
18385        });
18386
18387        url_finder.detach();
18388    }
18389
18390    pub fn open_selected_filename(
18391        &mut self,
18392        _: &OpenSelectedFilename,
18393        window: &mut Window,
18394        cx: &mut Context<Self>,
18395    ) {
18396        let Some(workspace) = self.workspace() else {
18397            return;
18398        };
18399
18400        let position = self.selections.newest_anchor().head();
18401
18402        let Some((buffer, buffer_position)) =
18403            self.buffer.read(cx).text_anchor_for_position(position, cx)
18404        else {
18405            return;
18406        };
18407
18408        let project = self.project.clone();
18409
18410        cx.spawn_in(window, async move |_, cx| {
18411            let result = find_file(&buffer, project, buffer_position, cx).await;
18412
18413            if let Some((_, path)) = result {
18414                workspace
18415                    .update_in(cx, |workspace, window, cx| {
18416                        workspace.open_resolved_path(path, window, cx)
18417                    })?
18418                    .await?;
18419            }
18420            anyhow::Ok(())
18421        })
18422        .detach();
18423    }
18424
18425    pub(crate) fn navigate_to_hover_links(
18426        &mut self,
18427        kind: Option<GotoDefinitionKind>,
18428        definitions: Vec<HoverLink>,
18429        origin: Option<NavigationEntry>,
18430        split: bool,
18431        window: &mut Window,
18432        cx: &mut Context<Editor>,
18433    ) -> Task<Result<Navigated>> {
18434        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
18435        let mut first_url_or_file = None;
18436        let definitions: Vec<_> = definitions
18437            .into_iter()
18438            .filter_map(|def| match def {
18439                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
18440                HoverLink::InlayHint(lsp_location, server_id) => {
18441                    let computation =
18442                        self.compute_target_location(lsp_location, server_id, window, cx);
18443                    Some(cx.background_spawn(computation))
18444                }
18445                HoverLink::Url(url) => {
18446                    first_url_or_file = Some(Either::Left(url));
18447                    None
18448                }
18449                HoverLink::File(path) => {
18450                    first_url_or_file = Some(Either::Right(path));
18451                    None
18452                }
18453            })
18454            .collect();
18455
18456        let workspace = self.workspace();
18457
18458        let excerpt_context_lines = multi_buffer::excerpt_context_lines(cx);
18459        cx.spawn_in(window, async move |editor, cx| {
18460            let locations: Vec<Location> = future::join_all(definitions)
18461                .await
18462                .into_iter()
18463                .filter_map(|location| location.transpose())
18464                .collect::<Result<_>>()
18465                .context("location tasks")?;
18466            let mut locations = cx.update(|_, cx| {
18467                locations
18468                    .into_iter()
18469                    .map(|location| {
18470                        let buffer = location.buffer.read(cx);
18471                        (location.buffer, location.range.to_point(buffer))
18472                    })
18473                    .into_group_map()
18474            })?;
18475            let mut num_locations = 0;
18476            for ranges in locations.values_mut() {
18477                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18478                ranges.dedup();
18479                // Merge overlapping or contained ranges. After sorting by
18480                // (start, Reverse(end)), we can merge in a single pass:
18481                // if the next range starts before the current one ends,
18482                // extend the current range's end if needed.
18483                let mut i = 0;
18484                while i + 1 < ranges.len() {
18485                    if ranges[i + 1].start <= ranges[i].end {
18486                        let merged_end = ranges[i].end.max(ranges[i + 1].end);
18487                        ranges[i].end = merged_end;
18488                        ranges.remove(i + 1);
18489                    } else {
18490                        i += 1;
18491                    }
18492                }
18493                let fits_in_one_excerpt = ranges
18494                    .iter()
18495                    .tuple_windows()
18496                    .all(|(a, b)| b.start.row - a.end.row <= 2 * excerpt_context_lines);
18497                num_locations += if fits_in_one_excerpt { 1 } else { ranges.len() };
18498            }
18499
18500            if num_locations > 1 {
18501                let tab_kind = match kind {
18502                    Some(GotoDefinitionKind::Implementation) => "Implementations",
18503                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
18504                    Some(GotoDefinitionKind::Declaration) => "Declarations",
18505                    Some(GotoDefinitionKind::Type) => "Types",
18506                };
18507                let title = editor
18508                    .update_in(cx, |_, _, cx| {
18509                        let target = locations
18510                            .iter()
18511                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18512                            .map(|(buffer, location)| {
18513                                buffer
18514                                    .read(cx)
18515                                    .text_for_range(location.clone())
18516                                    .collect::<String>()
18517                            })
18518                            .filter(|text| !text.contains('\n'))
18519                            .unique()
18520                            .take(3)
18521                            .join(", ");
18522                        if target.is_empty() {
18523                            tab_kind.to_owned()
18524                        } else {
18525                            format!("{tab_kind} for {target}")
18526                        }
18527                    })
18528                    .context("buffer title")?;
18529
18530                let Some(workspace) = workspace else {
18531                    return Ok(Navigated::No);
18532                };
18533
18534                let opened = workspace
18535                    .update_in(cx, |workspace, window, cx| {
18536                        let allow_preview = PreviewTabsSettings::get_global(cx)
18537                            .enable_preview_multibuffer_from_code_navigation;
18538                        if let Some((target_editor, target_pane)) =
18539                            Self::open_locations_in_multibuffer(
18540                                workspace,
18541                                locations,
18542                                title,
18543                                split,
18544                                allow_preview,
18545                                MultibufferSelectionMode::First,
18546                                window,
18547                                cx,
18548                            )
18549                        {
18550                            // We create our own nav history instead of using
18551                            // `target_editor.nav_history` because `nav_history`
18552                            // seems to be populated asynchronously when an item
18553                            // is added to a pane
18554                            let mut nav_history = target_pane
18555                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18556                            target_editor.update(cx, |editor, cx| {
18557                                let nav_data = editor
18558                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
18559                                let target =
18560                                    Some(nav_history.navigation_entry(Some(
18561                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18562                                    )));
18563                                nav_history.push_tag(origin, target);
18564                            })
18565                        }
18566                    })
18567                    .is_ok();
18568
18569                anyhow::Ok(Navigated::from_bool(opened))
18570            } else if num_locations == 0 {
18571                // If there is one url or file, open it directly
18572                match first_url_or_file {
18573                    Some(Either::Left(url)) => {
18574                        cx.update(|window, cx| {
18575                            if parse_zed_link(&url, cx).is_some() {
18576                                window
18577                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
18578                            } else {
18579                                cx.open_url(&url);
18580                            }
18581                        })?;
18582                        Ok(Navigated::Yes)
18583                    }
18584                    Some(Either::Right(path)) => {
18585                        // TODO(andrew): respect preview tab settings
18586                        //               `enable_keep_preview_on_code_navigation` and
18587                        //               `enable_preview_file_from_code_navigation`
18588                        let Some(workspace) = workspace else {
18589                            return Ok(Navigated::No);
18590                        };
18591                        workspace
18592                            .update_in(cx, |workspace, window, cx| {
18593                                workspace.open_resolved_path(path, window, cx)
18594                            })?
18595                            .await?;
18596                        Ok(Navigated::Yes)
18597                    }
18598                    None => Ok(Navigated::No),
18599                }
18600            } else {
18601                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18602
18603                editor.update_in(cx, |editor, window, cx| {
18604                    let target_ranges = target_ranges
18605                        .into_iter()
18606                        .map(|r| editor.range_for_match(&r))
18607                        .map(collapse_multiline_range)
18608                        .collect::<Vec<_>>();
18609                    if !split
18610                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
18611                    {
18612                        let multibuffer = editor.buffer.read(cx);
18613                        let target_ranges = target_ranges
18614                            .into_iter()
18615                            .filter_map(|r| {
18616                                let start = multibuffer.buffer_point_to_anchor(
18617                                    &target_buffer,
18618                                    r.start,
18619                                    cx,
18620                                )?;
18621                                let end = multibuffer.buffer_point_to_anchor(
18622                                    &target_buffer,
18623                                    r.end,
18624                                    cx,
18625                                )?;
18626                                Some(start..end)
18627                            })
18628                            .collect::<Vec<_>>();
18629                        if target_ranges.is_empty() {
18630                            return Navigated::No;
18631                        }
18632
18633                        editor.change_selections(
18634                            SelectionEffects::default().nav_history(true),
18635                            window,
18636                            cx,
18637                            |s| s.select_anchor_ranges(target_ranges),
18638                        );
18639
18640                        let target =
18641                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
18642                        if let Some(mut nav_history) = editor.nav_history.clone() {
18643                            nav_history.push_tag(origin, target);
18644                        }
18645                    } else {
18646                        let Some(workspace) = workspace else {
18647                            return Navigated::No;
18648                        };
18649                        let pane = workspace.read(cx).active_pane().clone();
18650                        window.defer(cx, move |window, cx| {
18651                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18652                                workspace.update(cx, |workspace, cx| {
18653                                    let pane = if split {
18654                                        workspace.adjacent_pane(window, cx)
18655                                    } else {
18656                                        workspace.active_pane().clone()
18657                                    };
18658
18659                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18660                                    let keep_old_preview = preview_tabs_settings
18661                                        .enable_keep_preview_on_code_navigation;
18662                                    let allow_new_preview = preview_tabs_settings
18663                                        .enable_preview_file_from_code_navigation;
18664
18665                                    let editor = workspace.open_project_item(
18666                                        pane.clone(),
18667                                        target_buffer.clone(),
18668                                        true,
18669                                        true,
18670                                        keep_old_preview,
18671                                        allow_new_preview,
18672                                        window,
18673                                        cx,
18674                                    );
18675                                    (editor, pane)
18676                                });
18677                            // We create our own nav history instead of using
18678                            // `target_editor.nav_history` because `nav_history`
18679                            // seems to be populated asynchronously when an item
18680                            // is added to a pane
18681                            let mut nav_history = target_pane
18682                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18683                            target_editor.update(cx, |target_editor, cx| {
18684                                // When selecting a definition in a different buffer, disable the nav history
18685                                // to avoid creating a history entry at the previous cursor location.
18686                                pane.update(cx, |pane, _| pane.disable_history());
18687
18688                                let multibuffer = target_editor.buffer.read(cx);
18689                                let Some(target_buffer) = multibuffer.as_singleton() else {
18690                                    return Navigated::No;
18691                                };
18692                                let target_ranges = target_ranges
18693                                    .into_iter()
18694                                    .filter_map(|r| {
18695                                        let start = multibuffer.buffer_point_to_anchor(
18696                                            &target_buffer,
18697                                            r.start,
18698                                            cx,
18699                                        )?;
18700                                        let end = multibuffer.buffer_point_to_anchor(
18701                                            &target_buffer,
18702                                            r.end,
18703                                            cx,
18704                                        )?;
18705                                        Some(start..end)
18706                                    })
18707                                    .collect::<Vec<_>>();
18708                                if target_ranges.is_empty() {
18709                                    return Navigated::No;
18710                                }
18711
18712                                target_editor.change_selections(
18713                                    SelectionEffects::default().nav_history(true),
18714                                    window,
18715                                    cx,
18716                                    |s| s.select_anchor_ranges(target_ranges),
18717                                );
18718
18719                                let nav_data = target_editor.navigation_data(
18720                                    target_editor.selections.newest_anchor().head(),
18721                                    cx,
18722                                );
18723                                let target =
18724                                    Some(nav_history.navigation_entry(Some(
18725                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18726                                    )));
18727                                nav_history.push_tag(origin, target);
18728                                pane.update(cx, |pane, _| pane.enable_history());
18729                                Navigated::Yes
18730                            });
18731                        });
18732                    }
18733                    Navigated::Yes
18734                })
18735            }
18736        })
18737    }
18738
18739    fn compute_target_location(
18740        &self,
18741        lsp_location: lsp::Location,
18742        server_id: LanguageServerId,
18743        window: &mut Window,
18744        cx: &mut Context<Self>,
18745    ) -> Task<anyhow::Result<Option<Location>>> {
18746        let Some(project) = self.project.clone() else {
18747            return Task::ready(Ok(None));
18748        };
18749
18750        cx.spawn_in(window, async move |editor, cx| {
18751            let location_task = editor.update(cx, |_, cx| {
18752                project.update(cx, |project, cx| {
18753                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18754                })
18755            })?;
18756            let location = Some({
18757                let target_buffer_handle = location_task.await.context("open local buffer")?;
18758                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18759                    let target_start = target_buffer
18760                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18761                    let target_end = target_buffer
18762                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18763                    target_buffer.anchor_after(target_start)
18764                        ..target_buffer.anchor_before(target_end)
18765                });
18766                Location {
18767                    buffer: target_buffer_handle,
18768                    range,
18769                }
18770            });
18771            Ok(location)
18772        })
18773    }
18774
18775    fn go_to_next_reference(
18776        &mut self,
18777        _: &GoToNextReference,
18778        window: &mut Window,
18779        cx: &mut Context<Self>,
18780    ) {
18781        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18782        if let Some(task) = task {
18783            task.detach();
18784        };
18785    }
18786
18787    fn go_to_prev_reference(
18788        &mut self,
18789        _: &GoToPreviousReference,
18790        window: &mut Window,
18791        cx: &mut Context<Self>,
18792    ) {
18793        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18794        if let Some(task) = task {
18795            task.detach();
18796        };
18797    }
18798
18799    fn go_to_symbol_by_offset(
18800        &mut self,
18801        window: &mut Window,
18802        cx: &mut Context<Self>,
18803        offset: i8,
18804    ) -> Task<Result<()>> {
18805        let editor_snapshot = self.snapshot(window, cx);
18806
18807        // We don't care about multi-buffer symbols
18808        if !editor_snapshot.is_singleton() {
18809            return Task::ready(Ok(()));
18810        }
18811
18812        let cursor_offset = self
18813            .selections
18814            .newest::<MultiBufferOffset>(&editor_snapshot.display_snapshot)
18815            .head();
18816
18817        cx.spawn_in(window, async move |editor, wcx| -> Result<()> {
18818            let Ok(Some(remote_id)) = editor.update(wcx, |ed, cx| {
18819                let buffer = ed.buffer.read(cx).as_singleton()?;
18820                Some(buffer.read(cx).remote_id())
18821            }) else {
18822                return Ok(());
18823            };
18824
18825            let task = editor.update(wcx, |ed, cx| ed.buffer_outline_items(remote_id, cx))?;
18826            let outline_items: Vec<OutlineItem<text::Anchor>> = task.await;
18827
18828            let multi_snapshot = editor_snapshot.buffer();
18829            let buffer_range = |range: &Range<_>| {
18830                Some(
18831                    multi_snapshot
18832                        .buffer_anchor_range_to_anchor_range(range.clone())?
18833                        .to_offset(multi_snapshot),
18834                )
18835            };
18836
18837            wcx.update_window(wcx.window_handle(), |_, window, acx| {
18838                let current_idx = outline_items
18839                    .iter()
18840                    .enumerate()
18841                    .filter_map(|(idx, item)| {
18842                        // Find the closest outline item by distance between outline text and cursor location
18843                        let source_range = buffer_range(&item.source_range_for_text)?;
18844                        let distance_to_closest_endpoint = cmp::min(
18845                            (source_range.start.0 as isize - cursor_offset.0 as isize).abs(),
18846                            (source_range.end.0 as isize - cursor_offset.0 as isize).abs(),
18847                        );
18848
18849                        let item_towards_offset =
18850                            (source_range.start.0 as isize - cursor_offset.0 as isize).signum()
18851                                == (offset as isize).signum();
18852
18853                        let source_range_contains_cursor = source_range.contains(&cursor_offset);
18854
18855                        // To pick the next outline to jump to, we should jump in the direction of the offset, and
18856                        // we should not already be within the outline's source range. We then pick the closest outline
18857                        // item.
18858                        (item_towards_offset && !source_range_contains_cursor)
18859                            .then_some((distance_to_closest_endpoint, idx))
18860                    })
18861                    .min()
18862                    .map(|(_, idx)| idx);
18863
18864                let Some(idx) = current_idx else {
18865                    return;
18866                };
18867
18868                let Some(range) = buffer_range(&outline_items[idx].source_range_for_text) else {
18869                    return;
18870                };
18871                let selection = [range.start..range.start];
18872
18873                let _ = editor
18874                    .update(acx, |editor, ecx| {
18875                        editor.change_selections(
18876                            SelectionEffects::scroll(Autoscroll::newest()),
18877                            window,
18878                            ecx,
18879                            |s| s.select_ranges(selection),
18880                        );
18881                    })
18882                    .ok();
18883            })?;
18884
18885            Ok(())
18886        })
18887    }
18888
18889    fn go_to_next_symbol(
18890        &mut self,
18891        _: &GoToNextSymbol,
18892        window: &mut Window,
18893        cx: &mut Context<Self>,
18894    ) {
18895        self.go_to_symbol_by_offset(window, cx, 1).detach();
18896    }
18897
18898    fn go_to_previous_symbol(
18899        &mut self,
18900        _: &GoToPreviousSymbol,
18901        window: &mut Window,
18902        cx: &mut Context<Self>,
18903    ) {
18904        self.go_to_symbol_by_offset(window, cx, -1).detach();
18905    }
18906
18907    pub fn go_to_reference_before_or_after_position(
18908        &mut self,
18909        direction: Direction,
18910        count: usize,
18911        window: &mut Window,
18912        cx: &mut Context<Self>,
18913    ) -> Option<Task<Result<()>>> {
18914        let selection = self.selections.newest_anchor();
18915        let head = selection.head();
18916
18917        let multi_buffer = self.buffer.read(cx);
18918
18919        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18920        let workspace = self.workspace()?;
18921        let project = workspace.read(cx).project().clone();
18922        let references =
18923            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18924        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18925            let Some(locations) = references.await? else {
18926                return Ok(());
18927            };
18928
18929            if locations.is_empty() {
18930                // totally normal - the cursor may be on something which is not
18931                // a symbol (e.g. a keyword)
18932                log::info!("no references found under cursor");
18933                return Ok(());
18934            }
18935
18936            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18937
18938            let (locations, current_location_index) =
18939                multi_buffer.update(cx, |multi_buffer, cx| {
18940                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18941                    let mut locations = locations
18942                        .into_iter()
18943                        .filter_map(|loc| {
18944                            let start = multi_buffer_snapshot.anchor_in_excerpt(loc.range.start)?;
18945                            let end = multi_buffer_snapshot.anchor_in_excerpt(loc.range.end)?;
18946                            Some(start..end)
18947                        })
18948                        .collect::<Vec<_>>();
18949                    // There is an O(n) implementation, but given this list will be
18950                    // small (usually <100 items), the extra O(log(n)) factor isn't
18951                    // worth the (surprisingly large amount of) extra complexity.
18952                    locations
18953                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18954
18955                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18956
18957                    let current_location_index = locations.iter().position(|loc| {
18958                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18959                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18960                    });
18961
18962                    (locations, current_location_index)
18963                });
18964
18965            let Some(current_location_index) = current_location_index else {
18966                // This indicates something has gone wrong, because we already
18967                // handle the "no references" case above
18968                log::error!(
18969                    "failed to find current reference under cursor. Total references: {}",
18970                    locations.len()
18971                );
18972                return Ok(());
18973            };
18974
18975            let destination_location_index = match direction {
18976                Direction::Next => (current_location_index + count) % locations.len(),
18977                Direction::Prev => {
18978                    (current_location_index + locations.len() - count % locations.len())
18979                        % locations.len()
18980                }
18981            };
18982
18983            // TODO(cameron): is this needed?
18984            // the thinking is to avoid "jumping to the current location" (avoid
18985            // polluting "jumplist" in vim terms)
18986            if current_location_index == destination_location_index {
18987                return Ok(());
18988            }
18989
18990            let Range { start, end } = locations[destination_location_index];
18991
18992            editor.update_in(cx, |editor, window, cx| {
18993                let effects = SelectionEffects::default();
18994
18995                editor.unfold_ranges(&[start..end], false, false, cx);
18996                editor.change_selections(effects, window, cx, |s| {
18997                    s.select_ranges([start..start]);
18998                });
18999            })?;
19000
19001            Ok(())
19002        }))
19003    }
19004
19005    pub fn find_all_references(
19006        &mut self,
19007        action: &FindAllReferences,
19008        window: &mut Window,
19009        cx: &mut Context<Self>,
19010    ) -> Option<Task<Result<Navigated>>> {
19011        let always_open_multibuffer = action.always_open_multibuffer;
19012        let selection = self.selections.newest_anchor();
19013        let multi_buffer = self.buffer.read(cx);
19014        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
19015        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
19016        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
19017        let head = selection_offset.head();
19018
19019        let head_anchor = multi_buffer_snapshot.anchor_at(
19020            head,
19021            if head < selection_offset.tail() {
19022                Bias::Right
19023            } else {
19024                Bias::Left
19025            },
19026        );
19027
19028        match self
19029            .find_all_references_task_sources
19030            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
19031        {
19032            Ok(_) => {
19033                log::info!(
19034                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
19035                );
19036                return None;
19037            }
19038            Err(i) => {
19039                self.find_all_references_task_sources.insert(i, head_anchor);
19040            }
19041        }
19042
19043        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
19044        let workspace = self.workspace()?;
19045        let project = workspace.read(cx).project().clone();
19046        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
19047        Some(cx.spawn_in(window, async move |editor, cx| {
19048            let _cleanup = cx.on_drop(&editor, move |editor, _| {
19049                if let Ok(i) = editor
19050                    .find_all_references_task_sources
19051                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
19052                {
19053                    editor.find_all_references_task_sources.remove(i);
19054                }
19055            });
19056
19057            let Some(locations) = references.await? else {
19058                return anyhow::Ok(Navigated::No);
19059            };
19060            let mut locations = cx.update(|_, cx| {
19061                locations
19062                    .into_iter()
19063                    .map(|location| {
19064                        let buffer = location.buffer.read(cx);
19065                        (location.buffer, location.range.to_point(buffer))
19066                    })
19067                    // if special-casing the single-match case, remove ranges
19068                    // that intersect current selection
19069                    .filter(|(location_buffer, location)| {
19070                        if always_open_multibuffer || &buffer != location_buffer {
19071                            return true;
19072                        }
19073
19074                        !location.contains_inclusive(&selection_point.range())
19075                    })
19076                    .into_group_map()
19077            })?;
19078            if locations.is_empty() {
19079                return anyhow::Ok(Navigated::No);
19080            }
19081            for ranges in locations.values_mut() {
19082                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
19083                ranges.dedup();
19084            }
19085            let mut num_locations = 0;
19086            for ranges in locations.values_mut() {
19087                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
19088                ranges.dedup();
19089                num_locations += ranges.len();
19090            }
19091
19092            if num_locations == 1 && !always_open_multibuffer {
19093                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
19094                let target_range = target_ranges.first().unwrap().clone();
19095
19096                return editor.update_in(cx, |editor, window, cx| {
19097                    let range = target_range.to_point(target_buffer.read(cx));
19098                    let range = editor.range_for_match(&range);
19099                    let range = range.start..range.start;
19100
19101                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
19102                        editor.go_to_singleton_buffer_range(range, window, cx);
19103                    } else {
19104                        let pane = workspace.read(cx).active_pane().clone();
19105                        window.defer(cx, move |window, cx| {
19106                            let target_editor: Entity<Self> =
19107                                workspace.update(cx, |workspace, cx| {
19108                                    let pane = workspace.active_pane().clone();
19109
19110                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
19111                                    let keep_old_preview = preview_tabs_settings
19112                                        .enable_keep_preview_on_code_navigation;
19113                                    let allow_new_preview = preview_tabs_settings
19114                                        .enable_preview_file_from_code_navigation;
19115
19116                                    workspace.open_project_item(
19117                                        pane,
19118                                        target_buffer.clone(),
19119                                        true,
19120                                        true,
19121                                        keep_old_preview,
19122                                        allow_new_preview,
19123                                        window,
19124                                        cx,
19125                                    )
19126                                });
19127                            target_editor.update(cx, |target_editor, cx| {
19128                                // When selecting a definition in a different buffer, disable the nav history
19129                                // to avoid creating a history entry at the previous cursor location.
19130                                pane.update(cx, |pane, _| pane.disable_history());
19131                                target_editor.go_to_singleton_buffer_range(range, window, cx);
19132                                pane.update(cx, |pane, _| pane.enable_history());
19133                            });
19134                        });
19135                    }
19136                    Navigated::No
19137                });
19138            }
19139
19140            workspace.update_in(cx, |workspace, window, cx| {
19141                let target = locations
19142                    .iter()
19143                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
19144                    .map(|(buffer, location)| {
19145                        buffer
19146                            .read(cx)
19147                            .text_for_range(location.clone())
19148                            .collect::<String>()
19149                    })
19150                    .filter(|text| !text.contains('\n'))
19151                    .unique()
19152                    .take(3)
19153                    .join(", ");
19154                let title = if target.is_empty() {
19155                    "References".to_owned()
19156                } else {
19157                    format!("References to {target}")
19158                };
19159                let allow_preview = PreviewTabsSettings::get_global(cx)
19160                    .enable_preview_multibuffer_from_code_navigation;
19161                Self::open_locations_in_multibuffer(
19162                    workspace,
19163                    locations,
19164                    title,
19165                    false,
19166                    allow_preview,
19167                    MultibufferSelectionMode::First,
19168                    window,
19169                    cx,
19170                );
19171                Navigated::Yes
19172            })
19173        }))
19174    }
19175
19176    /// Opens a multibuffer with the given project locations in it.
19177    pub fn open_locations_in_multibuffer(
19178        workspace: &mut Workspace,
19179        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
19180        title: String,
19181        split: bool,
19182        allow_preview: bool,
19183        multibuffer_selection_mode: MultibufferSelectionMode,
19184        window: &mut Window,
19185        cx: &mut Context<Workspace>,
19186    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
19187        if locations.is_empty() {
19188            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
19189            return None;
19190        }
19191
19192        let capability = workspace.project().read(cx).capability();
19193        let mut ranges = <Vec<Range<Anchor>>>::new();
19194
19195        // a key to find existing multibuffer editors with the same set of locations
19196        // to prevent us from opening more and more multibuffer tabs for searches and the like
19197        let mut key = (title.clone(), vec![]);
19198        let excerpt_buffer = cx.new(|cx| {
19199            let key = &mut key.1;
19200            let mut multibuffer = MultiBuffer::new(capability);
19201            for (buffer, mut ranges_for_buffer) in locations {
19202                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
19203                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
19204                multibuffer.set_excerpts_for_path(
19205                    PathKey::for_buffer(&buffer, cx),
19206                    buffer.clone(),
19207                    ranges_for_buffer.clone(),
19208                    multibuffer_context_lines(cx),
19209                    cx,
19210                );
19211                let snapshot = multibuffer.snapshot(cx);
19212                let buffer_snapshot = buffer.read(cx).snapshot();
19213                ranges.extend(ranges_for_buffer.into_iter().filter_map(|range| {
19214                    let text_range = buffer_snapshot.anchor_range_inside(range);
19215                    let start = snapshot.anchor_in_buffer(text_range.start)?;
19216                    let end = snapshot.anchor_in_buffer(text_range.end)?;
19217                    Some(start..end)
19218                }))
19219            }
19220
19221            multibuffer.with_title(title)
19222        });
19223        let existing = workspace.active_pane().update(cx, |pane, cx| {
19224            pane.items()
19225                .filter_map(|item| item.downcast::<Editor>())
19226                .find(|editor| {
19227                    editor
19228                        .read(cx)
19229                        .lookup_key
19230                        .as_ref()
19231                        .and_then(|it| {
19232                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
19233                        })
19234                        .is_some_and(|it| *it == key)
19235                })
19236        });
19237        let was_existing = existing.is_some();
19238        let editor = existing.unwrap_or_else(|| {
19239            cx.new(|cx| {
19240                let mut editor = Editor::for_multibuffer(
19241                    excerpt_buffer,
19242                    Some(workspace.project().clone()),
19243                    window,
19244                    cx,
19245                );
19246                editor.lookup_key = Some(Box::new(key));
19247                editor
19248            })
19249        });
19250        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
19251            MultibufferSelectionMode::First => {
19252                if let Some(first_range) = ranges.first() {
19253                    editor.change_selections(
19254                        SelectionEffects::no_scroll(),
19255                        window,
19256                        cx,
19257                        |selections| {
19258                            selections.clear_disjoint();
19259                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
19260                        },
19261                    );
19262                }
19263                editor.highlight_background(
19264                    HighlightKey::Editor,
19265                    &ranges,
19266                    |_, theme| theme.colors().editor_highlighted_line_background,
19267                    cx,
19268                );
19269            }
19270            MultibufferSelectionMode::All => {
19271                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
19272                    selections.clear_disjoint();
19273                    selections.select_anchor_ranges(ranges);
19274                });
19275            }
19276        });
19277
19278        let item = Box::new(editor.clone());
19279
19280        let pane = if split {
19281            workspace.adjacent_pane(window, cx)
19282        } else {
19283            workspace.active_pane().clone()
19284        };
19285        let activate_pane = split;
19286
19287        let mut destination_index = None;
19288        pane.update(cx, |pane, cx| {
19289            if allow_preview && !was_existing {
19290                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
19291            }
19292            if was_existing && !allow_preview {
19293                pane.unpreview_item_if_preview(item.item_id());
19294            }
19295            pane.add_item(item, activate_pane, true, destination_index, window, cx);
19296        });
19297
19298        Some((editor, pane))
19299    }
19300
19301    pub fn rename(
19302        &mut self,
19303        _: &Rename,
19304        window: &mut Window,
19305        cx: &mut Context<Self>,
19306    ) -> Option<Task<Result<()>>> {
19307        use language::ToOffset as _;
19308
19309        let provider = self.semantics_provider.clone()?;
19310        let selection = self.selections.newest_anchor().clone();
19311        let (cursor_buffer, cursor_buffer_position) = self
19312            .buffer
19313            .read(cx)
19314            .text_anchor_for_position(selection.head(), cx)?;
19315        let (tail_buffer, cursor_buffer_position_end) = self
19316            .buffer
19317            .read(cx)
19318            .text_anchor_for_position(selection.tail(), cx)?;
19319        if tail_buffer != cursor_buffer {
19320            return None;
19321        }
19322
19323        let snapshot = cursor_buffer.read(cx).snapshot();
19324        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
19325        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
19326        let prepare_rename = provider.range_for_rename(&cursor_buffer, cursor_buffer_position, cx);
19327        drop(snapshot);
19328
19329        Some(cx.spawn_in(window, async move |this, cx| {
19330            let rename_range = prepare_rename.await?;
19331            if let Some(rename_range) = rename_range {
19332                this.update_in(cx, |this, window, cx| {
19333                    let snapshot = cursor_buffer.read(cx).snapshot();
19334                    let rename_buffer_range = rename_range.to_offset(&snapshot);
19335                    let cursor_offset_in_rename_range =
19336                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
19337                    let cursor_offset_in_rename_range_end =
19338                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
19339
19340                    this.take_rename(false, window, cx);
19341                    let buffer = this.buffer.read(cx).read(cx);
19342                    let cursor_offset = selection.head().to_offset(&buffer);
19343                    let rename_start =
19344                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
19345                    let rename_end = rename_start + rename_buffer_range.len();
19346                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
19347                    let mut old_highlight_id = None;
19348                    let old_name: Arc<str> = buffer
19349                        .chunks(
19350                            rename_start..rename_end,
19351                            LanguageAwareStyling {
19352                                tree_sitter: true,
19353                                diagnostics: true,
19354                            },
19355                        )
19356                        .map(|chunk| {
19357                            if old_highlight_id.is_none() {
19358                                old_highlight_id = chunk.syntax_highlight_id;
19359                            }
19360                            chunk.text
19361                        })
19362                        .collect::<String>()
19363                        .into();
19364
19365                    drop(buffer);
19366
19367                    // Position the selection in the rename editor so that it matches the current selection.
19368                    this.show_local_selections = false;
19369                    let rename_editor = cx.new(|cx| {
19370                        let mut editor = Editor::single_line(window, cx);
19371                        editor.buffer.update(cx, |buffer, cx| {
19372                            buffer.edit(
19373                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
19374                                None,
19375                                cx,
19376                            )
19377                        });
19378                        let cursor_offset_in_rename_range =
19379                            MultiBufferOffset(cursor_offset_in_rename_range);
19380                        let cursor_offset_in_rename_range_end =
19381                            MultiBufferOffset(cursor_offset_in_rename_range_end);
19382                        let rename_selection_range = match cursor_offset_in_rename_range
19383                            .cmp(&cursor_offset_in_rename_range_end)
19384                        {
19385                            Ordering::Equal => {
19386                                editor.select_all(&SelectAll, window, cx);
19387                                return editor;
19388                            }
19389                            Ordering::Less => {
19390                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
19391                            }
19392                            Ordering::Greater => {
19393                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
19394                            }
19395                        };
19396                        if rename_selection_range.end.0 > old_name.len() {
19397                            editor.select_all(&SelectAll, window, cx);
19398                        } else {
19399                            editor.change_selections(Default::default(), window, cx, |s| {
19400                                s.select_ranges([rename_selection_range]);
19401                            });
19402                        }
19403                        editor
19404                    });
19405                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
19406                        if e == &EditorEvent::Focused {
19407                            cx.emit(EditorEvent::FocusedIn)
19408                        }
19409                    })
19410                    .detach();
19411
19412                    let write_highlights =
19413                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
19414                    let read_highlights =
19415                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
19416                    let ranges = write_highlights
19417                        .iter()
19418                        .flat_map(|(_, ranges)| ranges.iter())
19419                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
19420                        .cloned()
19421                        .collect();
19422
19423                    this.highlight_text(
19424                        HighlightKey::Rename,
19425                        ranges,
19426                        HighlightStyle {
19427                            fade_out: Some(0.6),
19428                            ..Default::default()
19429                        },
19430                        cx,
19431                    );
19432                    let rename_focus_handle = rename_editor.focus_handle(cx);
19433                    window.focus(&rename_focus_handle, cx);
19434                    let block_id = this.insert_blocks(
19435                        [BlockProperties {
19436                            style: BlockStyle::Flex,
19437                            placement: BlockPlacement::Below(range.start),
19438                            height: Some(1),
19439                            render: Arc::new({
19440                                let rename_editor = rename_editor.clone();
19441                                move |cx: &mut BlockContext| {
19442                                    let mut text_style = cx.editor_style.text.clone();
19443                                    if let Some(highlight_style) = old_highlight_id
19444                                        .and_then(|h| cx.editor_style.syntax.get(h).cloned())
19445                                    {
19446                                        text_style = text_style.highlight(highlight_style);
19447                                    }
19448                                    div()
19449                                        .block_mouse_except_scroll()
19450                                        .pl(cx.anchor_x)
19451                                        .child(EditorElement::new(
19452                                            &rename_editor,
19453                                            EditorStyle {
19454                                                background: cx.theme().system().transparent,
19455                                                local_player: cx.editor_style.local_player,
19456                                                text: text_style,
19457                                                scrollbar_width: cx.editor_style.scrollbar_width,
19458                                                syntax: cx.editor_style.syntax.clone(),
19459                                                status: cx.editor_style.status.clone(),
19460                                                inlay_hints_style: HighlightStyle {
19461                                                    font_weight: Some(FontWeight::BOLD),
19462                                                    ..make_inlay_hints_style(cx.app)
19463                                                },
19464                                                edit_prediction_styles: make_suggestion_styles(
19465                                                    cx.app,
19466                                                ),
19467                                                ..EditorStyle::default()
19468                                            },
19469                                        ))
19470                                        .into_any_element()
19471                                }
19472                            }),
19473                            priority: 0,
19474                        }],
19475                        Some(Autoscroll::fit()),
19476                        cx,
19477                    )[0];
19478                    this.pending_rename = Some(RenameState {
19479                        range,
19480                        old_name,
19481                        editor: rename_editor,
19482                        block_id,
19483                    });
19484                })?;
19485            }
19486
19487            Ok(())
19488        }))
19489    }
19490
19491    pub fn confirm_rename(
19492        &mut self,
19493        _: &ConfirmRename,
19494        window: &mut Window,
19495        cx: &mut Context<Self>,
19496    ) -> Option<Task<Result<()>>> {
19497        let rename = self.take_rename(false, window, cx)?;
19498        let workspace = self.workspace()?.downgrade();
19499        let (buffer, start) = self
19500            .buffer
19501            .read(cx)
19502            .text_anchor_for_position(rename.range.start, cx)?;
19503        let (end_buffer, _) = self
19504            .buffer
19505            .read(cx)
19506            .text_anchor_for_position(rename.range.end, cx)?;
19507        if buffer != end_buffer {
19508            return None;
19509        }
19510
19511        let old_name = rename.old_name;
19512        let new_name = rename.editor.read(cx).text(cx);
19513
19514        let rename = self.semantics_provider.as_ref()?.perform_rename(
19515            &buffer,
19516            start,
19517            new_name.clone(),
19518            cx,
19519        )?;
19520
19521        Some(cx.spawn_in(window, async move |editor, cx| {
19522            let project_transaction = rename.await?;
19523            Self::open_project_transaction(
19524                &editor,
19525                workspace,
19526                project_transaction,
19527                format!("Rename: {}{}", old_name, new_name),
19528                cx,
19529            )
19530            .await?;
19531
19532            editor.update(cx, |editor, cx| {
19533                editor.refresh_document_highlights(cx);
19534            })?;
19535            Ok(())
19536        }))
19537    }
19538
19539    fn take_rename(
19540        &mut self,
19541        moving_cursor: bool,
19542        window: &mut Window,
19543        cx: &mut Context<Self>,
19544    ) -> Option<RenameState> {
19545        let rename = self.pending_rename.take()?;
19546        if rename.editor.focus_handle(cx).is_focused(window) {
19547            window.focus(&self.focus_handle, cx);
19548        }
19549
19550        self.remove_blocks(
19551            [rename.block_id].into_iter().collect(),
19552            Some(Autoscroll::fit()),
19553            cx,
19554        );
19555        self.clear_highlights(HighlightKey::Rename, cx);
19556        self.show_local_selections = true;
19557
19558        if moving_cursor {
19559            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
19560                editor
19561                    .selections
19562                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
19563                    .head()
19564            });
19565
19566            // Update the selection to match the position of the selection inside
19567            // the rename editor.
19568            let snapshot = self.buffer.read(cx).read(cx);
19569            let rename_range = rename.range.to_offset(&snapshot);
19570            let cursor_in_editor = snapshot
19571                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
19572                .min(rename_range.end);
19573            drop(snapshot);
19574
19575            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19576                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
19577            });
19578        } else {
19579            self.refresh_document_highlights(cx);
19580        }
19581
19582        Some(rename)
19583    }
19584
19585    pub fn pending_rename(&self) -> Option<&RenameState> {
19586        self.pending_rename.as_ref()
19587    }
19588
19589    fn format(
19590        &mut self,
19591        _: &Format,
19592        window: &mut Window,
19593        cx: &mut Context<Self>,
19594    ) -> Option<Task<Result<()>>> {
19595        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19596
19597        let project = match &self.project {
19598            Some(project) => project.clone(),
19599            None => return None,
19600        };
19601
19602        Some(self.perform_format(
19603            project,
19604            FormatTrigger::Manual,
19605            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
19606            window,
19607            cx,
19608        ))
19609    }
19610
19611    fn format_selections(
19612        &mut self,
19613        _: &FormatSelections,
19614        window: &mut Window,
19615        cx: &mut Context<Self>,
19616    ) -> Option<Task<Result<()>>> {
19617        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19618
19619        let project = match &self.project {
19620            Some(project) => project.clone(),
19621            None => return None,
19622        };
19623
19624        let ranges = self
19625            .selections
19626            .all_adjusted(&self.display_snapshot(cx))
19627            .into_iter()
19628            .map(|selection| selection.range())
19629            .collect_vec();
19630
19631        Some(self.perform_format(
19632            project,
19633            FormatTrigger::Manual,
19634            FormatTarget::Ranges(ranges),
19635            window,
19636            cx,
19637        ))
19638    }
19639
19640    fn perform_format(
19641        &mut self,
19642        project: Entity<Project>,
19643        trigger: FormatTrigger,
19644        target: FormatTarget,
19645        window: &mut Window,
19646        cx: &mut Context<Self>,
19647    ) -> Task<Result<()>> {
19648        let buffer = self.buffer.clone();
19649        let (buffers, target) = match target {
19650            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
19651            FormatTarget::Ranges(selection_ranges) => {
19652                let multi_buffer = buffer.read(cx);
19653                let snapshot = multi_buffer.read(cx);
19654                let mut buffers = HashSet::default();
19655                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
19656                    BTreeMap::new();
19657                for selection_range in selection_ranges {
19658                    for (buffer_snapshot, buffer_range, _) in
19659                        snapshot.range_to_buffer_ranges(selection_range.start..selection_range.end)
19660                    {
19661                        let buffer_id = buffer_snapshot.remote_id();
19662                        let start = buffer_snapshot.anchor_before(buffer_range.start);
19663                        let end = buffer_snapshot.anchor_after(buffer_range.end);
19664                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
19665                        buffer_id_to_ranges
19666                            .entry(buffer_id)
19667                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
19668                            .or_insert_with(|| vec![start..end]);
19669                    }
19670                }
19671                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
19672            }
19673        };
19674
19675        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
19676        let selections_prev = transaction_id_prev
19677            .and_then(|transaction_id_prev| {
19678                // default to selections as they were after the last edit, if we have them,
19679                // instead of how they are now.
19680                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
19681                // will take you back to where you made the last edit, instead of staying where you scrolled
19682                self.selection_history
19683                    .transaction(transaction_id_prev)
19684                    .map(|t| t.0.clone())
19685            })
19686            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
19687
19688        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
19689        let format = project.update(cx, |project, cx| {
19690            project.format(buffers, target, true, trigger, cx)
19691        });
19692
19693        cx.spawn_in(window, async move |editor, cx| {
19694            let transaction = futures::select_biased! {
19695                transaction = format.log_err().fuse() => transaction,
19696                () = timeout => {
19697                    log::warn!("timed out waiting for formatting");
19698                    None
19699                }
19700            };
19701
19702            buffer.update(cx, |buffer, cx| {
19703                if let Some(transaction) = transaction
19704                    && !buffer.is_singleton()
19705                {
19706                    buffer.push_transaction(&transaction.0, cx);
19707                }
19708                cx.notify();
19709            });
19710
19711            if let Some(transaction_id_now) =
19712                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
19713            {
19714                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
19715                if has_new_transaction {
19716                    editor
19717                        .update(cx, |editor, _| {
19718                            editor
19719                                .selection_history
19720                                .insert_transaction(transaction_id_now, selections_prev);
19721                        })
19722                        .ok();
19723                }
19724            }
19725
19726            Ok(())
19727        })
19728    }
19729
19730    fn organize_imports(
19731        &mut self,
19732        _: &OrganizeImports,
19733        window: &mut Window,
19734        cx: &mut Context<Self>,
19735    ) -> Option<Task<Result<()>>> {
19736        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
19737        let project = match &self.project {
19738            Some(project) => project.clone(),
19739            None => return None,
19740        };
19741        Some(self.perform_code_action_kind(
19742            project,
19743            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
19744            window,
19745            cx,
19746        ))
19747    }
19748
19749    fn perform_code_action_kind(
19750        &mut self,
19751        project: Entity<Project>,
19752        kind: CodeActionKind,
19753        window: &mut Window,
19754        cx: &mut Context<Self>,
19755    ) -> Task<Result<()>> {
19756        let buffer = self.buffer.clone();
19757        let buffers = buffer.read(cx).all_buffers();
19758        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
19759        let apply_action = project.update(cx, |project, cx| {
19760            project.apply_code_action_kind(buffers, kind, true, cx)
19761        });
19762        cx.spawn_in(window, async move |_, cx| {
19763            let transaction = futures::select_biased! {
19764                () = timeout => {
19765                    log::warn!("timed out waiting for executing code action");
19766                    None
19767                }
19768                transaction = apply_action.log_err().fuse() => transaction,
19769            };
19770            buffer.update(cx, |buffer, cx| {
19771                // check if we need this
19772                if let Some(transaction) = transaction
19773                    && !buffer.is_singleton()
19774                {
19775                    buffer.push_transaction(&transaction.0, cx);
19776                }
19777                cx.notify();
19778            });
19779            Ok(())
19780        })
19781    }
19782
19783    pub fn restart_language_server(
19784        &mut self,
19785        _: &RestartLanguageServer,
19786        _: &mut Window,
19787        cx: &mut Context<Self>,
19788    ) {
19789        if let Some(project) = self.project.clone() {
19790            self.buffer.update(cx, |multi_buffer, cx| {
19791                project.update(cx, |project, cx| {
19792                    project.restart_language_servers_for_buffers(
19793                        multi_buffer.all_buffers().into_iter().collect(),
19794                        HashSet::default(),
19795                        cx,
19796                    );
19797                });
19798            })
19799        }
19800    }
19801
19802    pub fn stop_language_server(
19803        &mut self,
19804        _: &StopLanguageServer,
19805        _: &mut Window,
19806        cx: &mut Context<Self>,
19807    ) {
19808        if let Some(project) = self.project.clone() {
19809            self.buffer.update(cx, |multi_buffer, cx| {
19810                project.update(cx, |project, cx| {
19811                    project.stop_language_servers_for_buffers(
19812                        multi_buffer.all_buffers().into_iter().collect(),
19813                        HashSet::default(),
19814                        cx,
19815                    );
19816                });
19817            });
19818        }
19819    }
19820
19821    fn cancel_language_server_work(
19822        workspace: &mut Workspace,
19823        _: &actions::CancelLanguageServerWork,
19824        _: &mut Window,
19825        cx: &mut Context<Workspace>,
19826    ) {
19827        let project = workspace.project();
19828        let buffers = workspace
19829            .active_item(cx)
19830            .and_then(|item| item.act_as::<Editor>(cx))
19831            .map_or(HashSet::default(), |editor| {
19832                editor.read(cx).buffer.read(cx).all_buffers()
19833            });
19834        project.update(cx, |project, cx| {
19835            project.cancel_language_server_work_for_buffers(buffers, cx);
19836        });
19837    }
19838
19839    fn show_character_palette(
19840        &mut self,
19841        _: &ShowCharacterPalette,
19842        window: &mut Window,
19843        _: &mut Context<Self>,
19844    ) {
19845        window.show_character_palette();
19846    }
19847
19848    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19849        if !self.diagnostics_enabled() {
19850            return;
19851        }
19852
19853        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19854            let buffer = self.buffer.read(cx).snapshot(cx);
19855            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19856            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19857            let is_valid = buffer
19858                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19859                .any(|entry| {
19860                    entry.diagnostic.is_primary
19861                        && !entry.range.is_empty()
19862                        && entry.range.start == primary_range_start
19863                        && entry.diagnostic.message == active_diagnostics.active_message
19864                });
19865
19866            if !is_valid {
19867                self.dismiss_diagnostics(cx);
19868            }
19869        }
19870    }
19871
19872    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19873        match &self.active_diagnostics {
19874            ActiveDiagnostic::Group(group) => Some(group),
19875            _ => None,
19876        }
19877    }
19878
19879    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19880        if !self.diagnostics_enabled() {
19881            return;
19882        }
19883        self.dismiss_diagnostics(cx);
19884        self.active_diagnostics = ActiveDiagnostic::All;
19885    }
19886
19887    fn activate_diagnostics(
19888        &mut self,
19889        buffer_id: BufferId,
19890        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19891        window: &mut Window,
19892        cx: &mut Context<Self>,
19893    ) {
19894        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19895            return;
19896        }
19897        self.dismiss_diagnostics(cx);
19898        let snapshot = self.snapshot(window, cx);
19899        let buffer = self.buffer.read(cx).snapshot(cx);
19900        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19901            return;
19902        };
19903
19904        let diagnostic_group = buffer
19905            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19906            .collect::<Vec<_>>();
19907
19908        let language_registry = self
19909            .project()
19910            .map(|project| project.read(cx).languages().clone());
19911
19912        let blocks = renderer.render_group(
19913            diagnostic_group,
19914            buffer_id,
19915            snapshot,
19916            cx.weak_entity(),
19917            language_registry,
19918            cx,
19919        );
19920
19921        let blocks = self.display_map.update(cx, |display_map, cx| {
19922            display_map.insert_blocks(blocks, cx).into_iter().collect()
19923        });
19924        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19925            active_range: buffer.anchor_before(diagnostic.range.start)
19926                ..buffer.anchor_after(diagnostic.range.end),
19927            active_message: diagnostic.diagnostic.message.clone(),
19928            group_id: diagnostic.diagnostic.group_id,
19929            blocks,
19930        });
19931        cx.notify();
19932    }
19933
19934    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19935        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19936            return;
19937        };
19938
19939        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19940        if let ActiveDiagnostic::Group(group) = prev {
19941            self.display_map.update(cx, |display_map, cx| {
19942                display_map.remove_blocks(group.blocks, cx);
19943            });
19944            cx.notify();
19945        }
19946    }
19947
19948    /// Disable inline diagnostics rendering for this editor.
19949    pub fn disable_inline_diagnostics(&mut self) {
19950        self.inline_diagnostics_enabled = false;
19951        self.inline_diagnostics_update = Task::ready(());
19952        self.inline_diagnostics.clear();
19953    }
19954
19955    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19956        self.diagnostics_enabled = false;
19957        self.dismiss_diagnostics(cx);
19958        self.inline_diagnostics_update = Task::ready(());
19959        self.inline_diagnostics.clear();
19960    }
19961
19962    pub fn disable_word_completions(&mut self) {
19963        self.word_completions_enabled = false;
19964    }
19965
19966    pub fn diagnostics_enabled(&self) -> bool {
19967        self.diagnostics_enabled && self.lsp_data_enabled()
19968    }
19969
19970    pub fn inline_diagnostics_enabled(&self) -> bool {
19971        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19972    }
19973
19974    pub fn show_inline_diagnostics(&self) -> bool {
19975        self.show_inline_diagnostics
19976    }
19977
19978    pub fn toggle_inline_diagnostics(
19979        &mut self,
19980        _: &ToggleInlineDiagnostics,
19981        window: &mut Window,
19982        cx: &mut Context<Editor>,
19983    ) {
19984        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19985        self.refresh_inline_diagnostics(false, window, cx);
19986    }
19987
19988    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19989        self.diagnostics_max_severity = severity;
19990        self.display_map.update(cx, |display_map, _| {
19991            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19992        });
19993    }
19994
19995    pub fn toggle_diagnostics(
19996        &mut self,
19997        _: &ToggleDiagnostics,
19998        window: &mut Window,
19999        cx: &mut Context<Editor>,
20000    ) {
20001        if !self.diagnostics_enabled() {
20002            return;
20003        }
20004
20005        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
20006            EditorSettings::get_global(cx)
20007                .diagnostics_max_severity
20008                .filter(|severity| severity != &DiagnosticSeverity::Off)
20009                .unwrap_or(DiagnosticSeverity::Hint)
20010        } else {
20011            DiagnosticSeverity::Off
20012        };
20013        self.set_max_diagnostics_severity(new_severity, cx);
20014        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
20015            self.active_diagnostics = ActiveDiagnostic::None;
20016            self.inline_diagnostics_update = Task::ready(());
20017            self.inline_diagnostics.clear();
20018        } else {
20019            self.refresh_inline_diagnostics(false, window, cx);
20020        }
20021
20022        cx.notify();
20023    }
20024
20025    pub fn toggle_minimap(
20026        &mut self,
20027        _: &ToggleMinimap,
20028        window: &mut Window,
20029        cx: &mut Context<Editor>,
20030    ) {
20031        if self.supports_minimap(cx) {
20032            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
20033        }
20034    }
20035
20036    fn refresh_inline_diagnostics(
20037        &mut self,
20038        debounce: bool,
20039        window: &mut Window,
20040        cx: &mut Context<Self>,
20041    ) {
20042        let max_severity = ProjectSettings::get_global(cx)
20043            .diagnostics
20044            .inline
20045            .max_severity
20046            .unwrap_or(self.diagnostics_max_severity);
20047
20048        if !self.inline_diagnostics_enabled()
20049            || !self.diagnostics_enabled()
20050            || !self.show_inline_diagnostics
20051            || max_severity == DiagnosticSeverity::Off
20052        {
20053            self.inline_diagnostics_update = Task::ready(());
20054            self.inline_diagnostics.clear();
20055            return;
20056        }
20057
20058        let debounce_ms = ProjectSettings::get_global(cx)
20059            .diagnostics
20060            .inline
20061            .update_debounce_ms;
20062        let debounce = if debounce && debounce_ms > 0 {
20063            Some(Duration::from_millis(debounce_ms))
20064        } else {
20065            None
20066        };
20067        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
20068            if let Some(debounce) = debounce {
20069                cx.background_executor().timer(debounce).await;
20070            }
20071            let Some(snapshot) = editor.upgrade().map(|editor| {
20072                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
20073            }) else {
20074                return;
20075            };
20076
20077            let new_inline_diagnostics = cx
20078                .background_spawn(async move {
20079                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
20080                    for diagnostic_entry in
20081                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
20082                    {
20083                        let message = diagnostic_entry
20084                            .diagnostic
20085                            .message
20086                            .split_once('\n')
20087                            .map(|(line, _)| line)
20088                            .map(SharedString::new)
20089                            .unwrap_or_else(|| {
20090                                SharedString::new(&*diagnostic_entry.diagnostic.message)
20091                            });
20092                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
20093                        let (Ok(i) | Err(i)) = inline_diagnostics
20094                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
20095                        inline_diagnostics.insert(
20096                            i,
20097                            (
20098                                start_anchor,
20099                                InlineDiagnostic {
20100                                    message,
20101                                    group_id: diagnostic_entry.diagnostic.group_id,
20102                                    start: diagnostic_entry.range.start.to_point(&snapshot),
20103                                    is_primary: diagnostic_entry.diagnostic.is_primary,
20104                                    severity: diagnostic_entry.diagnostic.severity,
20105                                },
20106                            ),
20107                        );
20108                    }
20109                    inline_diagnostics
20110                })
20111                .await;
20112
20113            editor
20114                .update(cx, |editor, cx| {
20115                    editor.inline_diagnostics = new_inline_diagnostics;
20116                    cx.notify();
20117                })
20118                .ok();
20119        });
20120    }
20121
20122    fn pull_diagnostics(
20123        &mut self,
20124        buffer_id: BufferId,
20125        _window: &Window,
20126        cx: &mut Context<Self>,
20127    ) -> Option<()> {
20128        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
20129        // skip any LSP updates for it.
20130
20131        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
20132            return None;
20133        }
20134        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
20135            .diagnostics
20136            .lsp_pull_diagnostics;
20137        if !pull_diagnostics_settings.enabled {
20138            return None;
20139        }
20140        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
20141        let project = self.project()?.downgrade();
20142        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
20143
20144        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
20145            cx.background_executor().timer(debounce).await;
20146            if let Ok(task) = project.update(cx, |project, cx| {
20147                project.lsp_store().update(cx, |lsp_store, cx| {
20148                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
20149                })
20150            }) {
20151                task.await.log_err();
20152            }
20153            project
20154                .update(cx, |project, cx| {
20155                    project.lsp_store().update(cx, |lsp_store, cx| {
20156                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
20157                    })
20158                })
20159                .log_err();
20160        });
20161
20162        Some(())
20163    }
20164
20165    pub fn set_selections_from_remote(
20166        &mut self,
20167        selections: Vec<Selection<Anchor>>,
20168        pending_selection: Option<Selection<Anchor>>,
20169        window: &mut Window,
20170        cx: &mut Context<Self>,
20171    ) {
20172        let old_cursor_position = self.selections.newest_anchor().head();
20173        self.selections
20174            .change_with(&self.display_snapshot(cx), |s| {
20175                s.select_anchors(selections);
20176                if let Some(pending_selection) = pending_selection {
20177                    s.set_pending(pending_selection, SelectMode::Character);
20178                } else {
20179                    s.clear_pending();
20180                }
20181            });
20182        self.selections_did_change(
20183            false,
20184            &old_cursor_position,
20185            SelectionEffects::default(),
20186            window,
20187            cx,
20188        );
20189    }
20190
20191    pub fn transact(
20192        &mut self,
20193        window: &mut Window,
20194        cx: &mut Context<Self>,
20195        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
20196    ) -> Option<TransactionId> {
20197        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
20198            this.start_transaction_at(Instant::now(), window, cx);
20199            update(this, window, cx);
20200            this.end_transaction_at(Instant::now(), cx)
20201        })
20202    }
20203
20204    pub fn start_transaction_at(
20205        &mut self,
20206        now: Instant,
20207        window: &mut Window,
20208        cx: &mut Context<Self>,
20209    ) -> Option<TransactionId> {
20210        self.end_selection(window, cx);
20211        if let Some(tx_id) = self
20212            .buffer
20213            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
20214        {
20215            self.selection_history
20216                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
20217            cx.emit(EditorEvent::TransactionBegun {
20218                transaction_id: tx_id,
20219            });
20220            Some(tx_id)
20221        } else {
20222            None
20223        }
20224    }
20225
20226    pub fn end_transaction_at(
20227        &mut self,
20228        now: Instant,
20229        cx: &mut Context<Self>,
20230    ) -> Option<TransactionId> {
20231        if let Some(transaction_id) = self
20232            .buffer
20233            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
20234        {
20235            if let Some((_, end_selections)) =
20236                self.selection_history.transaction_mut(transaction_id)
20237            {
20238                *end_selections = Some(self.selections.disjoint_anchors_arc());
20239            } else {
20240                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
20241            }
20242
20243            cx.emit(EditorEvent::Edited { transaction_id });
20244            Some(transaction_id)
20245        } else {
20246            None
20247        }
20248    }
20249
20250    pub fn modify_transaction_selection_history(
20251        &mut self,
20252        transaction_id: TransactionId,
20253        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
20254    ) -> bool {
20255        self.selection_history
20256            .transaction_mut(transaction_id)
20257            .map(modify)
20258            .is_some()
20259    }
20260
20261    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
20262        if self.selection_mark_mode {
20263            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20264                s.move_with(&mut |_, sel| {
20265                    sel.collapse_to(sel.head(), SelectionGoal::None);
20266                });
20267            })
20268        }
20269        self.selection_mark_mode = true;
20270        cx.notify();
20271    }
20272
20273    pub fn swap_selection_ends(
20274        &mut self,
20275        _: &actions::SwapSelectionEnds,
20276        window: &mut Window,
20277        cx: &mut Context<Self>,
20278    ) {
20279        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
20280            s.move_with(&mut |_, sel| {
20281                if sel.start != sel.end {
20282                    sel.reversed = !sel.reversed
20283                }
20284            });
20285        });
20286        self.request_autoscroll(Autoscroll::newest(), cx);
20287        cx.notify();
20288    }
20289
20290    pub fn toggle_focus(
20291        workspace: &mut Workspace,
20292        _: &actions::ToggleFocus,
20293        window: &mut Window,
20294        cx: &mut Context<Workspace>,
20295    ) {
20296        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
20297            return;
20298        };
20299        workspace.activate_item(&item, true, true, window, cx);
20300    }
20301
20302    pub fn toggle_fold(
20303        &mut self,
20304        _: &actions::ToggleFold,
20305        window: &mut Window,
20306        cx: &mut Context<Self>,
20307    ) {
20308        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20309            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20310            let selection = self.selections.newest::<Point>(&display_map);
20311
20312            let range = if selection.is_empty() {
20313                let point = selection.head().to_display_point(&display_map);
20314                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20315                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20316                    .to_point(&display_map);
20317                start..end
20318            } else {
20319                selection.range()
20320            };
20321            if display_map.folds_in_range(range).next().is_some() {
20322                self.unfold_lines(&Default::default(), window, cx)
20323            } else {
20324                self.fold(&Default::default(), window, cx)
20325            }
20326        } else {
20327            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20328            let buffer_ids: HashSet<_> = self
20329                .selections
20330                .disjoint_anchor_ranges()
20331                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20332                .collect();
20333
20334            let should_unfold = buffer_ids
20335                .iter()
20336                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
20337
20338            for buffer_id in buffer_ids {
20339                if should_unfold {
20340                    self.unfold_buffer(buffer_id, cx);
20341                } else {
20342                    self.fold_buffer(buffer_id, cx);
20343                }
20344            }
20345        }
20346    }
20347
20348    pub fn toggle_fold_recursive(
20349        &mut self,
20350        _: &actions::ToggleFoldRecursive,
20351        window: &mut Window,
20352        cx: &mut Context<Self>,
20353    ) {
20354        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
20355
20356        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20357        let range = if selection.is_empty() {
20358            let point = selection.head().to_display_point(&display_map);
20359            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
20360            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
20361                .to_point(&display_map);
20362            start..end
20363        } else {
20364            selection.range()
20365        };
20366        if display_map.folds_in_range(range).next().is_some() {
20367            self.unfold_recursive(&Default::default(), window, cx)
20368        } else {
20369            self.fold_recursive(&Default::default(), window, cx)
20370        }
20371    }
20372
20373    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
20374        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20375            let mut to_fold = Vec::new();
20376            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20377            let selections = self.selections.all_adjusted(&display_map);
20378
20379            for selection in selections {
20380                let range = selection.range().sorted();
20381                let buffer_start_row = range.start.row;
20382
20383                if range.start.row != range.end.row {
20384                    let mut found = false;
20385                    let mut row = range.start.row;
20386                    while row <= range.end.row {
20387                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20388                        {
20389                            found = true;
20390                            row = crease.range().end.row + 1;
20391                            to_fold.push(crease);
20392                        } else {
20393                            row += 1
20394                        }
20395                    }
20396                    if found {
20397                        continue;
20398                    }
20399                }
20400
20401                for row in (0..=range.start.row).rev() {
20402                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
20403                        && crease.range().end.row >= buffer_start_row
20404                    {
20405                        to_fold.push(crease);
20406                        if row <= range.start.row {
20407                            break;
20408                        }
20409                    }
20410                }
20411            }
20412
20413            self.fold_creases(to_fold, true, window, cx);
20414        } else {
20415            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20416            let buffer_ids = self
20417                .selections
20418                .disjoint_anchor_ranges()
20419                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20420                .collect::<HashSet<_>>();
20421            for buffer_id in buffer_ids {
20422                self.fold_buffer(buffer_id, cx);
20423            }
20424        }
20425    }
20426
20427    pub fn toggle_fold_all(
20428        &mut self,
20429        _: &actions::ToggleFoldAll,
20430        window: &mut Window,
20431        cx: &mut Context<Self>,
20432    ) {
20433        let has_folds = if self.buffer.read(cx).is_singleton() {
20434            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20435            let has_folds = display_map
20436                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
20437                .next()
20438                .is_some();
20439            has_folds
20440        } else {
20441            let snapshot = self.buffer.read(cx).snapshot(cx);
20442            let has_folds = snapshot
20443                .all_buffer_ids()
20444                .any(|buffer_id| self.is_buffer_folded(buffer_id, cx));
20445            has_folds
20446        };
20447
20448        if has_folds {
20449            self.unfold_all(&actions::UnfoldAll, window, cx);
20450        } else {
20451            self.fold_all(&actions::FoldAll, window, cx);
20452        }
20453    }
20454
20455    fn fold_at_level(
20456        &mut self,
20457        fold_at: &FoldAtLevel,
20458        window: &mut Window,
20459        cx: &mut Context<Self>,
20460    ) {
20461        if !self.buffer.read(cx).is_singleton() {
20462            return;
20463        }
20464
20465        let fold_at_level = fold_at.0;
20466        let snapshot = self.buffer.read(cx).snapshot(cx);
20467        let mut to_fold = Vec::new();
20468        let mut stack = vec![(0, snapshot.max_row().0, 1)];
20469
20470        let row_ranges_to_keep: Vec<Range<u32>> = self
20471            .selections
20472            .all::<Point>(&self.display_snapshot(cx))
20473            .into_iter()
20474            .map(|sel| sel.start.row..sel.end.row)
20475            .collect();
20476
20477        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
20478            while start_row < end_row {
20479                match self
20480                    .snapshot(window, cx)
20481                    .crease_for_buffer_row(MultiBufferRow(start_row))
20482                {
20483                    Some(crease) => {
20484                        let nested_start_row = crease.range().start.row + 1;
20485                        let nested_end_row = crease.range().end.row;
20486
20487                        if current_level < fold_at_level {
20488                            stack.push((nested_start_row, nested_end_row, current_level + 1));
20489                        } else if current_level == fold_at_level {
20490                            // Fold iff there is no selection completely contained within the fold region
20491                            if !row_ranges_to_keep.iter().any(|selection| {
20492                                selection.end >= nested_start_row
20493                                    && selection.start <= nested_end_row
20494                            }) {
20495                                to_fold.push(crease);
20496                            }
20497                        }
20498
20499                        start_row = nested_end_row + 1;
20500                    }
20501                    None => start_row += 1,
20502                }
20503            }
20504        }
20505
20506        self.fold_creases(to_fold, true, window, cx);
20507    }
20508
20509    pub fn fold_at_level_1(
20510        &mut self,
20511        _: &actions::FoldAtLevel1,
20512        window: &mut Window,
20513        cx: &mut Context<Self>,
20514    ) {
20515        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
20516    }
20517
20518    pub fn fold_at_level_2(
20519        &mut self,
20520        _: &actions::FoldAtLevel2,
20521        window: &mut Window,
20522        cx: &mut Context<Self>,
20523    ) {
20524        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
20525    }
20526
20527    pub fn fold_at_level_3(
20528        &mut self,
20529        _: &actions::FoldAtLevel3,
20530        window: &mut Window,
20531        cx: &mut Context<Self>,
20532    ) {
20533        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
20534    }
20535
20536    pub fn fold_at_level_4(
20537        &mut self,
20538        _: &actions::FoldAtLevel4,
20539        window: &mut Window,
20540        cx: &mut Context<Self>,
20541    ) {
20542        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
20543    }
20544
20545    pub fn fold_at_level_5(
20546        &mut self,
20547        _: &actions::FoldAtLevel5,
20548        window: &mut Window,
20549        cx: &mut Context<Self>,
20550    ) {
20551        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
20552    }
20553
20554    pub fn fold_at_level_6(
20555        &mut self,
20556        _: &actions::FoldAtLevel6,
20557        window: &mut Window,
20558        cx: &mut Context<Self>,
20559    ) {
20560        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
20561    }
20562
20563    pub fn fold_at_level_7(
20564        &mut self,
20565        _: &actions::FoldAtLevel7,
20566        window: &mut Window,
20567        cx: &mut Context<Self>,
20568    ) {
20569        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
20570    }
20571
20572    pub fn fold_at_level_8(
20573        &mut self,
20574        _: &actions::FoldAtLevel8,
20575        window: &mut Window,
20576        cx: &mut Context<Self>,
20577    ) {
20578        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
20579    }
20580
20581    pub fn fold_at_level_9(
20582        &mut self,
20583        _: &actions::FoldAtLevel9,
20584        window: &mut Window,
20585        cx: &mut Context<Self>,
20586    ) {
20587        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
20588    }
20589
20590    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
20591        if self.buffer.read(cx).is_singleton() {
20592            let mut fold_ranges = Vec::new();
20593            let snapshot = self.buffer.read(cx).snapshot(cx);
20594
20595            for row in 0..snapshot.max_row().0 {
20596                if let Some(foldable_range) = self
20597                    .snapshot(window, cx)
20598                    .crease_for_buffer_row(MultiBufferRow(row))
20599                {
20600                    fold_ranges.push(foldable_range);
20601                }
20602            }
20603
20604            self.fold_creases(fold_ranges, true, window, cx);
20605        } else {
20606            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
20607                editor
20608                    .update_in(cx, |editor, _, cx| {
20609                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20610                        for buffer_id in snapshot.all_buffer_ids() {
20611                            editor.fold_buffer(buffer_id, cx);
20612                        }
20613                    })
20614                    .ok();
20615            });
20616        }
20617    }
20618
20619    pub fn fold_function_bodies(
20620        &mut self,
20621        _: &actions::FoldFunctionBodies,
20622        window: &mut Window,
20623        cx: &mut Context<Self>,
20624    ) {
20625        let snapshot = self.buffer.read(cx).snapshot(cx);
20626
20627        let ranges = snapshot
20628            .text_object_ranges(
20629                MultiBufferOffset(0)..snapshot.len(),
20630                TreeSitterOptions::default(),
20631            )
20632            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
20633            .collect::<Vec<_>>();
20634
20635        let creases = ranges
20636            .into_iter()
20637            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
20638            .collect();
20639
20640        self.fold_creases(creases, true, window, cx);
20641    }
20642
20643    pub fn fold_recursive(
20644        &mut self,
20645        _: &actions::FoldRecursive,
20646        window: &mut Window,
20647        cx: &mut Context<Self>,
20648    ) {
20649        let mut to_fold = Vec::new();
20650        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20651        let selections = self.selections.all_adjusted(&display_map);
20652
20653        for selection in selections {
20654            let range = selection.range().sorted();
20655            let buffer_start_row = range.start.row;
20656
20657            if range.start.row != range.end.row {
20658                let mut found = false;
20659                for row in range.start.row..=range.end.row {
20660                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20661                        found = true;
20662                        to_fold.push(crease);
20663                    }
20664                }
20665                if found {
20666                    continue;
20667                }
20668            }
20669
20670            for row in (0..=range.start.row).rev() {
20671                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
20672                    if crease.range().end.row >= buffer_start_row {
20673                        to_fold.push(crease);
20674                    } else {
20675                        break;
20676                    }
20677                }
20678            }
20679        }
20680
20681        self.fold_creases(to_fold, true, window, cx);
20682    }
20683
20684    pub fn fold_at(
20685        &mut self,
20686        buffer_row: MultiBufferRow,
20687        window: &mut Window,
20688        cx: &mut Context<Self>,
20689    ) {
20690        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20691
20692        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
20693            let autoscroll = self
20694                .selections
20695                .all::<Point>(&display_map)
20696                .iter()
20697                .any(|selection| crease.range().overlaps(&selection.range()));
20698
20699            self.fold_creases(vec![crease], autoscroll, window, cx);
20700        }
20701    }
20702
20703    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
20704        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
20705            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20706            let buffer = display_map.buffer_snapshot();
20707            let selections = self.selections.all::<Point>(&display_map);
20708            let ranges = selections
20709                .iter()
20710                .map(|s| {
20711                    let range = s.display_range(&display_map).sorted();
20712                    let mut start = range.start.to_point(&display_map);
20713                    let mut end = range.end.to_point(&display_map);
20714                    start.column = 0;
20715                    end.column = buffer.line_len(MultiBufferRow(end.row));
20716                    start..end
20717                })
20718                .collect::<Vec<_>>();
20719
20720            self.unfold_ranges(&ranges, true, true, cx);
20721        } else {
20722            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
20723            let buffer_ids = self
20724                .selections
20725                .disjoint_anchor_ranges()
20726                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
20727                .collect::<HashSet<_>>();
20728            for buffer_id in buffer_ids {
20729                self.unfold_buffer(buffer_id, cx);
20730            }
20731        }
20732    }
20733
20734    pub fn unfold_recursive(
20735        &mut self,
20736        _: &UnfoldRecursive,
20737        _window: &mut Window,
20738        cx: &mut Context<Self>,
20739    ) {
20740        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20741        let selections = self.selections.all::<Point>(&display_map);
20742        let ranges = selections
20743            .iter()
20744            .map(|s| {
20745                let mut range = s.display_range(&display_map).sorted();
20746                *range.start.column_mut() = 0;
20747                *range.end.column_mut() = display_map.line_len(range.end.row());
20748                let start = range.start.to_point(&display_map);
20749                let end = range.end.to_point(&display_map);
20750                start..end
20751            })
20752            .collect::<Vec<_>>();
20753
20754        self.unfold_ranges(&ranges, true, true, cx);
20755    }
20756
20757    pub fn unfold_at(
20758        &mut self,
20759        buffer_row: MultiBufferRow,
20760        _window: &mut Window,
20761        cx: &mut Context<Self>,
20762    ) {
20763        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20764
20765        let intersection_range = Point::new(buffer_row.0, 0)
20766            ..Point::new(
20767                buffer_row.0,
20768                display_map.buffer_snapshot().line_len(buffer_row),
20769            );
20770
20771        let autoscroll = self
20772            .selections
20773            .all::<Point>(&display_map)
20774            .iter()
20775            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20776
20777        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20778    }
20779
20780    pub fn unfold_all(
20781        &mut self,
20782        _: &actions::UnfoldAll,
20783        _window: &mut Window,
20784        cx: &mut Context<Self>,
20785    ) {
20786        if self.buffer.read(cx).is_singleton() {
20787            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20788            self.unfold_ranges(
20789                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20790                true,
20791                true,
20792                cx,
20793            );
20794        } else {
20795            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20796                editor
20797                    .update(cx, |editor, cx| {
20798                        let snapshot = editor.buffer.read(cx).snapshot(cx);
20799                        for buffer_id in snapshot.all_buffer_ids() {
20800                            editor.unfold_buffer(buffer_id, cx);
20801                        }
20802                    })
20803                    .ok();
20804            });
20805        }
20806    }
20807
20808    pub fn fold_selected_ranges(
20809        &mut self,
20810        _: &FoldSelectedRanges,
20811        window: &mut Window,
20812        cx: &mut Context<Self>,
20813    ) {
20814        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20815        let selections = self.selections.all_adjusted(&display_map);
20816        let ranges = selections
20817            .into_iter()
20818            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20819            .collect::<Vec<_>>();
20820        self.fold_creases(ranges, true, window, cx);
20821    }
20822
20823    pub fn fold_ranges<T: ToOffset + Clone>(
20824        &mut self,
20825        ranges: Vec<Range<T>>,
20826        auto_scroll: bool,
20827        window: &mut Window,
20828        cx: &mut Context<Self>,
20829    ) {
20830        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20831        let ranges = ranges
20832            .into_iter()
20833            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20834            .collect::<Vec<_>>();
20835        self.fold_creases(ranges, auto_scroll, window, cx);
20836    }
20837
20838    pub fn fold_creases<T: ToOffset + Clone>(
20839        &mut self,
20840        creases: Vec<Crease<T>>,
20841        auto_scroll: bool,
20842        window: &mut Window,
20843        cx: &mut Context<Self>,
20844    ) {
20845        if creases.is_empty() {
20846            return;
20847        }
20848
20849        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20850
20851        if auto_scroll {
20852            self.request_autoscroll(Autoscroll::fit(), cx);
20853        }
20854
20855        cx.notify();
20856
20857        self.scrollbar_marker_state.dirty = true;
20858        self.update_data_on_scroll(window, cx);
20859        self.folds_did_change(cx);
20860    }
20861
20862    /// Removes any folds whose ranges intersect any of the given ranges.
20863    pub fn unfold_ranges<T: ToOffset + Clone>(
20864        &mut self,
20865        ranges: &[Range<T>],
20866        inclusive: bool,
20867        auto_scroll: bool,
20868        cx: &mut Context<Self>,
20869    ) {
20870        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20871            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20872        });
20873        self.folds_did_change(cx);
20874    }
20875
20876    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20877        self.fold_buffers([buffer_id], cx);
20878    }
20879
20880    pub fn fold_buffers(
20881        &mut self,
20882        buffer_ids: impl IntoIterator<Item = BufferId>,
20883        cx: &mut Context<Self>,
20884    ) {
20885        if self.buffer().read(cx).is_singleton() {
20886            return;
20887        }
20888
20889        let ids_to_fold: Vec<BufferId> = buffer_ids
20890            .into_iter()
20891            .filter(|id| !self.is_buffer_folded(*id, cx))
20892            .collect();
20893
20894        if ids_to_fold.is_empty() {
20895            return;
20896        }
20897
20898        self.display_map.update(cx, |display_map, cx| {
20899            display_map.fold_buffers(ids_to_fold.clone(), cx)
20900        });
20901
20902        let snapshot = self.display_snapshot(cx);
20903        self.selections.change_with(&snapshot, |selections| {
20904            for buffer_id in ids_to_fold.iter().copied() {
20905                selections.remove_selections_from_buffer(buffer_id);
20906            }
20907        });
20908
20909        cx.emit(EditorEvent::BufferFoldToggled {
20910            ids: ids_to_fold,
20911            folded: true,
20912        });
20913        cx.notify();
20914    }
20915
20916    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20917        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20918            return;
20919        }
20920        self.display_map.update(cx, |display_map, cx| {
20921            display_map.unfold_buffers([buffer_id], cx);
20922        });
20923        cx.emit(EditorEvent::BufferFoldToggled {
20924            ids: vec![buffer_id],
20925            folded: false,
20926        });
20927        cx.notify();
20928    }
20929
20930    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20931        self.display_map.read(cx).is_buffer_folded(buffer)
20932    }
20933
20934    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20935        if self.buffer().read(cx).is_singleton() {
20936            return false;
20937        }
20938        !self.folded_buffers(cx).is_empty()
20939    }
20940
20941    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20942        self.display_map.read(cx).folded_buffers()
20943    }
20944
20945    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20946        self.display_map.update(cx, |display_map, cx| {
20947            display_map.disable_header_for_buffer(buffer_id, cx);
20948        });
20949        cx.notify();
20950    }
20951
20952    /// Removes any folds with the given ranges.
20953    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20954        &mut self,
20955        ranges: &[Range<T>],
20956        type_id: TypeId,
20957        auto_scroll: bool,
20958        cx: &mut Context<Self>,
20959    ) {
20960        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20961            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20962        });
20963        self.folds_did_change(cx);
20964    }
20965
20966    fn remove_folds_with<T: ToOffset + Clone>(
20967        &mut self,
20968        ranges: &[Range<T>],
20969        auto_scroll: bool,
20970        cx: &mut Context<Self>,
20971        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20972    ) {
20973        if ranges.is_empty() {
20974            return;
20975        }
20976
20977        self.display_map.update(cx, update);
20978
20979        if auto_scroll {
20980            self.request_autoscroll(Autoscroll::fit(), cx);
20981        }
20982
20983        cx.notify();
20984        self.scrollbar_marker_state.dirty = true;
20985        self.active_indent_guides_state.dirty = true;
20986    }
20987
20988    pub fn update_renderer_widths(
20989        &mut self,
20990        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20991        cx: &mut Context<Self>,
20992    ) -> bool {
20993        self.display_map
20994            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20995    }
20996
20997    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20998        self.display_map.read(cx).fold_placeholder.clone()
20999    }
21000
21001    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
21002        self.buffer.update(cx, |buffer, cx| {
21003            buffer.set_all_diff_hunks_expanded(cx);
21004        });
21005    }
21006
21007    pub fn expand_all_diff_hunks(
21008        &mut self,
21009        _: &ExpandAllDiffHunks,
21010        _window: &mut Window,
21011        cx: &mut Context<Self>,
21012    ) {
21013        self.buffer.update(cx, |buffer, cx| {
21014            buffer.expand_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
21015        });
21016    }
21017
21018    pub fn collapse_all_diff_hunks(
21019        &mut self,
21020        _: &CollapseAllDiffHunks,
21021        _window: &mut Window,
21022        cx: &mut Context<Self>,
21023    ) {
21024        self.buffer.update(cx, |buffer, cx| {
21025            buffer.collapse_diff_hunks(vec![Anchor::Min..Anchor::Max], cx)
21026        });
21027    }
21028
21029    pub fn toggle_selected_diff_hunks(
21030        &mut self,
21031        _: &ToggleSelectedDiffHunks,
21032        _window: &mut Window,
21033        cx: &mut Context<Self>,
21034    ) {
21035        let ranges: Vec<_> = self
21036            .selections
21037            .disjoint_anchors()
21038            .iter()
21039            .map(|s| s.range())
21040            .collect();
21041        self.toggle_diff_hunks_in_ranges(ranges, cx);
21042    }
21043
21044    pub fn diff_hunks_in_ranges<'a>(
21045        &'a self,
21046        ranges: &'a [Range<Anchor>],
21047        buffer: &'a MultiBufferSnapshot,
21048    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
21049        ranges.iter().flat_map(move |range| {
21050            let end_excerpt = buffer.excerpt_containing(range.end..range.end);
21051            let range = range.to_point(buffer);
21052            let mut peek_end = range.end;
21053            if range.end.row < buffer.max_row().0 {
21054                peek_end = Point::new(range.end.row + 1, 0);
21055            }
21056            buffer
21057                .diff_hunks_in_range(range.start..peek_end)
21058                .filter(move |hunk| {
21059                    if let Some((_, excerpt_range)) = &end_excerpt
21060                        && let Some(end_anchor) =
21061                            buffer.anchor_in_excerpt(excerpt_range.context.end)
21062                        && let Some(hunk_end_anchor) =
21063                            buffer.anchor_in_excerpt(hunk.excerpt_range.context.end)
21064                        && hunk_end_anchor.cmp(&end_anchor, buffer).is_gt()
21065                    {
21066                        false
21067                    } else {
21068                        true
21069                    }
21070                })
21071        })
21072    }
21073
21074    pub fn has_stageable_diff_hunks_in_ranges(
21075        &self,
21076        ranges: &[Range<Anchor>],
21077        snapshot: &MultiBufferSnapshot,
21078    ) -> bool {
21079        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
21080        hunks.any(|hunk| hunk.status().has_secondary_hunk())
21081    }
21082
21083    pub fn toggle_staged_selected_diff_hunks(
21084        &mut self,
21085        _: &::git::ToggleStaged,
21086        _: &mut Window,
21087        cx: &mut Context<Self>,
21088    ) {
21089        let snapshot = self.buffer.read(cx).snapshot(cx);
21090        let ranges: Vec<_> = self
21091            .selections
21092            .disjoint_anchors()
21093            .iter()
21094            .map(|s| s.range())
21095            .collect();
21096        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
21097        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21098    }
21099
21100    pub fn set_render_diff_hunk_controls(
21101        &mut self,
21102        render_diff_hunk_controls: RenderDiffHunkControlsFn,
21103        cx: &mut Context<Self>,
21104    ) {
21105        self.render_diff_hunk_controls = render_diff_hunk_controls;
21106        cx.notify();
21107    }
21108
21109    pub fn stage_and_next(
21110        &mut self,
21111        _: &::git::StageAndNext,
21112        window: &mut Window,
21113        cx: &mut Context<Self>,
21114    ) {
21115        self.do_stage_or_unstage_and_next(true, window, cx);
21116    }
21117
21118    pub fn unstage_and_next(
21119        &mut self,
21120        _: &::git::UnstageAndNext,
21121        window: &mut Window,
21122        cx: &mut Context<Self>,
21123    ) {
21124        self.do_stage_or_unstage_and_next(false, window, cx);
21125    }
21126
21127    pub fn stage_or_unstage_diff_hunks(
21128        &mut self,
21129        stage: bool,
21130        ranges: Vec<Range<Anchor>>,
21131        cx: &mut Context<Self>,
21132    ) {
21133        if self.delegate_stage_and_restore {
21134            let snapshot = self.buffer.read(cx).snapshot(cx);
21135            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
21136            if !hunks.is_empty() {
21137                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
21138            }
21139            return;
21140        }
21141        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
21142        cx.spawn(async move |this, cx| {
21143            task.await?;
21144            this.update(cx, |this, cx| {
21145                let snapshot = this.buffer.read(cx).snapshot(cx);
21146                let chunk_by = this
21147                    .diff_hunks_in_ranges(&ranges, &snapshot)
21148                    .chunk_by(|hunk| hunk.buffer_id);
21149                for (buffer_id, hunks) in &chunk_by {
21150                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
21151                }
21152            })
21153        })
21154        .detach_and_log_err(cx);
21155    }
21156
21157    fn save_buffers_for_ranges_if_needed(
21158        &mut self,
21159        ranges: &[Range<Anchor>],
21160        cx: &mut Context<Editor>,
21161    ) -> Task<Result<()>> {
21162        let multibuffer = self.buffer.read(cx);
21163        let snapshot = multibuffer.read(cx);
21164        let buffer_ids: HashSet<_> = ranges
21165            .iter()
21166            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
21167            .collect();
21168        drop(snapshot);
21169
21170        let mut buffers = HashSet::default();
21171        for buffer_id in buffer_ids {
21172            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
21173                let buffer = buffer_entity.read(cx);
21174                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
21175                {
21176                    buffers.insert(buffer_entity);
21177                }
21178            }
21179        }
21180
21181        if let Some(project) = &self.project {
21182            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
21183        } else {
21184            Task::ready(Ok(()))
21185        }
21186    }
21187
21188    fn do_stage_or_unstage_and_next(
21189        &mut self,
21190        stage: bool,
21191        window: &mut Window,
21192        cx: &mut Context<Self>,
21193    ) {
21194        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
21195
21196        if ranges.iter().any(|range| range.start != range.end) {
21197            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21198            return;
21199        }
21200
21201        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
21202
21203        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
21204        let wrap_around = !all_diff_hunks_expanded;
21205        let snapshot = self.snapshot(window, cx);
21206        let position = self
21207            .selections
21208            .newest::<Point>(&snapshot.display_snapshot)
21209            .head();
21210
21211        self.go_to_hunk_before_or_after_position(
21212            &snapshot,
21213            position,
21214            Direction::Next,
21215            wrap_around,
21216            window,
21217            cx,
21218        );
21219    }
21220
21221    pub(crate) fn do_stage_or_unstage(
21222        &self,
21223        stage: bool,
21224        buffer_id: BufferId,
21225        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
21226        cx: &mut App,
21227    ) -> Option<()> {
21228        let project = self.project()?;
21229        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
21230        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
21231        let buffer_snapshot = buffer.read(cx).snapshot();
21232        let file_exists = buffer_snapshot
21233            .file()
21234            .is_some_and(|file| file.disk_state().exists());
21235        diff.update(cx, |diff, cx| {
21236            diff.stage_or_unstage_hunks(
21237                stage,
21238                &hunks
21239                    .map(|hunk| buffer_diff::DiffHunk {
21240                        buffer_range: hunk.buffer_range,
21241                        // We don't need to pass in word diffs here because they're only used for rendering and
21242                        // this function changes internal state
21243                        base_word_diffs: Vec::default(),
21244                        buffer_word_diffs: Vec::default(),
21245                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
21246                            ..hunk.diff_base_byte_range.end.0,
21247                        secondary_status: hunk.status.secondary,
21248                        range: Point::zero()..Point::zero(), // unused
21249                    })
21250                    .collect::<Vec<_>>(),
21251                &buffer_snapshot,
21252                file_exists,
21253                cx,
21254            )
21255        });
21256        None
21257    }
21258
21259    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
21260        let ranges: Vec<_> = self
21261            .selections
21262            .disjoint_anchors()
21263            .iter()
21264            .map(|s| s.range())
21265            .collect();
21266        self.buffer
21267            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
21268    }
21269
21270    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
21271        self.buffer.update(cx, |buffer, cx| {
21272            let ranges = vec![Anchor::Min..Anchor::Max];
21273            if !buffer.all_diff_hunks_expanded()
21274                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
21275            {
21276                buffer.collapse_diff_hunks(ranges, cx);
21277                true
21278            } else {
21279                false
21280            }
21281        })
21282    }
21283
21284    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
21285        if self.buffer.read(cx).all_diff_hunks_expanded() {
21286            return true;
21287        }
21288        let ranges = vec![Anchor::Min..Anchor::Max];
21289        self.buffer
21290            .read(cx)
21291            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
21292    }
21293
21294    fn toggle_diff_hunks_in_ranges(
21295        &mut self,
21296        ranges: Vec<Range<Anchor>>,
21297        cx: &mut Context<Editor>,
21298    ) {
21299        self.buffer.update(cx, |buffer, cx| {
21300            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
21301            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
21302        })
21303    }
21304
21305    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
21306        self.buffer.update(cx, |buffer, cx| {
21307            buffer.toggle_single_diff_hunk(range, cx);
21308        })
21309    }
21310
21311    pub(crate) fn apply_all_diff_hunks(
21312        &mut self,
21313        _: &ApplyAllDiffHunks,
21314        window: &mut Window,
21315        cx: &mut Context<Self>,
21316    ) {
21317        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21318
21319        let buffers = self.buffer.read(cx).all_buffers();
21320        for branch_buffer in buffers {
21321            branch_buffer.update(cx, |branch_buffer, cx| {
21322                branch_buffer.merge_into_base(Vec::new(), cx);
21323            });
21324        }
21325
21326        if let Some(project) = self.project.clone() {
21327            self.save(
21328                SaveOptions {
21329                    format: true,
21330                    autosave: false,
21331                },
21332                project,
21333                window,
21334                cx,
21335            )
21336            .detach_and_log_err(cx);
21337        }
21338    }
21339
21340    pub(crate) fn apply_selected_diff_hunks(
21341        &mut self,
21342        _: &ApplyDiffHunk,
21343        window: &mut Window,
21344        cx: &mut Context<Self>,
21345    ) {
21346        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
21347        let snapshot = self.snapshot(window, cx);
21348        let hunks = snapshot.hunks_for_ranges(
21349            self.selections
21350                .all(&snapshot.display_snapshot)
21351                .into_iter()
21352                .map(|selection| selection.range()),
21353        );
21354        let mut ranges_by_buffer = HashMap::default();
21355        self.transact(window, cx, |editor, _window, cx| {
21356            for hunk in hunks {
21357                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
21358                    ranges_by_buffer
21359                        .entry(buffer.clone())
21360                        .or_insert_with(Vec::new)
21361                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
21362                }
21363            }
21364
21365            for (buffer, ranges) in ranges_by_buffer {
21366                buffer.update(cx, |buffer, cx| {
21367                    buffer.merge_into_base(ranges, cx);
21368                });
21369            }
21370        });
21371
21372        if let Some(project) = self.project.clone() {
21373            self.save(
21374                SaveOptions {
21375                    format: true,
21376                    autosave: false,
21377                },
21378                project,
21379                window,
21380                cx,
21381            )
21382            .detach_and_log_err(cx);
21383        }
21384    }
21385
21386    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
21387        if hovered != self.gutter_hovered {
21388            self.gutter_hovered = hovered;
21389            cx.notify();
21390        }
21391    }
21392
21393    pub fn insert_blocks(
21394        &mut self,
21395        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
21396        autoscroll: Option<Autoscroll>,
21397        cx: &mut Context<Self>,
21398    ) -> Vec<CustomBlockId> {
21399        let blocks = self
21400            .display_map
21401            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
21402        if let Some(autoscroll) = autoscroll {
21403            self.request_autoscroll(autoscroll, cx);
21404        }
21405        cx.notify();
21406        blocks
21407    }
21408
21409    pub fn resize_blocks(
21410        &mut self,
21411        heights: HashMap<CustomBlockId, u32>,
21412        autoscroll: Option<Autoscroll>,
21413        cx: &mut Context<Self>,
21414    ) {
21415        self.display_map
21416            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
21417        if let Some(autoscroll) = autoscroll {
21418            self.request_autoscroll(autoscroll, cx);
21419        }
21420        cx.notify();
21421    }
21422
21423    pub fn replace_blocks(
21424        &mut self,
21425        renderers: HashMap<CustomBlockId, RenderBlock>,
21426        autoscroll: Option<Autoscroll>,
21427        cx: &mut Context<Self>,
21428    ) {
21429        self.display_map
21430            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
21431        if let Some(autoscroll) = autoscroll {
21432            self.request_autoscroll(autoscroll, cx);
21433        }
21434        cx.notify();
21435    }
21436
21437    pub fn remove_blocks(
21438        &mut self,
21439        block_ids: HashSet<CustomBlockId>,
21440        autoscroll: Option<Autoscroll>,
21441        cx: &mut Context<Self>,
21442    ) {
21443        self.display_map.update(cx, |display_map, cx| {
21444            display_map.remove_blocks(block_ids, cx)
21445        });
21446        if let Some(autoscroll) = autoscroll {
21447            self.request_autoscroll(autoscroll, cx);
21448        }
21449        cx.notify();
21450    }
21451
21452    pub fn row_for_block(
21453        &self,
21454        block_id: CustomBlockId,
21455        cx: &mut Context<Self>,
21456    ) -> Option<DisplayRow> {
21457        self.display_map
21458            .update(cx, |map, cx| map.row_for_block(block_id, cx))
21459    }
21460
21461    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
21462        self.focused_block = Some(focused_block);
21463    }
21464
21465    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
21466        self.focused_block.take()
21467    }
21468
21469    pub fn insert_creases(
21470        &mut self,
21471        creases: impl IntoIterator<Item = Crease<Anchor>>,
21472        cx: &mut Context<Self>,
21473    ) -> Vec<CreaseId> {
21474        self.display_map
21475            .update(cx, |map, cx| map.insert_creases(creases, cx))
21476    }
21477
21478    pub fn remove_creases(
21479        &mut self,
21480        ids: impl IntoIterator<Item = CreaseId>,
21481        cx: &mut Context<Self>,
21482    ) -> Vec<(CreaseId, Range<Anchor>)> {
21483        self.display_map
21484            .update(cx, |map, cx| map.remove_creases(ids, cx))
21485    }
21486
21487    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
21488        self.display_map
21489            .update(cx, |map, cx| map.snapshot(cx))
21490            .longest_row()
21491    }
21492
21493    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
21494        self.display_map
21495            .update(cx, |map, cx| map.snapshot(cx))
21496            .max_point()
21497    }
21498
21499    pub fn text(&self, cx: &App) -> String {
21500        self.buffer.read(cx).read(cx).text()
21501    }
21502
21503    pub fn is_empty(&self, cx: &App) -> bool {
21504        self.buffer.read(cx).read(cx).is_empty()
21505    }
21506
21507    pub fn text_option(&self, cx: &App) -> Option<String> {
21508        let text = self.text(cx);
21509        let text = text.trim();
21510
21511        if text.is_empty() {
21512            return None;
21513        }
21514
21515        Some(text.to_string())
21516    }
21517
21518    pub fn set_text(
21519        &mut self,
21520        text: impl Into<Arc<str>>,
21521        window: &mut Window,
21522        cx: &mut Context<Self>,
21523    ) {
21524        self.transact(window, cx, |this, _, cx| {
21525            this.buffer
21526                .read(cx)
21527                .as_singleton()
21528                .expect("you can only call set_text on editors for singleton buffers")
21529                .update(cx, |buffer, cx| buffer.set_text(text, cx));
21530        });
21531    }
21532
21533    pub fn display_text(&self, cx: &mut App) -> String {
21534        self.display_map
21535            .update(cx, |map, cx| map.snapshot(cx))
21536            .text()
21537    }
21538
21539    fn create_minimap(
21540        &self,
21541        minimap_settings: MinimapSettings,
21542        window: &mut Window,
21543        cx: &mut Context<Self>,
21544    ) -> Option<Entity<Self>> {
21545        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
21546            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
21547    }
21548
21549    fn initialize_new_minimap(
21550        &self,
21551        minimap_settings: MinimapSettings,
21552        window: &mut Window,
21553        cx: &mut Context<Self>,
21554    ) -> Entity<Self> {
21555        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
21556        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
21557
21558        let mut minimap = Editor::new_internal(
21559            EditorMode::Minimap {
21560                parent: cx.weak_entity(),
21561            },
21562            self.buffer.clone(),
21563            None,
21564            Some(self.display_map.clone()),
21565            window,
21566            cx,
21567        );
21568        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
21569        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
21570        minimap.scroll_manager.clone_state(
21571            &self.scroll_manager,
21572            &my_snapshot,
21573            &minimap_snapshot,
21574            cx,
21575        );
21576        minimap.set_text_style_refinement(TextStyleRefinement {
21577            font_size: Some(MINIMAP_FONT_SIZE),
21578            font_weight: Some(MINIMAP_FONT_WEIGHT),
21579            font_family: Some(MINIMAP_FONT_FAMILY),
21580            ..Default::default()
21581        });
21582        minimap.update_minimap_configuration(minimap_settings, cx);
21583        cx.new(|_| minimap)
21584    }
21585
21586    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
21587        let current_line_highlight = minimap_settings
21588            .current_line_highlight
21589            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
21590        self.set_current_line_highlight(Some(current_line_highlight));
21591    }
21592
21593    pub fn minimap(&self) -> Option<&Entity<Self>> {
21594        self.minimap
21595            .as_ref()
21596            .filter(|_| self.minimap_visibility.visible())
21597    }
21598
21599    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
21600        let mut wrap_guides = smallvec![];
21601
21602        if self.show_wrap_guides == Some(false) {
21603            return wrap_guides;
21604        }
21605
21606        let settings = self.buffer.read(cx).language_settings(cx);
21607        if settings.show_wrap_guides {
21608            match self.soft_wrap_mode(cx) {
21609                SoftWrap::Column(soft_wrap) => {
21610                    wrap_guides.push((soft_wrap as usize, true));
21611                }
21612                SoftWrap::Bounded(soft_wrap) => {
21613                    wrap_guides.push((soft_wrap as usize, true));
21614                }
21615                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
21616            }
21617            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
21618        }
21619
21620        wrap_guides
21621    }
21622
21623    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
21624        let settings = self.buffer.read(cx).language_settings(cx);
21625        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
21626        match mode {
21627            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
21628                SoftWrap::None
21629            }
21630            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
21631            language_settings::SoftWrap::PreferredLineLength => {
21632                SoftWrap::Column(settings.preferred_line_length)
21633            }
21634            language_settings::SoftWrap::Bounded => {
21635                SoftWrap::Bounded(settings.preferred_line_length)
21636            }
21637        }
21638    }
21639
21640    pub fn set_soft_wrap_mode(
21641        &mut self,
21642        mode: language_settings::SoftWrap,
21643        cx: &mut Context<Self>,
21644    ) {
21645        self.soft_wrap_mode_override = Some(mode);
21646        cx.notify();
21647    }
21648
21649    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
21650        self.hard_wrap = hard_wrap;
21651        cx.notify();
21652    }
21653
21654    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
21655        self.text_style_refinement = Some(style);
21656    }
21657
21658    /// called by the Element so we know what style we were most recently rendered with.
21659    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
21660        // We intentionally do not inform the display map about the minimap style
21661        // so that wrapping is not recalculated and stays consistent for the editor
21662        // and its linked minimap.
21663        if !self.mode.is_minimap() {
21664            let font = style.text.font();
21665            let font_size = style.text.font_size.to_pixels(window.rem_size());
21666            let display_map = self
21667                .placeholder_display_map
21668                .as_ref()
21669                .filter(|_| self.is_empty(cx))
21670                .unwrap_or(&self.display_map);
21671
21672            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
21673        }
21674        self.style = Some(style);
21675    }
21676
21677    pub fn style(&mut self, cx: &App) -> &EditorStyle {
21678        if self.style.is_none() {
21679            self.style = Some(self.create_style(cx));
21680        }
21681        self.style.as_ref().unwrap()
21682    }
21683
21684    // Called by the element. This method is not designed to be called outside of the editor
21685    // element's layout code because it does not notify when rewrapping is computed synchronously.
21686    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
21687        if self.is_empty(cx) {
21688            self.placeholder_display_map
21689                .as_ref()
21690                .map_or(false, |display_map| {
21691                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
21692                })
21693        } else {
21694            self.display_map
21695                .update(cx, |map, cx| map.set_wrap_width(width, cx))
21696        }
21697    }
21698
21699    pub fn set_soft_wrap(&mut self) {
21700        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
21701    }
21702
21703    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
21704        if self.soft_wrap_mode_override.is_some() {
21705            self.soft_wrap_mode_override.take();
21706        } else {
21707            let soft_wrap = match self.soft_wrap_mode(cx) {
21708                SoftWrap::GitDiff => return,
21709                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
21710                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
21711                    language_settings::SoftWrap::None
21712                }
21713            };
21714            self.soft_wrap_mode_override = Some(soft_wrap);
21715        }
21716        cx.notify();
21717    }
21718
21719    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
21720        let Some(workspace) = self.workspace() else {
21721            return;
21722        };
21723        let fs = workspace.read(cx).app_state().fs.clone();
21724        let current_show = TabBarSettings::get_global(cx).show;
21725        update_settings_file(fs, cx, move |setting, _| {
21726            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
21727        });
21728    }
21729
21730    pub fn toggle_indent_guides(
21731        &mut self,
21732        _: &ToggleIndentGuides,
21733        _: &mut Window,
21734        cx: &mut Context<Self>,
21735    ) {
21736        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
21737            self.buffer
21738                .read(cx)
21739                .language_settings(cx)
21740                .indent_guides
21741                .enabled
21742        });
21743        self.show_indent_guides = Some(!currently_enabled);
21744        cx.notify();
21745    }
21746
21747    fn should_show_indent_guides(&self) -> Option<bool> {
21748        self.show_indent_guides
21749    }
21750
21751    pub fn disable_indent_guides_for_buffer(
21752        &mut self,
21753        buffer_id: BufferId,
21754        cx: &mut Context<Self>,
21755    ) {
21756        self.buffers_with_disabled_indent_guides.insert(buffer_id);
21757        cx.notify();
21758    }
21759
21760    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
21761        self.buffers_with_disabled_indent_guides
21762            .contains(&buffer_id)
21763    }
21764
21765    pub fn toggle_line_numbers(
21766        &mut self,
21767        _: &ToggleLineNumbers,
21768        _: &mut Window,
21769        cx: &mut Context<Self>,
21770    ) {
21771        let mut editor_settings = EditorSettings::get_global(cx).clone();
21772        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
21773        EditorSettings::override_global(editor_settings, cx);
21774    }
21775
21776    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21777        if let Some(show_line_numbers) = self.show_line_numbers {
21778            return show_line_numbers;
21779        }
21780        EditorSettings::get_global(cx).gutter.line_numbers
21781    }
21782
21783    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21784        match (
21785            self.use_relative_line_numbers,
21786            EditorSettings::get_global(cx).relative_line_numbers,
21787        ) {
21788            (None, setting) => setting,
21789            (Some(false), _) => RelativeLineNumbers::Disabled,
21790            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21791            (Some(true), _) => RelativeLineNumbers::Enabled,
21792        }
21793    }
21794
21795    pub fn toggle_relative_line_numbers(
21796        &mut self,
21797        _: &ToggleRelativeLineNumbers,
21798        _: &mut Window,
21799        cx: &mut Context<Self>,
21800    ) {
21801        let is_relative = self.relative_line_numbers(cx);
21802        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21803    }
21804
21805    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21806        self.use_relative_line_numbers = is_relative;
21807        cx.notify();
21808    }
21809
21810    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21811        self.show_gutter = show_gutter;
21812        cx.notify();
21813    }
21814
21815    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21816        self.show_scrollbars = ScrollbarAxes {
21817            horizontal: show,
21818            vertical: show,
21819        };
21820        cx.notify();
21821    }
21822
21823    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21824        self.show_scrollbars.vertical = show;
21825        cx.notify();
21826    }
21827
21828    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21829        self.show_scrollbars.horizontal = show;
21830        cx.notify();
21831    }
21832
21833    pub fn set_minimap_visibility(
21834        &mut self,
21835        minimap_visibility: MinimapVisibility,
21836        window: &mut Window,
21837        cx: &mut Context<Self>,
21838    ) {
21839        if self.minimap_visibility != minimap_visibility {
21840            if minimap_visibility.visible() && self.minimap.is_none() {
21841                let minimap_settings = EditorSettings::get_global(cx).minimap;
21842                self.minimap =
21843                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21844            }
21845            self.minimap_visibility = minimap_visibility;
21846            cx.notify();
21847        }
21848    }
21849
21850    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21851        self.set_show_scrollbars(false, cx);
21852        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21853    }
21854
21855    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21856        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21857    }
21858
21859    /// Normally the text in full mode and auto height editors is padded on the
21860    /// left side by roughly half a character width for improved hit testing.
21861    ///
21862    /// Use this method to disable this for cases where this is not wanted (e.g.
21863    /// if you want to align the editor text with some other text above or below)
21864    /// or if you want to add this padding to single-line editors.
21865    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21866        self.offset_content = offset_content;
21867        cx.notify();
21868    }
21869
21870    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21871        self.show_line_numbers = Some(show_line_numbers);
21872        cx.notify();
21873    }
21874
21875    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21876        self.disable_expand_excerpt_buttons = true;
21877        cx.notify();
21878    }
21879
21880    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21881        self.number_deleted_lines = number;
21882        cx.notify();
21883    }
21884
21885    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21886        self.delegate_expand_excerpts = delegate;
21887    }
21888
21889    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21890        self.delegate_stage_and_restore = delegate;
21891    }
21892
21893    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21894        self.delegate_open_excerpts = delegate;
21895    }
21896
21897    pub fn set_on_local_selections_changed(
21898        &mut self,
21899        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21900    ) {
21901        self.on_local_selections_changed = callback;
21902    }
21903
21904    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21905        self.suppress_selection_callback = suppress;
21906    }
21907
21908    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21909        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21910        cx.notify();
21911    }
21912
21913    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21914        self.show_code_actions = Some(show_code_actions);
21915        cx.notify();
21916    }
21917
21918    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21919        self.show_runnables = Some(show_runnables);
21920        cx.notify();
21921    }
21922
21923    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21924        self.show_breakpoints = Some(show_breakpoints);
21925        cx.notify();
21926    }
21927
21928    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21929        self.show_diff_review_button = show;
21930        cx.notify();
21931    }
21932
21933    pub fn show_diff_review_button(&self) -> bool {
21934        self.show_diff_review_button
21935    }
21936
21937    pub fn render_diff_review_button(
21938        &self,
21939        display_row: DisplayRow,
21940        width: Pixels,
21941        cx: &mut Context<Self>,
21942    ) -> impl IntoElement {
21943        let text_color = cx.theme().colors().text;
21944        let icon_color = cx.theme().colors().icon_accent;
21945
21946        h_flex()
21947            .id("diff_review_button")
21948            .cursor_pointer()
21949            .w(width - px(1.))
21950            .h(relative(0.9))
21951            .justify_center()
21952            .rounded_sm()
21953            .border_1()
21954            .border_color(text_color.opacity(0.1))
21955            .bg(text_color.opacity(0.15))
21956            .hover(|s| {
21957                s.bg(icon_color.opacity(0.4))
21958                    .border_color(icon_color.opacity(0.5))
21959            })
21960            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21961            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21962            .on_mouse_down(
21963                gpui::MouseButton::Left,
21964                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21965                    editor.start_diff_review_drag(display_row, window, cx);
21966                }),
21967            )
21968    }
21969
21970    pub fn start_diff_review_drag(
21971        &mut self,
21972        display_row: DisplayRow,
21973        window: &mut Window,
21974        cx: &mut Context<Self>,
21975    ) {
21976        let snapshot = self.snapshot(window, cx);
21977        let point = snapshot
21978            .display_snapshot
21979            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21980        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21981        self.diff_review_drag_state = Some(DiffReviewDragState {
21982            start_anchor: anchor,
21983            current_anchor: anchor,
21984        });
21985        cx.notify();
21986    }
21987
21988    pub fn update_diff_review_drag(
21989        &mut self,
21990        display_row: DisplayRow,
21991        window: &mut Window,
21992        cx: &mut Context<Self>,
21993    ) {
21994        if self.diff_review_drag_state.is_none() {
21995            return;
21996        }
21997        let snapshot = self.snapshot(window, cx);
21998        let point = snapshot
21999            .display_snapshot
22000            .display_point_to_point(display_row.as_display_point(), Bias::Left);
22001        let anchor = snapshot.buffer_snapshot().anchor_before(point);
22002        if let Some(drag_state) = &mut self.diff_review_drag_state {
22003            drag_state.current_anchor = anchor;
22004            cx.notify();
22005        }
22006    }
22007
22008    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22009        if let Some(drag_state) = self.diff_review_drag_state.take() {
22010            let snapshot = self.snapshot(window, cx);
22011            let range = drag_state.row_range(&snapshot.display_snapshot);
22012            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
22013        }
22014        cx.notify();
22015    }
22016
22017    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
22018        self.diff_review_drag_state = None;
22019        cx.notify();
22020    }
22021
22022    /// Calculates the appropriate block height for the diff review overlay.
22023    /// Height is in lines: 2 for input row, 1 for header when comments exist,
22024    /// and 2 lines per comment when expanded.
22025    fn calculate_overlay_height(
22026        &self,
22027        hunk_key: &DiffHunkKey,
22028        comments_expanded: bool,
22029        snapshot: &MultiBufferSnapshot,
22030    ) -> u32 {
22031        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
22032        let base_height: u32 = 2; // Input row with avatar and buttons
22033
22034        if comment_count == 0 {
22035            base_height
22036        } else if comments_expanded {
22037            // Header (1 line) + 2 lines per comment
22038            base_height + 1 + (comment_count as u32 * 2)
22039        } else {
22040            // Just header when collapsed
22041            base_height + 1
22042        }
22043    }
22044
22045    pub fn show_diff_review_overlay(
22046        &mut self,
22047        display_range: Range<DisplayRow>,
22048        window: &mut Window,
22049        cx: &mut Context<Self>,
22050    ) {
22051        let Range { start, end } = display_range.sorted();
22052
22053        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
22054        let editor_snapshot = self.snapshot(window, cx);
22055
22056        // Convert display rows to multibuffer points
22057        let start_point = editor_snapshot
22058            .display_snapshot
22059            .display_point_to_point(start.as_display_point(), Bias::Left);
22060        let end_point = editor_snapshot
22061            .display_snapshot
22062            .display_point_to_point(end.as_display_point(), Bias::Left);
22063        let end_multi_buffer_row = MultiBufferRow(end_point.row);
22064
22065        // Create anchor range for the selected lines (start of first line to end of last line)
22066        let line_end = Point::new(
22067            end_point.row,
22068            buffer_snapshot.line_len(end_multi_buffer_row),
22069        );
22070        let anchor_range =
22071            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
22072
22073        // Compute the hunk key for this display row
22074        let file_path = buffer_snapshot
22075            .file_at(start_point)
22076            .map(|file: &Arc<dyn language::File>| file.path().clone())
22077            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
22078        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
22079        let new_hunk_key = DiffHunkKey {
22080            file_path,
22081            hunk_start_anchor,
22082        };
22083
22084        // Check if we already have an overlay for this hunk
22085        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
22086            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
22087        }) {
22088            // Just focus the existing overlay's prompt editor
22089            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
22090            window.focus(&focus_handle, cx);
22091            return;
22092        }
22093
22094        // Dismiss overlays that have no comments for their hunks
22095        self.dismiss_overlays_without_comments(cx);
22096
22097        // Get the current user's avatar URI from the project's user_store
22098        let user_avatar_uri = self.project.as_ref().and_then(|project| {
22099            let user_store = project.read(cx).user_store();
22100            user_store
22101                .read(cx)
22102                .current_user()
22103                .map(|user| user.avatar_uri.clone())
22104        });
22105
22106        // Create anchor at the end of the last row so the block appears immediately below it
22107        // Use multibuffer coordinates for anchor creation
22108        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
22109        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
22110
22111        // Use the hunk key we already computed
22112        let hunk_key = new_hunk_key;
22113
22114        // Create the prompt editor for the review input
22115        let prompt_editor = cx.new(|cx| {
22116            let mut editor = Editor::single_line(window, cx);
22117            editor.set_placeholder_text("Add a review comment...", window, cx);
22118            editor
22119        });
22120
22121        // Register the Newline action on the prompt editor to submit the review
22122        let parent_editor = cx.entity().downgrade();
22123        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
22124            prompt_editor.register_action({
22125                let parent_editor = parent_editor.clone();
22126                move |_: &crate::actions::Newline, window, cx| {
22127                    if let Some(editor) = parent_editor.upgrade() {
22128                        editor.update(cx, |editor, cx| {
22129                            editor.submit_diff_review_comment(window, cx);
22130                        });
22131                    }
22132                }
22133            })
22134        });
22135
22136        // Calculate initial height based on existing comments for this hunk
22137        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
22138
22139        // Create the overlay block
22140        let prompt_editor_for_render = prompt_editor.clone();
22141        let hunk_key_for_render = hunk_key.clone();
22142        let editor_handle = cx.entity().downgrade();
22143        let block = BlockProperties {
22144            style: BlockStyle::Sticky,
22145            placement: BlockPlacement::Below(anchor),
22146            height: Some(initial_height),
22147            render: Arc::new(move |cx| {
22148                Self::render_diff_review_overlay(
22149                    &prompt_editor_for_render,
22150                    &hunk_key_for_render,
22151                    &editor_handle,
22152                    cx,
22153                )
22154            }),
22155            priority: 0,
22156        };
22157
22158        let block_ids = self.insert_blocks([block], None, cx);
22159        let Some(block_id) = block_ids.into_iter().next() else {
22160            log::error!("Failed to insert diff review overlay block");
22161            return;
22162        };
22163
22164        self.diff_review_overlays.push(DiffReviewOverlay {
22165            anchor_range,
22166            block_id,
22167            prompt_editor: prompt_editor.clone(),
22168            hunk_key,
22169            comments_expanded: true,
22170            inline_edit_editors: HashMap::default(),
22171            inline_edit_subscriptions: HashMap::default(),
22172            user_avatar_uri,
22173            _subscription: subscription,
22174        });
22175
22176        // Focus the prompt editor
22177        let focus_handle = prompt_editor.focus_handle(cx);
22178        window.focus(&focus_handle, cx);
22179
22180        cx.notify();
22181    }
22182
22183    /// Dismisses all diff review overlays.
22184    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
22185        if self.diff_review_overlays.is_empty() {
22186            return;
22187        }
22188        let block_ids: HashSet<_> = self
22189            .diff_review_overlays
22190            .drain(..)
22191            .map(|overlay| overlay.block_id)
22192            .collect();
22193        self.remove_blocks(block_ids, None, cx);
22194        cx.notify();
22195    }
22196
22197    /// Dismisses overlays that have no comments stored for their hunks.
22198    /// Keeps overlays that have at least one comment.
22199    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
22200        let snapshot = self.buffer.read(cx).snapshot(cx);
22201
22202        // First, compute which overlays have comments (to avoid borrow issues with retain)
22203        let overlays_with_comments: Vec<bool> = self
22204            .diff_review_overlays
22205            .iter()
22206            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
22207            .collect();
22208
22209        // Now collect block IDs to remove and retain overlays
22210        let mut block_ids_to_remove = HashSet::default();
22211        let mut index = 0;
22212        self.diff_review_overlays.retain(|overlay| {
22213            let has_comments = overlays_with_comments[index];
22214            index += 1;
22215            if !has_comments {
22216                block_ids_to_remove.insert(overlay.block_id);
22217            }
22218            has_comments
22219        });
22220
22221        if !block_ids_to_remove.is_empty() {
22222            self.remove_blocks(block_ids_to_remove, None, cx);
22223            cx.notify();
22224        }
22225    }
22226
22227    /// Refreshes the diff review overlay block to update its height and render function.
22228    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
22229    fn refresh_diff_review_overlay_height(
22230        &mut self,
22231        hunk_key: &DiffHunkKey,
22232        _window: &mut Window,
22233        cx: &mut Context<Self>,
22234    ) {
22235        // Extract all needed data from overlay first to avoid borrow conflicts
22236        let snapshot = self.buffer.read(cx).snapshot(cx);
22237        let (comments_expanded, block_id, prompt_editor) = {
22238            let Some(overlay) = self
22239                .diff_review_overlays
22240                .iter()
22241                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22242            else {
22243                return;
22244            };
22245
22246            (
22247                overlay.comments_expanded,
22248                overlay.block_id,
22249                overlay.prompt_editor.clone(),
22250            )
22251        };
22252
22253        // Calculate new height
22254        let snapshot = self.buffer.read(cx).snapshot(cx);
22255        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
22256
22257        // Update the block height using resize_blocks (avoids flicker)
22258        let mut heights = HashMap::default();
22259        heights.insert(block_id, new_height);
22260        self.resize_blocks(heights, None, cx);
22261
22262        // Update the render function using replace_blocks (avoids flicker)
22263        let hunk_key_for_render = hunk_key.clone();
22264        let editor_handle = cx.entity().downgrade();
22265        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
22266            Arc::new(move |cx| {
22267                Self::render_diff_review_overlay(
22268                    &prompt_editor,
22269                    &hunk_key_for_render,
22270                    &editor_handle,
22271                    cx,
22272                )
22273            });
22274
22275        let mut renderers = HashMap::default();
22276        renderers.insert(block_id, render);
22277        self.replace_blocks(renderers, None, cx);
22278    }
22279
22280    /// Action handler for SubmitDiffReviewComment.
22281    pub fn submit_diff_review_comment_action(
22282        &mut self,
22283        _: &SubmitDiffReviewComment,
22284        window: &mut Window,
22285        cx: &mut Context<Self>,
22286    ) {
22287        self.submit_diff_review_comment(window, cx);
22288    }
22289
22290    /// Stores the diff review comment locally.
22291    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
22292    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
22293        // Find the overlay that currently has focus
22294        let overlay_index = self
22295            .diff_review_overlays
22296            .iter()
22297            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
22298        let Some(overlay_index) = overlay_index else {
22299            return;
22300        };
22301        let overlay = &self.diff_review_overlays[overlay_index];
22302
22303        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
22304        if comment_text.is_empty() {
22305            return;
22306        }
22307
22308        let anchor_range = overlay.anchor_range.clone();
22309        let hunk_key = overlay.hunk_key.clone();
22310
22311        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
22312
22313        // Clear the prompt editor but keep the overlay open
22314        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
22315            overlay.prompt_editor.update(cx, |editor, cx| {
22316                editor.clear(window, cx);
22317            });
22318        }
22319
22320        // Refresh the overlay to update the block height for the new comment
22321        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22322
22323        cx.notify();
22324    }
22325
22326    /// Returns the prompt editor for the diff review overlay, if one is active.
22327    /// This is primarily used for testing.
22328    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
22329        self.diff_review_overlays
22330            .first()
22331            .map(|overlay| &overlay.prompt_editor)
22332    }
22333
22334    /// Returns the line range for the first diff review overlay, if one is active.
22335    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
22336    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
22337        let overlay = self.diff_review_overlays.first()?;
22338        let snapshot = self.buffer.read(cx).snapshot(cx);
22339        let start_point = overlay.anchor_range.start.to_point(&snapshot);
22340        let end_point = overlay.anchor_range.end.to_point(&snapshot);
22341        let start_row = snapshot
22342            .point_to_buffer_point(start_point)
22343            .map(|(_, p)| p.row)
22344            .unwrap_or(start_point.row);
22345        let end_row = snapshot
22346            .point_to_buffer_point(end_point)
22347            .map(|(_, p)| p.row)
22348            .unwrap_or(end_point.row);
22349        Some((start_row, end_row))
22350    }
22351
22352    /// Sets whether the comments section is expanded in the diff review overlay.
22353    /// This is primarily used for testing.
22354    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
22355        for overlay in &mut self.diff_review_overlays {
22356            overlay.comments_expanded = expanded;
22357        }
22358        cx.notify();
22359    }
22360
22361    /// Compares two DiffHunkKeys for equality by resolving their anchors.
22362    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
22363        a.file_path == b.file_path
22364            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
22365    }
22366
22367    /// Returns comments for a specific hunk, ordered by creation time.
22368    pub fn comments_for_hunk<'a>(
22369        &'a self,
22370        key: &DiffHunkKey,
22371        snapshot: &MultiBufferSnapshot,
22372    ) -> &'a [StoredReviewComment] {
22373        let key_point = key.hunk_start_anchor.to_point(snapshot);
22374        self.stored_review_comments
22375            .iter()
22376            .find(|(k, _)| {
22377                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22378            })
22379            .map(|(_, comments)| comments.as_slice())
22380            .unwrap_or(&[])
22381    }
22382
22383    /// Returns the total count of stored review comments across all hunks.
22384    pub fn total_review_comment_count(&self) -> usize {
22385        self.stored_review_comments
22386            .iter()
22387            .map(|(_, v)| v.len())
22388            .sum()
22389    }
22390
22391    /// Returns the count of comments for a specific hunk.
22392    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
22393        let key_point = key.hunk_start_anchor.to_point(snapshot);
22394        self.stored_review_comments
22395            .iter()
22396            .find(|(k, _)| {
22397                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
22398            })
22399            .map(|(_, v)| v.len())
22400            .unwrap_or(0)
22401    }
22402
22403    /// Adds a new review comment to a specific hunk.
22404    pub fn add_review_comment(
22405        &mut self,
22406        hunk_key: DiffHunkKey,
22407        comment: String,
22408        anchor_range: Range<Anchor>,
22409        cx: &mut Context<Self>,
22410    ) -> usize {
22411        let id = self.next_review_comment_id;
22412        self.next_review_comment_id += 1;
22413
22414        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
22415
22416        let snapshot = self.buffer.read(cx).snapshot(cx);
22417        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
22418
22419        // Find existing entry for this hunk or add a new one
22420        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
22421            k.file_path == hunk_key.file_path
22422                && k.hunk_start_anchor.to_point(&snapshot) == key_point
22423        }) {
22424            comments.push(stored_comment);
22425        } else {
22426            self.stored_review_comments
22427                .push((hunk_key, vec![stored_comment]));
22428        }
22429
22430        cx.emit(EditorEvent::ReviewCommentsChanged {
22431            total_count: self.total_review_comment_count(),
22432        });
22433        cx.notify();
22434        id
22435    }
22436
22437    /// Removes a review comment by ID from any hunk.
22438    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
22439        for (_, comments) in self.stored_review_comments.iter_mut() {
22440            if let Some(index) = comments.iter().position(|c| c.id == id) {
22441                comments.remove(index);
22442                cx.emit(EditorEvent::ReviewCommentsChanged {
22443                    total_count: self.total_review_comment_count(),
22444                });
22445                cx.notify();
22446                return true;
22447            }
22448        }
22449        false
22450    }
22451
22452    /// Updates a review comment's text by ID.
22453    pub fn update_review_comment(
22454        &mut self,
22455        id: usize,
22456        new_comment: String,
22457        cx: &mut Context<Self>,
22458    ) -> bool {
22459        for (_, comments) in self.stored_review_comments.iter_mut() {
22460            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22461                comment.comment = new_comment;
22462                comment.is_editing = false;
22463                cx.emit(EditorEvent::ReviewCommentsChanged {
22464                    total_count: self.total_review_comment_count(),
22465                });
22466                cx.notify();
22467                return true;
22468            }
22469        }
22470        false
22471    }
22472
22473    /// Sets a comment's editing state.
22474    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
22475        for (_, comments) in self.stored_review_comments.iter_mut() {
22476            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
22477                comment.is_editing = is_editing;
22478                cx.notify();
22479                return;
22480            }
22481        }
22482    }
22483
22484    /// Takes all stored comments from all hunks, clearing the storage.
22485    /// Returns a Vec of (hunk_key, comments) pairs.
22486    pub fn take_all_review_comments(
22487        &mut self,
22488        cx: &mut Context<Self>,
22489    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
22490        // Dismiss all overlays when taking comments (e.g., when sending to agent)
22491        self.dismiss_all_diff_review_overlays(cx);
22492        let comments = std::mem::take(&mut self.stored_review_comments);
22493        // Reset the ID counter since all comments have been taken
22494        self.next_review_comment_id = 0;
22495        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
22496        cx.notify();
22497        comments
22498    }
22499
22500    /// Removes review comments whose anchors are no longer valid or whose
22501    /// associated diff hunks no longer exist.
22502    ///
22503    /// This should be called when the buffer changes to prevent orphaned comments
22504    /// from accumulating.
22505    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
22506        let snapshot = self.buffer.read(cx).snapshot(cx);
22507        let original_count = self.total_review_comment_count();
22508
22509        // Remove comments with invalid hunk anchors
22510        self.stored_review_comments
22511            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
22512
22513        // Also clean up individual comments with invalid anchor ranges
22514        for (_, comments) in &mut self.stored_review_comments {
22515            comments.retain(|comment| {
22516                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
22517            });
22518        }
22519
22520        // Remove empty hunk entries
22521        self.stored_review_comments
22522            .retain(|(_, comments)| !comments.is_empty());
22523
22524        let new_count = self.total_review_comment_count();
22525        if new_count != original_count {
22526            cx.emit(EditorEvent::ReviewCommentsChanged {
22527                total_count: new_count,
22528            });
22529            cx.notify();
22530        }
22531    }
22532
22533    /// Toggles the expanded state of the comments section in the overlay.
22534    pub fn toggle_review_comments_expanded(
22535        &mut self,
22536        _: &ToggleReviewCommentsExpanded,
22537        window: &mut Window,
22538        cx: &mut Context<Self>,
22539    ) {
22540        // Find the overlay that currently has focus, or use the first one
22541        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
22542            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
22543                overlay.comments_expanded = !overlay.comments_expanded;
22544                Some(overlay.hunk_key.clone())
22545            } else {
22546                None
22547            }
22548        });
22549
22550        // If no focused overlay found, toggle the first one
22551        let hunk_key = overlay_info.or_else(|| {
22552            self.diff_review_overlays.first_mut().map(|overlay| {
22553                overlay.comments_expanded = !overlay.comments_expanded;
22554                overlay.hunk_key.clone()
22555            })
22556        });
22557
22558        if let Some(hunk_key) = hunk_key {
22559            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22560            cx.notify();
22561        }
22562    }
22563
22564    /// Handles the EditReviewComment action - sets a comment into editing mode.
22565    pub fn edit_review_comment(
22566        &mut self,
22567        action: &EditReviewComment,
22568        window: &mut Window,
22569        cx: &mut Context<Self>,
22570    ) {
22571        let comment_id = action.id;
22572
22573        // Set the comment to editing mode
22574        self.set_comment_editing(comment_id, true, cx);
22575
22576        // Find the overlay that contains this comment and create an inline editor if needed
22577        // First, find which hunk this comment belongs to
22578        let hunk_key = self
22579            .stored_review_comments
22580            .iter()
22581            .find_map(|(key, comments)| {
22582                if comments.iter().any(|c| c.id == comment_id) {
22583                    Some(key.clone())
22584                } else {
22585                    None
22586                }
22587            });
22588
22589        let snapshot = self.buffer.read(cx).snapshot(cx);
22590        if let Some(hunk_key) = hunk_key {
22591            if let Some(overlay) = self
22592                .diff_review_overlays
22593                .iter_mut()
22594                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22595            {
22596                if let std::collections::hash_map::Entry::Vacant(entry) =
22597                    overlay.inline_edit_editors.entry(comment_id)
22598                {
22599                    // Find the comment text
22600                    let comment_text = self
22601                        .stored_review_comments
22602                        .iter()
22603                        .flat_map(|(_, comments)| comments)
22604                        .find(|c| c.id == comment_id)
22605                        .map(|c| c.comment.clone())
22606                        .unwrap_or_default();
22607
22608                    // Create inline editor
22609                    let parent_editor = cx.entity().downgrade();
22610                    let inline_editor = cx.new(|cx| {
22611                        let mut editor = Editor::single_line(window, cx);
22612                        editor.set_text(&*comment_text, window, cx);
22613                        // Select all text for easy replacement
22614                        editor.select_all(&crate::actions::SelectAll, window, cx);
22615                        editor
22616                    });
22617
22618                    // Register the Newline action to confirm the edit
22619                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
22620                        inline_editor.register_action({
22621                            let parent_editor = parent_editor.clone();
22622                            move |_: &crate::actions::Newline, window, cx| {
22623                                if let Some(editor) = parent_editor.upgrade() {
22624                                    editor.update(cx, |editor, cx| {
22625                                        editor.confirm_edit_review_comment(comment_id, window, cx);
22626                                    });
22627                                }
22628                            }
22629                        })
22630                    });
22631
22632                    // Store the subscription to keep the action handler alive
22633                    overlay
22634                        .inline_edit_subscriptions
22635                        .insert(comment_id, subscription);
22636
22637                    // Focus the inline editor
22638                    let focus_handle = inline_editor.focus_handle(cx);
22639                    window.focus(&focus_handle, cx);
22640
22641                    entry.insert(inline_editor);
22642                }
22643            }
22644        }
22645
22646        cx.notify();
22647    }
22648
22649    /// Confirms an inline edit of a review comment.
22650    pub fn confirm_edit_review_comment(
22651        &mut self,
22652        comment_id: usize,
22653        _window: &mut Window,
22654        cx: &mut Context<Self>,
22655    ) {
22656        // Get the new text from the inline editor
22657        // Find the overlay containing this comment's inline editor
22658        let snapshot = self.buffer.read(cx).snapshot(cx);
22659        let hunk_key = self
22660            .stored_review_comments
22661            .iter()
22662            .find_map(|(key, comments)| {
22663                if comments.iter().any(|c| c.id == comment_id) {
22664                    Some(key.clone())
22665                } else {
22666                    None
22667                }
22668            });
22669
22670        let new_text = hunk_key
22671            .as_ref()
22672            .and_then(|hunk_key| {
22673                self.diff_review_overlays
22674                    .iter()
22675                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
22676            })
22677            .as_ref()
22678            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
22679            .map(|editor| editor.read(cx).text(cx).trim().to_string());
22680
22681        if let Some(new_text) = new_text {
22682            if !new_text.is_empty() {
22683                self.update_review_comment(comment_id, new_text, cx);
22684            }
22685        }
22686
22687        // Remove the inline editor and its subscription
22688        if let Some(hunk_key) = hunk_key {
22689            if let Some(overlay) = self
22690                .diff_review_overlays
22691                .iter_mut()
22692                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22693            {
22694                overlay.inline_edit_editors.remove(&comment_id);
22695                overlay.inline_edit_subscriptions.remove(&comment_id);
22696            }
22697        }
22698
22699        // Clear editing state
22700        self.set_comment_editing(comment_id, false, cx);
22701    }
22702
22703    /// Cancels an inline edit of a review comment.
22704    pub fn cancel_edit_review_comment(
22705        &mut self,
22706        comment_id: usize,
22707        _window: &mut Window,
22708        cx: &mut Context<Self>,
22709    ) {
22710        // Find which hunk this comment belongs to
22711        let hunk_key = self
22712            .stored_review_comments
22713            .iter()
22714            .find_map(|(key, comments)| {
22715                if comments.iter().any(|c| c.id == comment_id) {
22716                    Some(key.clone())
22717                } else {
22718                    None
22719                }
22720            });
22721
22722        // Remove the inline editor and its subscription
22723        if let Some(hunk_key) = hunk_key {
22724            let snapshot = self.buffer.read(cx).snapshot(cx);
22725            if let Some(overlay) = self
22726                .diff_review_overlays
22727                .iter_mut()
22728                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
22729            {
22730                overlay.inline_edit_editors.remove(&comment_id);
22731                overlay.inline_edit_subscriptions.remove(&comment_id);
22732            }
22733        }
22734
22735        // Clear editing state
22736        self.set_comment_editing(comment_id, false, cx);
22737    }
22738
22739    /// Action handler for ConfirmEditReviewComment.
22740    pub fn confirm_edit_review_comment_action(
22741        &mut self,
22742        action: &ConfirmEditReviewComment,
22743        window: &mut Window,
22744        cx: &mut Context<Self>,
22745    ) {
22746        self.confirm_edit_review_comment(action.id, window, cx);
22747    }
22748
22749    /// Action handler for CancelEditReviewComment.
22750    pub fn cancel_edit_review_comment_action(
22751        &mut self,
22752        action: &CancelEditReviewComment,
22753        window: &mut Window,
22754        cx: &mut Context<Self>,
22755    ) {
22756        self.cancel_edit_review_comment(action.id, window, cx);
22757    }
22758
22759    /// Handles the DeleteReviewComment action - removes a comment.
22760    pub fn delete_review_comment(
22761        &mut self,
22762        action: &DeleteReviewComment,
22763        window: &mut Window,
22764        cx: &mut Context<Self>,
22765    ) {
22766        // Get the hunk key before removing the comment
22767        // Find the hunk key from the comment itself
22768        let comment_id = action.id;
22769        let hunk_key = self
22770            .stored_review_comments
22771            .iter()
22772            .find_map(|(key, comments)| {
22773                if comments.iter().any(|c| c.id == comment_id) {
22774                    Some(key.clone())
22775                } else {
22776                    None
22777                }
22778            });
22779
22780        // Also get it from the overlay for refresh purposes
22781        let overlay_hunk_key = self
22782            .diff_review_overlays
22783            .first()
22784            .map(|o| o.hunk_key.clone());
22785
22786        self.remove_review_comment(action.id, cx);
22787
22788        // Refresh the overlay height after removing a comment
22789        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22790            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22791        }
22792    }
22793
22794    fn render_diff_review_overlay(
22795        prompt_editor: &Entity<Editor>,
22796        hunk_key: &DiffHunkKey,
22797        editor_handle: &WeakEntity<Editor>,
22798        cx: &mut BlockContext,
22799    ) -> AnyElement {
22800        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22801            if ranges.is_empty() {
22802                return None;
22803            }
22804            let formatted: Vec<String> = ranges
22805                .iter()
22806                .map(|(start, end)| {
22807                    let start_line = start + 1;
22808                    let end_line = end + 1;
22809                    if start_line == end_line {
22810                        format!("Line {start_line}")
22811                    } else {
22812                        format!("Lines {start_line}-{end_line}")
22813                    }
22814                })
22815                .collect();
22816            // Don't show label for single line in single excerpt
22817            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22818                return None;
22819            }
22820            Some(formatted.join(""))
22821        }
22822
22823        let theme = cx.theme();
22824        let colors = theme.colors();
22825
22826        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22827            editor_handle
22828                .upgrade()
22829                .map(|editor| {
22830                    let editor = editor.read(cx);
22831                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22832                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22833                    let (expanded, editors, avatar_uri, line_ranges) = editor
22834                        .diff_review_overlays
22835                        .iter()
22836                        .find(|overlay| {
22837                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22838                        })
22839                        .map(|o| {
22840                            let start_point = o.anchor_range.start.to_point(&snapshot);
22841                            let end_point = o.anchor_range.end.to_point(&snapshot);
22842                            // Get line ranges per excerpt to detect discontinuities
22843                            let buffer_ranges =
22844                                snapshot.range_to_buffer_ranges(start_point..end_point);
22845                            let ranges: Vec<(u32, u32)> = buffer_ranges
22846                                .iter()
22847                                .map(|(buffer_snapshot, range, _)| {
22848                                    let start = buffer_snapshot.offset_to_point(range.start.0).row;
22849                                    let end = buffer_snapshot.offset_to_point(range.end.0).row;
22850                                    (start, end)
22851                                })
22852                                .collect();
22853                            (
22854                                o.comments_expanded,
22855                                o.inline_edit_editors.clone(),
22856                                o.user_avatar_uri.clone(),
22857                                if ranges.is_empty() {
22858                                    None
22859                                } else {
22860                                    Some(ranges)
22861                                },
22862                            )
22863                        })
22864                        .unwrap_or((true, HashMap::default(), None, None));
22865                    (comments, expanded, editors, avatar_uri, line_ranges)
22866                })
22867                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22868
22869        let comment_count = comments.len();
22870        let avatar_size = px(20.);
22871        let action_icon_size = IconSize::XSmall;
22872
22873        v_flex()
22874            .w_full()
22875            .bg(colors.editor_background)
22876            .border_b_1()
22877            .border_color(colors.border)
22878            .px_2()
22879            .pb_2()
22880            .gap_2()
22881            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22882            .when_some(line_ranges, |el, ranges| {
22883                let label = format_line_ranges(&ranges);
22884                if let Some(label) = label {
22885                    el.child(
22886                        h_flex()
22887                            .w_full()
22888                            .px_2()
22889                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22890                    )
22891                } else {
22892                    el
22893                }
22894            })
22895            // Top row: editable input with user's avatar
22896            .child(
22897                h_flex()
22898                    .w_full()
22899                    .items_center()
22900                    .gap_2()
22901                    .px_2()
22902                    .py_1p5()
22903                    .rounded_md()
22904                    .bg(colors.surface_background)
22905                    .child(
22906                        div()
22907                            .size(avatar_size)
22908                            .flex_shrink_0()
22909                            .rounded_full()
22910                            .overflow_hidden()
22911                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22912                                Avatar::new(avatar_uri.clone())
22913                                    .size(avatar_size)
22914                                    .into_any_element()
22915                            } else {
22916                                Icon::new(IconName::Person)
22917                                    .size(IconSize::Small)
22918                                    .color(ui::Color::Muted)
22919                                    .into_any_element()
22920                            }),
22921                    )
22922                    .child(
22923                        div()
22924                            .flex_1()
22925                            .border_1()
22926                            .border_color(colors.border)
22927                            .rounded_md()
22928                            .bg(colors.editor_background)
22929                            .px_2()
22930                            .py_1()
22931                            .child(prompt_editor.clone()),
22932                    )
22933                    .child(
22934                        h_flex()
22935                            .flex_shrink_0()
22936                            .gap_1()
22937                            .child(
22938                                IconButton::new("diff-review-close", IconName::Close)
22939                                    .icon_color(ui::Color::Muted)
22940                                    .icon_size(action_icon_size)
22941                                    .tooltip(Tooltip::text("Close"))
22942                                    .on_click(|_, window, cx| {
22943                                        window
22944                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22945                                    }),
22946                            )
22947                            .child(
22948                                IconButton::new("diff-review-add", IconName::Return)
22949                                    .icon_color(ui::Color::Muted)
22950                                    .icon_size(action_icon_size)
22951                                    .tooltip(Tooltip::text("Add comment"))
22952                                    .on_click(|_, window, cx| {
22953                                        window.dispatch_action(
22954                                            Box::new(crate::actions::SubmitDiffReviewComment),
22955                                            cx,
22956                                        );
22957                                    }),
22958                            ),
22959                    ),
22960            )
22961            // Expandable comments section (only shown when there are comments)
22962            .when(comment_count > 0, |el| {
22963                el.child(Self::render_comments_section(
22964                    comments,
22965                    comments_expanded,
22966                    inline_editors,
22967                    user_avatar_uri,
22968                    avatar_size,
22969                    action_icon_size,
22970                    colors,
22971                ))
22972            })
22973            .into_any_element()
22974    }
22975
22976    fn render_comments_section(
22977        comments: Vec<StoredReviewComment>,
22978        expanded: bool,
22979        inline_editors: HashMap<usize, Entity<Editor>>,
22980        user_avatar_uri: Option<SharedUri>,
22981        avatar_size: Pixels,
22982        action_icon_size: IconSize,
22983        colors: &theme::ThemeColors,
22984    ) -> impl IntoElement {
22985        let comment_count = comments.len();
22986
22987        v_flex()
22988            .w_full()
22989            .gap_1()
22990            // Header with expand/collapse toggle
22991            .child(
22992                h_flex()
22993                    .id("review-comments-header")
22994                    .w_full()
22995                    .items_center()
22996                    .gap_1()
22997                    .px_2()
22998                    .py_1()
22999                    .cursor_pointer()
23000                    .rounded_md()
23001                    .hover(|style| style.bg(colors.ghost_element_hover))
23002                    .on_click(|_, window: &mut Window, cx| {
23003                        window.dispatch_action(
23004                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
23005                            cx,
23006                        );
23007                    })
23008                    .child(
23009                        Icon::new(if expanded {
23010                            IconName::ChevronDown
23011                        } else {
23012                            IconName::ChevronRight
23013                        })
23014                        .size(IconSize::Small)
23015                        .color(ui::Color::Muted),
23016                    )
23017                    .child(
23018                        Label::new(format!(
23019                            "{} Comment{}",
23020                            comment_count,
23021                            if comment_count == 1 { "" } else { "s" }
23022                        ))
23023                        .size(LabelSize::Small)
23024                        .color(Color::Muted),
23025                    ),
23026            )
23027            // Comments list (when expanded)
23028            .when(expanded, |el| {
23029                el.children(comments.into_iter().map(|comment| {
23030                    let inline_editor = inline_editors.get(&comment.id).cloned();
23031                    Self::render_comment_row(
23032                        comment,
23033                        inline_editor,
23034                        user_avatar_uri.clone(),
23035                        avatar_size,
23036                        action_icon_size,
23037                        colors,
23038                    )
23039                }))
23040            })
23041    }
23042
23043    fn render_comment_row(
23044        comment: StoredReviewComment,
23045        inline_editor: Option<Entity<Editor>>,
23046        user_avatar_uri: Option<SharedUri>,
23047        avatar_size: Pixels,
23048        action_icon_size: IconSize,
23049        colors: &theme::ThemeColors,
23050    ) -> impl IntoElement {
23051        let comment_id = comment.id;
23052        let is_editing = inline_editor.is_some();
23053
23054        h_flex()
23055            .w_full()
23056            .items_center()
23057            .gap_2()
23058            .px_2()
23059            .py_1p5()
23060            .rounded_md()
23061            .bg(colors.surface_background)
23062            .child(
23063                div()
23064                    .size(avatar_size)
23065                    .flex_shrink_0()
23066                    .rounded_full()
23067                    .overflow_hidden()
23068                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
23069                        Avatar::new(avatar_uri.clone())
23070                            .size(avatar_size)
23071                            .into_any_element()
23072                    } else {
23073                        Icon::new(IconName::Person)
23074                            .size(IconSize::Small)
23075                            .color(ui::Color::Muted)
23076                            .into_any_element()
23077                    }),
23078            )
23079            .child(if let Some(editor) = inline_editor {
23080                // Inline edit mode: show an editable text field
23081                div()
23082                    .flex_1()
23083                    .border_1()
23084                    .border_color(colors.border)
23085                    .rounded_md()
23086                    .bg(colors.editor_background)
23087                    .px_2()
23088                    .py_1()
23089                    .child(editor)
23090                    .into_any_element()
23091            } else {
23092                // Display mode: show the comment text
23093                div()
23094                    .flex_1()
23095                    .text_sm()
23096                    .text_color(colors.text)
23097                    .child(comment.comment)
23098                    .into_any_element()
23099            })
23100            .child(if is_editing {
23101                // Editing mode: show close and confirm buttons
23102                h_flex()
23103                    .gap_1()
23104                    .child(
23105                        IconButton::new(
23106                            format!("diff-review-cancel-edit-{comment_id}"),
23107                            IconName::Close,
23108                        )
23109                        .icon_color(ui::Color::Muted)
23110                        .icon_size(action_icon_size)
23111                        .tooltip(Tooltip::text("Cancel"))
23112                        .on_click(move |_, window, cx| {
23113                            window.dispatch_action(
23114                                Box::new(crate::actions::CancelEditReviewComment {
23115                                    id: comment_id,
23116                                }),
23117                                cx,
23118                            );
23119                        }),
23120                    )
23121                    .child(
23122                        IconButton::new(
23123                            format!("diff-review-confirm-edit-{comment_id}"),
23124                            IconName::Return,
23125                        )
23126                        .icon_color(ui::Color::Muted)
23127                        .icon_size(action_icon_size)
23128                        .tooltip(Tooltip::text("Confirm"))
23129                        .on_click(move |_, window, cx| {
23130                            window.dispatch_action(
23131                                Box::new(crate::actions::ConfirmEditReviewComment {
23132                                    id: comment_id,
23133                                }),
23134                                cx,
23135                            );
23136                        }),
23137                    )
23138                    .into_any_element()
23139            } else {
23140                // Display mode: no action buttons for now (edit/delete not yet implemented)
23141                gpui::Empty.into_any_element()
23142            })
23143    }
23144
23145    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
23146        if self.display_map.read(cx).masked != masked {
23147            self.display_map.update(cx, |map, _| map.masked = masked);
23148        }
23149        cx.notify()
23150    }
23151
23152    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
23153        self.show_wrap_guides = Some(show_wrap_guides);
23154        cx.notify();
23155    }
23156
23157    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
23158        self.show_indent_guides = Some(show_indent_guides);
23159        cx.notify();
23160    }
23161
23162    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
23163        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
23164            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
23165                && let Some(dir) = file.abs_path(cx).parent()
23166            {
23167                return Some(dir.to_owned());
23168            }
23169        }
23170
23171        None
23172    }
23173
23174    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
23175        self.active_buffer(cx)?
23176            .read(cx)
23177            .file()
23178            .and_then(|f| f.as_local())
23179    }
23180
23181    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
23182        self.active_buffer(cx).and_then(|buffer| {
23183            let buffer = buffer.read(cx);
23184            if let Some(project_path) = buffer.project_path(cx) {
23185                let project = self.project()?.read(cx);
23186                project.absolute_path(&project_path, cx)
23187            } else {
23188                buffer
23189                    .file()
23190                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
23191            }
23192        })
23193    }
23194
23195    pub fn reveal_in_finder(
23196        &mut self,
23197        _: &RevealInFileManager,
23198        _window: &mut Window,
23199        cx: &mut Context<Self>,
23200    ) {
23201        if let Some(path) = self.target_file_abs_path(cx) {
23202            if let Some(project) = self.project() {
23203                project.update(cx, |project, cx| project.reveal_path(&path, cx));
23204            } else {
23205                cx.reveal_path(&path);
23206            }
23207        }
23208    }
23209
23210    pub fn copy_path(
23211        &mut self,
23212        _: &zed_actions::workspace::CopyPath,
23213        _window: &mut Window,
23214        cx: &mut Context<Self>,
23215    ) {
23216        if let Some(path) = self.target_file_abs_path(cx)
23217            && let Some(path) = path.to_str()
23218        {
23219            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23220        } else {
23221            cx.propagate();
23222        }
23223    }
23224
23225    pub fn copy_relative_path(
23226        &mut self,
23227        _: &zed_actions::workspace::CopyRelativePath,
23228        _window: &mut Window,
23229        cx: &mut Context<Self>,
23230    ) {
23231        if let Some(path) = self.active_buffer(cx).and_then(|buffer| {
23232            let project = self.project()?.read(cx);
23233            let path = buffer.read(cx).file()?.path();
23234            let path = path.display(project.path_style(cx));
23235            Some(path)
23236        }) {
23237            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
23238        } else {
23239            cx.propagate();
23240        }
23241    }
23242
23243    /// Returns the project path for the editor's buffer, if any buffer is
23244    /// opened in the editor.
23245    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
23246        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
23247            buffer.read(cx).project_path(cx)
23248        } else {
23249            None
23250        }
23251    }
23252
23253    // Returns true if the editor handled a go-to-line request
23254    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
23255        maybe!({
23256            let breakpoint_store = self.breakpoint_store.as_ref()?;
23257
23258            let (active_stack_frame, debug_line_pane_id) = {
23259                let store = breakpoint_store.read(cx);
23260                let active_stack_frame = store.active_position().cloned();
23261                let debug_line_pane_id = store.active_debug_line_pane_id();
23262                (active_stack_frame, debug_line_pane_id)
23263            };
23264
23265            let Some(active_stack_frame) = active_stack_frame else {
23266                self.clear_row_highlights::<ActiveDebugLine>();
23267                return None;
23268            };
23269
23270            if let Some(debug_line_pane_id) = debug_line_pane_id {
23271                if let Some(workspace) = self
23272                    .workspace
23273                    .as_ref()
23274                    .and_then(|(workspace, _)| workspace.upgrade())
23275                {
23276                    let editor_pane_id = workspace
23277                        .read(cx)
23278                        .pane_for_item_id(cx.entity_id())
23279                        .map(|pane| pane.entity_id());
23280
23281                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
23282                        self.clear_row_highlights::<ActiveDebugLine>();
23283                        return None;
23284                    }
23285                }
23286            }
23287
23288            let position = active_stack_frame.position;
23289
23290            let snapshot = self.buffer.read(cx).snapshot(cx);
23291            let multibuffer_anchor = snapshot.anchor_in_excerpt(position)?;
23292
23293            self.clear_row_highlights::<ActiveDebugLine>();
23294
23295            self.go_to_line::<ActiveDebugLine>(
23296                multibuffer_anchor,
23297                Some(cx.theme().colors().editor_debugger_active_line_background),
23298                window,
23299                cx,
23300            );
23301
23302            cx.notify();
23303
23304            Some(())
23305        })
23306        .is_some()
23307    }
23308
23309    pub fn copy_file_name_without_extension(
23310        &mut self,
23311        _: &CopyFileNameWithoutExtension,
23312        _: &mut Window,
23313        cx: &mut Context<Self>,
23314    ) {
23315        if let Some(file_stem) = self.active_buffer(cx).and_then(|buffer| {
23316            let file = buffer.read(cx).file()?;
23317            file.path().file_stem()
23318        }) {
23319            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
23320        }
23321    }
23322
23323    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
23324        if let Some(file_name) = self.active_buffer(cx).and_then(|buffer| {
23325            let file = buffer.read(cx).file()?;
23326            Some(file.file_name(cx))
23327        }) {
23328            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
23329        }
23330    }
23331
23332    pub fn toggle_git_blame(
23333        &mut self,
23334        _: &::git::Blame,
23335        window: &mut Window,
23336        cx: &mut Context<Self>,
23337    ) {
23338        self.show_git_blame_gutter = !self.show_git_blame_gutter;
23339
23340        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
23341            self.start_git_blame(true, window, cx);
23342        }
23343
23344        cx.notify();
23345    }
23346
23347    pub fn toggle_git_blame_inline(
23348        &mut self,
23349        _: &ToggleGitBlameInline,
23350        window: &mut Window,
23351        cx: &mut Context<Self>,
23352    ) {
23353        self.toggle_git_blame_inline_internal(true, window, cx);
23354        cx.notify();
23355    }
23356
23357    pub fn open_git_blame_commit(
23358        &mut self,
23359        _: &OpenGitBlameCommit,
23360        window: &mut Window,
23361        cx: &mut Context<Self>,
23362    ) {
23363        self.open_git_blame_commit_internal(window, cx);
23364    }
23365
23366    fn open_git_blame_commit_internal(
23367        &mut self,
23368        window: &mut Window,
23369        cx: &mut Context<Self>,
23370    ) -> Option<()> {
23371        let blame = self.blame.as_ref()?;
23372        let snapshot = self.snapshot(window, cx);
23373        let cursor = self
23374            .selections
23375            .newest::<Point>(&snapshot.display_snapshot)
23376            .head();
23377        let (buffer, point) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
23378        let (_, blame_entry) = blame
23379            .update(cx, |blame, cx| {
23380                blame
23381                    .blame_for_rows(
23382                        &[RowInfo {
23383                            buffer_id: Some(buffer.remote_id()),
23384                            buffer_row: Some(point.row),
23385                            ..Default::default()
23386                        }],
23387                        cx,
23388                    )
23389                    .next()
23390            })
23391            .flatten()?;
23392        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
23393        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
23394        let workspace = self.workspace()?.downgrade();
23395        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
23396        None
23397    }
23398
23399    pub fn git_blame_inline_enabled(&self) -> bool {
23400        self.git_blame_inline_enabled
23401    }
23402
23403    pub fn toggle_selection_menu(
23404        &mut self,
23405        _: &ToggleSelectionMenu,
23406        _: &mut Window,
23407        cx: &mut Context<Self>,
23408    ) {
23409        self.show_selection_menu = self
23410            .show_selection_menu
23411            .map(|show_selections_menu| !show_selections_menu)
23412            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
23413
23414        cx.notify();
23415    }
23416
23417    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
23418        self.show_selection_menu
23419            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
23420    }
23421
23422    fn start_git_blame(
23423        &mut self,
23424        user_triggered: bool,
23425        window: &mut Window,
23426        cx: &mut Context<Self>,
23427    ) {
23428        if let Some(project) = self.project() {
23429            if let Some(buffer) = self.buffer().read(cx).as_singleton()
23430                && buffer.read(cx).file().is_none()
23431            {
23432                return;
23433            }
23434
23435            let focused = self.focus_handle(cx).contains_focused(window, cx);
23436
23437            let project = project.clone();
23438            let blame = cx
23439                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
23440            self.blame_subscription =
23441                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
23442            self.blame = Some(blame);
23443        }
23444    }
23445
23446    fn toggle_git_blame_inline_internal(
23447        &mut self,
23448        user_triggered: bool,
23449        window: &mut Window,
23450        cx: &mut Context<Self>,
23451    ) {
23452        if self.git_blame_inline_enabled {
23453            self.git_blame_inline_enabled = false;
23454            self.show_git_blame_inline = false;
23455            self.show_git_blame_inline_delay_task.take();
23456        } else {
23457            self.git_blame_inline_enabled = true;
23458            self.start_git_blame_inline(user_triggered, window, cx);
23459        }
23460
23461        cx.notify();
23462    }
23463
23464    fn start_git_blame_inline(
23465        &mut self,
23466        user_triggered: bool,
23467        window: &mut Window,
23468        cx: &mut Context<Self>,
23469    ) {
23470        self.start_git_blame(user_triggered, window, cx);
23471
23472        if ProjectSettings::get_global(cx)
23473            .git
23474            .inline_blame_delay()
23475            .is_some()
23476        {
23477            self.start_inline_blame_timer(window, cx);
23478        } else {
23479            self.show_git_blame_inline = true
23480        }
23481    }
23482
23483    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
23484        self.blame.as_ref()
23485    }
23486
23487    pub fn show_git_blame_gutter(&self) -> bool {
23488        self.show_git_blame_gutter
23489    }
23490
23491    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
23492        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
23493    }
23494
23495    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
23496        self.show_git_blame_inline
23497            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
23498            && !self.newest_selection_head_on_empty_line(cx)
23499            && self.has_blame_entries(cx)
23500    }
23501
23502    fn has_blame_entries(&self, cx: &App) -> bool {
23503        self.blame()
23504            .is_some_and(|blame| blame.read(cx).has_generated_entries())
23505    }
23506
23507    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
23508        let cursor_anchor = self.selections.newest_anchor().head();
23509
23510        let snapshot = self.buffer.read(cx).snapshot(cx);
23511        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
23512
23513        snapshot.line_len(buffer_row) == 0
23514    }
23515
23516    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
23517        let buffer_and_selection = maybe!({
23518            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23519            let selection_range = selection.range();
23520
23521            let multi_buffer = self.buffer().read(cx);
23522            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
23523            let buffer_ranges = multi_buffer_snapshot
23524                .range_to_buffer_ranges(selection_range.start..selection_range.end);
23525
23526            let (buffer_snapshot, range, _) = if selection.reversed {
23527                buffer_ranges.first()
23528            } else {
23529                buffer_ranges.last()
23530            }?;
23531
23532            let buffer_range = range.to_point(buffer_snapshot);
23533            let buffer = multi_buffer.buffer(buffer_snapshot.remote_id()).unwrap();
23534
23535            let Some(buffer_diff) = multi_buffer.diff_for(buffer_snapshot.remote_id()) else {
23536                return Some((buffer, buffer_range.start.row..buffer_range.end.row));
23537            };
23538
23539            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
23540            let start = buffer_diff_snapshot
23541                .buffer_point_to_base_text_point(buffer_range.start, &buffer_snapshot);
23542            let end = buffer_diff_snapshot
23543                .buffer_point_to_base_text_point(buffer_range.end, &buffer_snapshot);
23544
23545            Some((buffer, start.row..end.row))
23546        });
23547
23548        let Some((buffer, selection)) = buffer_and_selection else {
23549            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
23550        };
23551
23552        let Some(project) = self.project() else {
23553            return Task::ready(Err(anyhow!("editor does not have project")));
23554        };
23555
23556        project.update(cx, |project, cx| {
23557            project.get_permalink_to_line(&buffer, selection, cx)
23558        })
23559    }
23560
23561    pub fn copy_permalink_to_line(
23562        &mut self,
23563        _: &CopyPermalinkToLine,
23564        window: &mut Window,
23565        cx: &mut Context<Self>,
23566    ) {
23567        let permalink_task = self.get_permalink_to_line(cx);
23568        let workspace = self.workspace();
23569
23570        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23571            Ok(permalink) => {
23572                cx.update(|_, cx| {
23573                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
23574                })
23575                .ok();
23576            }
23577            Err(err) => {
23578                let message = format!("Failed to copy permalink: {err}");
23579
23580                anyhow::Result::<()>::Err(err).log_err();
23581
23582                if let Some(workspace) = workspace {
23583                    workspace
23584                        .update_in(cx, |workspace, _, cx| {
23585                            struct CopyPermalinkToLine;
23586
23587                            workspace.show_toast(
23588                                Toast::new(
23589                                    NotificationId::unique::<CopyPermalinkToLine>(),
23590                                    message,
23591                                ),
23592                                cx,
23593                            )
23594                        })
23595                        .ok();
23596                }
23597            }
23598        })
23599        .detach();
23600    }
23601
23602    pub fn copy_file_location(
23603        &mut self,
23604        _: &CopyFileLocation,
23605        _: &mut Window,
23606        cx: &mut Context<Self>,
23607    ) {
23608        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
23609
23610        let start_line = selection.start.row + 1;
23611        let end_line = selection.end.row + 1;
23612
23613        let end_line = if selection.end.column == 0 && end_line > start_line {
23614            end_line - 1
23615        } else {
23616            end_line
23617        };
23618
23619        if let Some(file_location) = self.active_buffer(cx).and_then(|buffer| {
23620            let project = self.project()?.read(cx);
23621            let file = buffer.read(cx).file()?;
23622            let path = file.path().display(project.path_style(cx));
23623
23624            let location = if start_line == end_line {
23625                format!("{path}:{start_line}")
23626            } else {
23627                format!("{path}:{start_line}-{end_line}")
23628            };
23629            Some(location)
23630        }) {
23631            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
23632        }
23633    }
23634
23635    pub fn open_permalink_to_line(
23636        &mut self,
23637        _: &OpenPermalinkToLine,
23638        window: &mut Window,
23639        cx: &mut Context<Self>,
23640    ) {
23641        let permalink_task = self.get_permalink_to_line(cx);
23642        let workspace = self.workspace();
23643
23644        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
23645            Ok(permalink) => {
23646                cx.update(|_, cx| {
23647                    cx.open_url(permalink.as_ref());
23648                })
23649                .ok();
23650            }
23651            Err(err) => {
23652                let message = format!("Failed to open permalink: {err}");
23653
23654                anyhow::Result::<()>::Err(err).log_err();
23655
23656                if let Some(workspace) = workspace {
23657                    workspace.update(cx, |workspace, cx| {
23658                        struct OpenPermalinkToLine;
23659
23660                        workspace.show_toast(
23661                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
23662                            cx,
23663                        )
23664                    });
23665                }
23666            }
23667        })
23668        .detach();
23669    }
23670
23671    pub fn insert_uuid_v4(
23672        &mut self,
23673        _: &InsertUuidV4,
23674        window: &mut Window,
23675        cx: &mut Context<Self>,
23676    ) {
23677        self.insert_uuid(UuidVersion::V4, window, cx);
23678    }
23679
23680    pub fn insert_uuid_v7(
23681        &mut self,
23682        _: &InsertUuidV7,
23683        window: &mut Window,
23684        cx: &mut Context<Self>,
23685    ) {
23686        self.insert_uuid(UuidVersion::V7, window, cx);
23687    }
23688
23689    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
23690        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
23691        self.transact(window, cx, |this, window, cx| {
23692            let edits = this
23693                .selections
23694                .all::<Point>(&this.display_snapshot(cx))
23695                .into_iter()
23696                .map(|selection| {
23697                    let uuid = match version {
23698                        UuidVersion::V4 => uuid::Uuid::new_v4(),
23699                        UuidVersion::V7 => uuid::Uuid::now_v7(),
23700                    };
23701
23702                    (selection.range(), uuid.to_string())
23703                });
23704            this.edit(edits, cx);
23705            this.refresh_edit_prediction(true, false, window, cx);
23706        });
23707    }
23708
23709    pub fn open_selections_in_multibuffer(
23710        &mut self,
23711        _: &OpenSelectionsInMultibuffer,
23712        window: &mut Window,
23713        cx: &mut Context<Self>,
23714    ) {
23715        let multibuffer = self.buffer.read(cx);
23716
23717        let Some(buffer) = multibuffer.as_singleton() else {
23718            return;
23719        };
23720        let buffer_snapshot = buffer.read(cx).snapshot();
23721
23722        let Some(workspace) = self.workspace() else {
23723            return;
23724        };
23725
23726        let title = multibuffer.title(cx).to_string();
23727
23728        let locations = self
23729            .selections
23730            .all_anchors(&self.display_snapshot(cx))
23731            .iter()
23732            .map(|selection| {
23733                (
23734                    buffer.clone(),
23735                    (selection.start.text_anchor_in(&buffer_snapshot)
23736                        ..selection.end.text_anchor_in(&buffer_snapshot))
23737                        .to_point(buffer.read(cx)),
23738                )
23739            })
23740            .into_group_map();
23741
23742        cx.spawn_in(window, async move |_, cx| {
23743            workspace.update_in(cx, |workspace, window, cx| {
23744                Self::open_locations_in_multibuffer(
23745                    workspace,
23746                    locations,
23747                    format!("Selections for '{title}'"),
23748                    false,
23749                    false,
23750                    MultibufferSelectionMode::All,
23751                    window,
23752                    cx,
23753                );
23754            })
23755        })
23756        .detach();
23757    }
23758
23759    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23760    /// last highlight added will be used.
23761    ///
23762    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23763    pub fn highlight_rows<T: 'static>(
23764        &mut self,
23765        range: Range<Anchor>,
23766        color: Hsla,
23767        options: RowHighlightOptions,
23768        cx: &mut Context<Self>,
23769    ) {
23770        let snapshot = self.buffer().read(cx).snapshot(cx);
23771        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23772        let ix = row_highlights.binary_search_by(|highlight| {
23773            Ordering::Equal
23774                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23775                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23776        });
23777
23778        if let Err(mut ix) = ix {
23779            let index = post_inc(&mut self.highlight_order);
23780
23781            // If this range intersects with the preceding highlight, then merge it with
23782            // the preceding highlight. Otherwise insert a new highlight.
23783            let mut merged = false;
23784            if ix > 0 {
23785                let prev_highlight = &mut row_highlights[ix - 1];
23786                if prev_highlight
23787                    .range
23788                    .end
23789                    .cmp(&range.start, &snapshot)
23790                    .is_ge()
23791                {
23792                    ix -= 1;
23793                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23794                        prev_highlight.range.end = range.end;
23795                    }
23796                    merged = true;
23797                    prev_highlight.index = index;
23798                    prev_highlight.color = color;
23799                    prev_highlight.options = options;
23800                }
23801            }
23802
23803            if !merged {
23804                row_highlights.insert(
23805                    ix,
23806                    RowHighlight {
23807                        range,
23808                        index,
23809                        color,
23810                        options,
23811                        type_id: TypeId::of::<T>(),
23812                    },
23813                );
23814            }
23815
23816            // If any of the following highlights intersect with this one, merge them.
23817            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23818                let highlight = &row_highlights[ix];
23819                if next_highlight
23820                    .range
23821                    .start
23822                    .cmp(&highlight.range.end, &snapshot)
23823                    .is_le()
23824                {
23825                    if next_highlight
23826                        .range
23827                        .end
23828                        .cmp(&highlight.range.end, &snapshot)
23829                        .is_gt()
23830                    {
23831                        row_highlights[ix].range.end = next_highlight.range.end;
23832                    }
23833                    row_highlights.remove(ix + 1);
23834                } else {
23835                    break;
23836                }
23837            }
23838        }
23839    }
23840
23841    /// Remove any highlighted row ranges of the given type that intersect the
23842    /// given ranges.
23843    pub fn remove_highlighted_rows<T: 'static>(
23844        &mut self,
23845        ranges_to_remove: Vec<Range<Anchor>>,
23846        cx: &mut Context<Self>,
23847    ) {
23848        let snapshot = self.buffer().read(cx).snapshot(cx);
23849        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23850        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23851        row_highlights.retain(|highlight| {
23852            while let Some(range_to_remove) = ranges_to_remove.peek() {
23853                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23854                    Ordering::Less | Ordering::Equal => {
23855                        ranges_to_remove.next();
23856                    }
23857                    Ordering::Greater => {
23858                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23859                            Ordering::Less | Ordering::Equal => {
23860                                return false;
23861                            }
23862                            Ordering::Greater => break,
23863                        }
23864                    }
23865                }
23866            }
23867
23868            true
23869        })
23870    }
23871
23872    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23873    pub fn clear_row_highlights<T: 'static>(&mut self) {
23874        self.highlighted_rows.remove(&TypeId::of::<T>());
23875    }
23876
23877    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23878    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23879        self.highlighted_rows
23880            .get(&TypeId::of::<T>())
23881            .map_or(&[] as &[_], |vec| vec.as_slice())
23882            .iter()
23883            .map(|highlight| (highlight.range.clone(), highlight.color))
23884    }
23885
23886    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23887    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23888    /// Allows to ignore certain kinds of highlights.
23889    pub fn highlighted_display_rows(
23890        &self,
23891        window: &mut Window,
23892        cx: &mut App,
23893    ) -> BTreeMap<DisplayRow, LineHighlight> {
23894        let snapshot = self.snapshot(window, cx);
23895        let mut used_highlight_orders = HashMap::default();
23896        self.highlighted_rows
23897            .iter()
23898            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23899            .fold(
23900                BTreeMap::<DisplayRow, LineHighlight>::new(),
23901                |mut unique_rows, highlight| {
23902                    let start = highlight.range.start.to_display_point(&snapshot);
23903                    let end = highlight.range.end.to_display_point(&snapshot);
23904                    let start_row = start.row().0;
23905                    let end_row = if !highlight.range.end.is_max() && end.column() == 0 {
23906                        end.row().0.saturating_sub(1)
23907                    } else {
23908                        end.row().0
23909                    };
23910                    for row in start_row..=end_row {
23911                        let used_index =
23912                            used_highlight_orders.entry(row).or_insert(highlight.index);
23913                        if highlight.index >= *used_index {
23914                            *used_index = highlight.index;
23915                            unique_rows.insert(
23916                                DisplayRow(row),
23917                                LineHighlight {
23918                                    include_gutter: highlight.options.include_gutter,
23919                                    border: None,
23920                                    background: highlight.color.into(),
23921                                    type_id: Some(highlight.type_id),
23922                                },
23923                            );
23924                        }
23925                    }
23926                    unique_rows
23927                },
23928            )
23929    }
23930
23931    pub fn highlighted_display_row_for_autoscroll(
23932        &self,
23933        snapshot: &DisplaySnapshot,
23934    ) -> Option<DisplayRow> {
23935        self.highlighted_rows
23936            .values()
23937            .flat_map(|highlighted_rows| highlighted_rows.iter())
23938            .filter_map(|highlight| {
23939                if highlight.options.autoscroll {
23940                    Some(highlight.range.start.to_display_point(snapshot).row())
23941                } else {
23942                    None
23943                }
23944            })
23945            .min()
23946    }
23947
23948    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23949        self.highlight_background(
23950            HighlightKey::SearchWithinRange,
23951            ranges,
23952            |_, colors| colors.colors().editor_document_highlight_read_background,
23953            cx,
23954        )
23955    }
23956
23957    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23958        self.breadcrumb_header = Some(new_header);
23959    }
23960
23961    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23962        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23963    }
23964
23965    pub fn highlight_background(
23966        &mut self,
23967        key: HighlightKey,
23968        ranges: &[Range<Anchor>],
23969        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23970        cx: &mut Context<Self>,
23971    ) {
23972        self.background_highlights
23973            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23974        self.scrollbar_marker_state.dirty = true;
23975        cx.notify();
23976    }
23977
23978    pub fn clear_background_highlights(
23979        &mut self,
23980        key: HighlightKey,
23981        cx: &mut Context<Self>,
23982    ) -> Option<BackgroundHighlight> {
23983        let text_highlights = self.background_highlights.remove(&key)?;
23984        if !text_highlights.1.is_empty() {
23985            self.scrollbar_marker_state.dirty = true;
23986            cx.notify();
23987        }
23988        Some(text_highlights)
23989    }
23990
23991    pub fn highlight_gutter<T: 'static>(
23992        &mut self,
23993        ranges: impl Into<Vec<Range<Anchor>>>,
23994        color_fetcher: fn(&App) -> Hsla,
23995        cx: &mut Context<Self>,
23996    ) {
23997        self.gutter_highlights
23998            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23999        cx.notify();
24000    }
24001
24002    pub fn clear_gutter_highlights<T: 'static>(
24003        &mut self,
24004        cx: &mut Context<Self>,
24005    ) -> Option<GutterHighlight> {
24006        cx.notify();
24007        self.gutter_highlights.remove(&TypeId::of::<T>())
24008    }
24009
24010    pub fn insert_gutter_highlight<T: 'static>(
24011        &mut self,
24012        range: Range<Anchor>,
24013        color_fetcher: fn(&App) -> Hsla,
24014        cx: &mut Context<Self>,
24015    ) {
24016        let snapshot = self.buffer().read(cx).snapshot(cx);
24017        let mut highlights = self
24018            .gutter_highlights
24019            .remove(&TypeId::of::<T>())
24020            .map(|(_, highlights)| highlights)
24021            .unwrap_or_default();
24022        let ix = highlights.binary_search_by(|highlight| {
24023            Ordering::Equal
24024                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
24025                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
24026        });
24027        if let Err(ix) = ix {
24028            highlights.insert(ix, range);
24029        }
24030        self.gutter_highlights
24031            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
24032    }
24033
24034    pub fn remove_gutter_highlights<T: 'static>(
24035        &mut self,
24036        ranges_to_remove: Vec<Range<Anchor>>,
24037        cx: &mut Context<Self>,
24038    ) {
24039        let snapshot = self.buffer().read(cx).snapshot(cx);
24040        let Some((color_fetcher, mut gutter_highlights)) =
24041            self.gutter_highlights.remove(&TypeId::of::<T>())
24042        else {
24043            return;
24044        };
24045        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
24046        gutter_highlights.retain(|highlight| {
24047            while let Some(range_to_remove) = ranges_to_remove.peek() {
24048                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
24049                    Ordering::Less | Ordering::Equal => {
24050                        ranges_to_remove.next();
24051                    }
24052                    Ordering::Greater => {
24053                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
24054                            Ordering::Less | Ordering::Equal => {
24055                                return false;
24056                            }
24057                            Ordering::Greater => break,
24058                        }
24059                    }
24060                }
24061            }
24062
24063            true
24064        });
24065        self.gutter_highlights
24066            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
24067    }
24068
24069    #[cfg(any(test, feature = "test-support"))]
24070    pub fn all_text_highlights(
24071        &self,
24072        window: &mut Window,
24073        cx: &mut Context<Self>,
24074    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
24075        let snapshot = self.snapshot(window, cx);
24076        self.display_map.update(cx, |display_map, _| {
24077            display_map
24078                .all_text_highlights()
24079                .map(|(_, highlight)| {
24080                    let (style, ranges) = highlight.as_ref();
24081                    (
24082                        *style,
24083                        ranges
24084                            .iter()
24085                            .map(|range| range.clone().to_display_points(&snapshot))
24086                            .collect(),
24087                    )
24088                })
24089                .collect()
24090        })
24091    }
24092
24093    #[cfg(any(test, feature = "test-support"))]
24094    pub fn all_text_background_highlights(
24095        &self,
24096        window: &mut Window,
24097        cx: &mut Context<Self>,
24098    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24099        let snapshot = self.snapshot(window, cx);
24100        let buffer = &snapshot.buffer_snapshot();
24101        let start = buffer.anchor_before(MultiBufferOffset(0));
24102        let end = buffer.anchor_after(buffer.len());
24103        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
24104    }
24105
24106    #[cfg(any(test, feature = "test-support"))]
24107    pub fn sorted_background_highlights_in_range(
24108        &self,
24109        search_range: Range<Anchor>,
24110        display_snapshot: &DisplaySnapshot,
24111        theme: &Theme,
24112    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24113        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
24114        res.sort_by(|a, b| {
24115            a.0.start
24116                .cmp(&b.0.start)
24117                .then_with(|| a.0.end.cmp(&b.0.end))
24118                .then_with(|| a.1.cmp(&b.1))
24119        });
24120        res
24121    }
24122
24123    #[cfg(any(test, feature = "test-support"))]
24124    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
24125        let snapshot = self.buffer().read(cx).snapshot(cx);
24126
24127        let highlights = self
24128            .background_highlights
24129            .get(&HighlightKey::BufferSearchHighlights);
24130
24131        if let Some((_color, ranges)) = highlights {
24132            ranges
24133                .iter()
24134                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
24135                .collect_vec()
24136        } else {
24137            vec![]
24138        }
24139    }
24140
24141    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
24142        self.background_highlights
24143            .get(&key)
24144            .is_some_and(|(_, highlights)| !highlights.is_empty())
24145    }
24146
24147    /// Returns all background highlights for a given range.
24148    ///
24149    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
24150    pub fn background_highlights_in_range(
24151        &self,
24152        search_range: Range<Anchor>,
24153        display_snapshot: &DisplaySnapshot,
24154        theme: &Theme,
24155    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24156        let mut results = Vec::new();
24157        for (color_fetcher, ranges) in self.background_highlights.values() {
24158            let start_ix = match ranges.binary_search_by(|probe| {
24159                let cmp = probe
24160                    .end
24161                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
24162                if cmp.is_gt() {
24163                    Ordering::Greater
24164                } else {
24165                    Ordering::Less
24166                }
24167            }) {
24168                Ok(i) | Err(i) => i,
24169            };
24170            for (index, range) in ranges[start_ix..].iter().enumerate() {
24171                if range
24172                    .start
24173                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24174                    .is_ge()
24175                {
24176                    break;
24177                }
24178
24179                let color = color_fetcher(&(start_ix + index), theme);
24180                let start = range.start.to_display_point(display_snapshot);
24181                let end = range.end.to_display_point(display_snapshot);
24182                results.push((start..end, color))
24183            }
24184        }
24185        results
24186    }
24187
24188    pub fn gutter_highlights_in_range(
24189        &self,
24190        search_range: Range<Anchor>,
24191        display_snapshot: &DisplaySnapshot,
24192        cx: &App,
24193    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
24194        let mut results = Vec::new();
24195        for (color_fetcher, ranges) in self.gutter_highlights.values() {
24196            let color = color_fetcher(cx);
24197            let start_ix = match ranges.binary_search_by(|probe| {
24198                let cmp = probe
24199                    .end
24200                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
24201                if cmp.is_gt() {
24202                    Ordering::Greater
24203                } else {
24204                    Ordering::Less
24205                }
24206            }) {
24207                Ok(i) | Err(i) => i,
24208            };
24209            for range in &ranges[start_ix..] {
24210                if range
24211                    .start
24212                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
24213                    .is_ge()
24214                {
24215                    break;
24216                }
24217
24218                let start = range.start.to_display_point(display_snapshot);
24219                let end = range.end.to_display_point(display_snapshot);
24220                results.push((start..end, color))
24221            }
24222        }
24223        results
24224    }
24225
24226    /// Get the text ranges corresponding to the redaction query
24227    pub fn redacted_ranges(
24228        &self,
24229        search_range: Range<Anchor>,
24230        display_snapshot: &DisplaySnapshot,
24231        cx: &App,
24232    ) -> Vec<Range<DisplayPoint>> {
24233        display_snapshot
24234            .buffer_snapshot()
24235            .redacted_ranges(search_range, |file| {
24236                if let Some(file) = file {
24237                    file.is_private()
24238                        && EditorSettings::get(
24239                            Some(SettingsLocation {
24240                                worktree_id: file.worktree_id(cx),
24241                                path: file.path().as_ref(),
24242                            }),
24243                            cx,
24244                        )
24245                        .redact_private_values
24246                } else {
24247                    false
24248                }
24249            })
24250            .map(|range| {
24251                range.start.to_display_point(display_snapshot)
24252                    ..range.end.to_display_point(display_snapshot)
24253            })
24254            .collect()
24255    }
24256
24257    pub fn highlight_text_key(
24258        &mut self,
24259        key: HighlightKey,
24260        ranges: Vec<Range<Anchor>>,
24261        style: HighlightStyle,
24262        merge: bool,
24263        cx: &mut Context<Self>,
24264    ) {
24265        self.display_map.update(cx, |map, cx| {
24266            map.highlight_text(key, ranges, style, merge, cx);
24267        });
24268        cx.notify();
24269    }
24270
24271    pub fn highlight_text(
24272        &mut self,
24273        key: HighlightKey,
24274        ranges: Vec<Range<Anchor>>,
24275        style: HighlightStyle,
24276        cx: &mut Context<Self>,
24277    ) {
24278        self.display_map.update(cx, |map, cx| {
24279            map.highlight_text(key, ranges, style, false, cx)
24280        });
24281        cx.notify();
24282    }
24283
24284    pub fn text_highlights<'a>(
24285        &'a self,
24286        key: HighlightKey,
24287        cx: &'a App,
24288    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
24289        self.display_map.read(cx).text_highlights(key)
24290    }
24291
24292    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
24293        let cleared = self
24294            .display_map
24295            .update(cx, |map, _| map.clear_highlights(key));
24296        if cleared {
24297            cx.notify();
24298        }
24299    }
24300
24301    pub fn clear_highlights_with(
24302        &mut self,
24303        f: &mut dyn FnMut(&HighlightKey) -> bool,
24304        cx: &mut Context<Self>,
24305    ) {
24306        let cleared = self
24307            .display_map
24308            .update(cx, |map, _| map.clear_highlights_with(f));
24309        if cleared {
24310            cx.notify();
24311        }
24312    }
24313
24314    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
24315        (self.read_only(cx) || self.blink_manager.read(cx).visible())
24316            && self.focus_handle.is_focused(window)
24317    }
24318
24319    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
24320        self.show_cursor_when_unfocused = is_enabled;
24321        cx.notify();
24322    }
24323
24324    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
24325        cx.notify();
24326    }
24327
24328    fn on_debug_session_event(
24329        &mut self,
24330        _session: Entity<Session>,
24331        event: &SessionEvent,
24332        cx: &mut Context<Self>,
24333    ) {
24334        if let SessionEvent::InvalidateInlineValue = event {
24335            self.refresh_inline_values(cx);
24336        }
24337    }
24338
24339    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
24340        let Some(semantics) = self.semantics_provider.clone() else {
24341            return;
24342        };
24343
24344        if !self.inline_value_cache.enabled {
24345            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
24346            self.splice_inlays(&inlays, Vec::new(), cx);
24347            return;
24348        }
24349
24350        let current_execution_position = self
24351            .highlighted_rows
24352            .get(&TypeId::of::<ActiveDebugLine>())
24353            .and_then(|lines| lines.last().map(|line| line.range.end));
24354
24355        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
24356            let inline_values = editor
24357                .update(cx, |editor, cx| {
24358                    let Some(current_execution_position) = current_execution_position else {
24359                        return Some(Task::ready(Ok(Vec::new())));
24360                    };
24361
24362                    let (buffer, buffer_anchor) =
24363                        editor.buffer.read_with(cx, |multibuffer, cx| {
24364                            let multibuffer_snapshot = multibuffer.snapshot(cx);
24365                            let (buffer_anchor, _) = multibuffer_snapshot
24366                                .anchor_to_buffer_anchor(current_execution_position)?;
24367                            let buffer = multibuffer.buffer(buffer_anchor.buffer_id)?;
24368                            Some((buffer, buffer_anchor))
24369                        })?;
24370
24371                    let range = buffer.read(cx).anchor_before(0)..buffer_anchor;
24372
24373                    semantics.inline_values(buffer, range, cx)
24374                })
24375                .ok()
24376                .flatten()?
24377                .await
24378                .context("refreshing debugger inlays")
24379                .log_err()?;
24380
24381            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
24382
24383            for (buffer_id, inline_value) in inline_values
24384                .into_iter()
24385                .map(|hint| (hint.position.buffer_id, hint))
24386            {
24387                buffer_inline_values
24388                    .entry(buffer_id)
24389                    .or_default()
24390                    .push(inline_value);
24391            }
24392
24393            editor
24394                .update(cx, |editor, cx| {
24395                    let snapshot = editor.buffer.read(cx).snapshot(cx);
24396                    let mut new_inlays = Vec::default();
24397
24398                    for (_buffer_id, inline_values) in buffer_inline_values {
24399                        for hint in inline_values {
24400                            let Some(anchor) = snapshot.anchor_in_excerpt(hint.position) else {
24401                                continue;
24402                            };
24403                            let inlay = Inlay::debugger(
24404                                post_inc(&mut editor.next_inlay_id),
24405                                anchor,
24406                                hint.text(),
24407                            );
24408                            if !inlay.text().chars().contains(&'\n') {
24409                                new_inlays.push(inlay);
24410                            }
24411                        }
24412                    }
24413
24414                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
24415                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
24416
24417                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
24418                })
24419                .ok()?;
24420            Some(())
24421        });
24422    }
24423
24424    fn on_buffer_event(
24425        &mut self,
24426        multibuffer: &Entity<MultiBuffer>,
24427        event: &multi_buffer::Event,
24428        window: &mut Window,
24429        cx: &mut Context<Self>,
24430    ) {
24431        match event {
24432            multi_buffer::Event::Edited {
24433                edited_buffer,
24434                is_local,
24435            } => {
24436                self.scrollbar_marker_state.dirty = true;
24437                self.active_indent_guides_state.dirty = true;
24438                self.refresh_active_diagnostics(cx);
24439                self.refresh_code_actions(window, cx);
24440                self.refresh_single_line_folds(window, cx);
24441                let snapshot = self.snapshot(window, cx);
24442                self.refresh_matching_bracket_highlights(&snapshot, cx);
24443                self.refresh_outline_symbols_at_cursor(cx);
24444                self.refresh_sticky_headers(&snapshot, cx);
24445                if *is_local && self.has_active_edit_prediction() {
24446                    self.update_visible_edit_prediction(window, cx);
24447                }
24448
24449                // Clean up orphaned review comments after edits
24450                self.cleanup_orphaned_review_comments(cx);
24451
24452                if let Some(buffer) = edited_buffer {
24453                    if buffer.read(cx).file().is_none() {
24454                        cx.emit(EditorEvent::TitleChanged);
24455                    }
24456
24457                    if self.project.is_some() {
24458                        let buffer_id = buffer.read(cx).remote_id();
24459                        self.register_buffer(buffer_id, cx);
24460                        self.update_lsp_data(Some(buffer_id), window, cx);
24461                        self.refresh_inlay_hints(
24462                            InlayHintRefreshReason::BufferEdited(buffer_id),
24463                            cx,
24464                        );
24465                    }
24466                }
24467
24468                cx.emit(EditorEvent::BufferEdited);
24469                cx.emit(SearchEvent::MatchesInvalidated);
24470
24471                let Some(project) = &self.project else { return };
24472                let (telemetry, is_via_ssh) = {
24473                    let project = project.read(cx);
24474                    let telemetry = project.client().telemetry().clone();
24475                    let is_via_ssh = project.is_via_remote_server();
24476                    (telemetry, is_via_ssh)
24477                };
24478                telemetry.log_edit_event("editor", is_via_ssh);
24479            }
24480            multi_buffer::Event::BufferRangesUpdated {
24481                buffer,
24482                ranges,
24483                path_key,
24484            } => {
24485                self.refresh_document_highlights(cx);
24486                let buffer_id = buffer.read(cx).remote_id();
24487                if self.buffer.read(cx).diff_for(buffer_id).is_none()
24488                    && let Some(project) = &self.project
24489                {
24490                    update_uncommitted_diff_for_buffer(
24491                        cx.entity(),
24492                        project,
24493                        [buffer.clone()],
24494                        self.buffer.clone(),
24495                        cx,
24496                    )
24497                    .detach();
24498                }
24499                self.register_visible_buffers(cx);
24500                self.update_lsp_data(Some(buffer_id), window, cx);
24501                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
24502                self.refresh_runnables(None, window, cx);
24503                self.bracket_fetched_tree_sitter_chunks
24504                    .retain(|range, _| range.start.buffer_id != buffer_id);
24505                self.colorize_brackets(false, cx);
24506                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24507                self.semantic_token_state.invalidate_buffer(&buffer_id);
24508                cx.emit(EditorEvent::BufferRangesUpdated {
24509                    buffer: buffer.clone(),
24510                    ranges: ranges.clone(),
24511                    path_key: path_key.clone(),
24512                });
24513            }
24514            multi_buffer::Event::BuffersRemoved { removed_buffer_ids } => {
24515                if let Some(inlay_hints) = &mut self.inlay_hints {
24516                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
24517                }
24518                self.refresh_inlay_hints(
24519                    InlayHintRefreshReason::BuffersRemoved(removed_buffer_ids.clone()),
24520                    cx,
24521                );
24522                for buffer_id in removed_buffer_ids {
24523                    self.registered_buffers.remove(buffer_id);
24524                    self.clear_runnables(Some(*buffer_id));
24525                    self.semantic_token_state.invalidate_buffer(buffer_id);
24526                    self.display_map.update(cx, |display_map, cx| {
24527                        display_map.invalidate_semantic_highlights(*buffer_id);
24528                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
24529                    });
24530                }
24531
24532                self.display_map.update(cx, |display_map, cx| {
24533                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
24534                });
24535
24536                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24537                cx.emit(EditorEvent::BuffersRemoved {
24538                    removed_buffer_ids: removed_buffer_ids.clone(),
24539                });
24540            }
24541            multi_buffer::Event::BuffersEdited { buffer_ids } => {
24542                self.display_map.update(cx, |map, cx| {
24543                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
24544                });
24545                cx.emit(EditorEvent::BuffersEdited {
24546                    buffer_ids: buffer_ids.clone(),
24547                });
24548            }
24549            multi_buffer::Event::Reparsed(buffer_id) => {
24550                self.refresh_runnables(Some(*buffer_id), window, cx);
24551                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
24552                self.colorize_brackets(true, cx);
24553                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24554
24555                cx.emit(EditorEvent::Reparsed(*buffer_id));
24556            }
24557            multi_buffer::Event::DiffHunksToggled => {
24558                self.refresh_runnables(None, window, cx);
24559            }
24560            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
24561                if !is_fresh_language {
24562                    self.registered_buffers.remove(&buffer_id);
24563                }
24564                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
24565                cx.emit(EditorEvent::Reparsed(*buffer_id));
24566                self.update_edit_prediction_settings(cx);
24567                cx.notify();
24568            }
24569            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
24570            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
24571            multi_buffer::Event::FileHandleChanged
24572            | multi_buffer::Event::Reloaded
24573            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
24574            multi_buffer::Event::DiagnosticsUpdated => {
24575                self.update_diagnostics_state(window, cx);
24576            }
24577            _ => {}
24578        };
24579    }
24580
24581    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
24582        if !self.diagnostics_enabled() {
24583            return;
24584        }
24585        self.refresh_active_diagnostics(cx);
24586        self.refresh_inline_diagnostics(true, window, cx);
24587        self.scrollbar_marker_state.dirty = true;
24588        cx.notify();
24589    }
24590
24591    pub fn start_temporary_diff_override(&mut self) {
24592        self.load_diff_task.take();
24593        self.temporary_diff_override = true;
24594    }
24595
24596    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
24597        self.temporary_diff_override = false;
24598        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
24599        self.buffer.update(cx, |buffer, cx| {
24600            buffer.set_all_diff_hunks_collapsed(cx);
24601        });
24602
24603        if let Some(project) = self.project.clone() {
24604            self.load_diff_task = Some(
24605                update_uncommitted_diff_for_buffer(
24606                    cx.entity(),
24607                    &project,
24608                    self.buffer.read(cx).all_buffers(),
24609                    self.buffer.clone(),
24610                    cx,
24611                )
24612                .shared(),
24613            );
24614        }
24615    }
24616
24617    fn on_display_map_changed(
24618        &mut self,
24619        _: Entity<DisplayMap>,
24620        _: &mut Window,
24621        cx: &mut Context<Self>,
24622    ) {
24623        cx.notify();
24624    }
24625
24626    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
24627        if !self.mode.is_full() {
24628            return None;
24629        }
24630
24631        let theme_settings = theme_settings::ThemeSettings::get_global(cx);
24632        let theme = cx.theme();
24633        let accent_colors = theme.accents().clone();
24634
24635        let accent_overrides = theme_settings
24636            .theme_overrides
24637            .get(theme.name.as_ref())
24638            .map(|theme_style| &theme_style.accents)
24639            .into_iter()
24640            .flatten()
24641            .chain(
24642                theme_settings
24643                    .experimental_theme_overrides
24644                    .as_ref()
24645                    .map(|overrides| &overrides.accents)
24646                    .into_iter()
24647                    .flatten(),
24648            )
24649            .flat_map(|accent| accent.0.clone().map(SharedString::from))
24650            .collect();
24651
24652        Some(AccentData {
24653            colors: accent_colors,
24654            overrides: accent_overrides,
24655        })
24656    }
24657
24658    fn fetch_applicable_language_settings(
24659        &self,
24660        cx: &App,
24661    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
24662        if !self.mode.is_full() {
24663            return HashMap::default();
24664        }
24665
24666        self.buffer().read(cx).all_buffers().into_iter().fold(
24667            HashMap::default(),
24668            |mut acc, buffer| {
24669                let buffer = buffer.read(cx);
24670                let language = buffer.language().map(|language| language.name());
24671                if let hash_map::Entry::Vacant(v) = acc.entry(language) {
24672                    v.insert(LanguageSettings::for_buffer(&buffer, cx).into_owned());
24673                }
24674                acc
24675            },
24676        )
24677    }
24678
24679    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24680        let new_language_settings = self.fetch_applicable_language_settings(cx);
24681        let language_settings_changed = new_language_settings != self.applicable_language_settings;
24682        self.applicable_language_settings = new_language_settings;
24683
24684        let new_accents = self.fetch_accent_data(cx);
24685        let accents_changed = new_accents != self.accent_data;
24686        self.accent_data = new_accents;
24687
24688        if self.diagnostics_enabled() {
24689            let new_severity = EditorSettings::get_global(cx)
24690                .diagnostics_max_severity
24691                .unwrap_or(DiagnosticSeverity::Hint);
24692            self.set_max_diagnostics_severity(new_severity, cx);
24693        }
24694        self.refresh_runnables(None, window, cx);
24695        self.update_edit_prediction_settings(cx);
24696        self.refresh_edit_prediction(true, false, window, cx);
24697        self.refresh_inline_values(cx);
24698
24699        let old_cursor_shape = self.cursor_shape;
24700        let old_show_breadcrumbs = self.show_breadcrumbs;
24701
24702        {
24703            let editor_settings = EditorSettings::get_global(cx);
24704            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24705            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24706            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24707            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24708        }
24709
24710        if old_cursor_shape != self.cursor_shape {
24711            cx.emit(EditorEvent::CursorShapeChanged);
24712        }
24713
24714        if old_show_breadcrumbs != self.show_breadcrumbs {
24715            cx.emit(EditorEvent::BreadcrumbsChanged);
24716        }
24717
24718        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24719            let project_settings = ProjectSettings::get_global(cx);
24720            (
24721                project_settings.session.restore_unsaved_buffers,
24722                project_settings.diagnostics.inline.enabled,
24723                project_settings.git.inline_blame.enabled,
24724            )
24725        };
24726        self.buffer_serialization = self
24727            .should_serialize_buffer()
24728            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24729
24730        if self.mode.is_full() {
24731            if self.show_inline_diagnostics != show_inline_diagnostics {
24732                self.show_inline_diagnostics = show_inline_diagnostics;
24733                self.refresh_inline_diagnostics(false, window, cx);
24734            }
24735
24736            if self.git_blame_inline_enabled != inline_blame_enabled {
24737                self.toggle_git_blame_inline_internal(false, window, cx);
24738            }
24739
24740            let minimap_settings = EditorSettings::get_global(cx).minimap;
24741            if self.minimap_visibility != MinimapVisibility::Disabled {
24742                if self.minimap_visibility.settings_visibility()
24743                    != minimap_settings.minimap_enabled()
24744                {
24745                    self.set_minimap_visibility(
24746                        MinimapVisibility::for_mode(self.mode(), cx),
24747                        window,
24748                        cx,
24749                    );
24750                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24751                    minimap_entity.update(cx, |minimap_editor, cx| {
24752                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24753                    })
24754                }
24755            }
24756
24757            if language_settings_changed || accents_changed {
24758                self.colorize_brackets(true, cx);
24759            }
24760
24761            if language_settings_changed {
24762                self.clear_disabled_lsp_folding_ranges(window, cx);
24763                self.refresh_document_symbols(None, cx);
24764            }
24765
24766            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24767                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24768            }) {
24769                if !inlay_splice.is_empty() {
24770                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24771                }
24772                self.refresh_document_colors(None, window, cx);
24773            }
24774
24775            self.refresh_inlay_hints(
24776                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24777                    self.selections.newest_anchor().head(),
24778                    &self.buffer.read(cx).snapshot(cx),
24779                    cx,
24780                )),
24781                cx,
24782            );
24783
24784            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24785                .global_lsp_settings
24786                .semantic_token_rules
24787                .clone();
24788            let semantic_token_rules_changed = self
24789                .semantic_token_state
24790                .update_rules(new_semantic_token_rules);
24791            if language_settings_changed || semantic_token_rules_changed {
24792                self.invalidate_semantic_tokens(None);
24793                self.refresh_semantic_tokens(None, None, cx);
24794            }
24795        }
24796
24797        cx.notify();
24798    }
24799
24800    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24801        if !self.mode.is_full() {
24802            return;
24803        }
24804
24805        let new_accents = self.fetch_accent_data(cx);
24806        if new_accents != self.accent_data {
24807            self.accent_data = new_accents;
24808            self.colorize_brackets(true, cx);
24809        }
24810
24811        self.invalidate_semantic_tokens(None);
24812        self.refresh_semantic_tokens(None, None, cx);
24813    }
24814
24815    pub fn set_searchable(&mut self, searchable: bool) {
24816        self.searchable = searchable;
24817    }
24818
24819    pub fn searchable(&self) -> bool {
24820        self.searchable
24821    }
24822
24823    pub fn open_excerpts_in_split(
24824        &mut self,
24825        _: &OpenExcerptsSplit,
24826        window: &mut Window,
24827        cx: &mut Context<Self>,
24828    ) {
24829        self.open_excerpts_common(None, true, window, cx)
24830    }
24831
24832    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24833        self.open_excerpts_common(None, false, window, cx)
24834    }
24835
24836    pub(crate) fn open_excerpts_common(
24837        &mut self,
24838        jump_data: Option<JumpData>,
24839        split: bool,
24840        window: &mut Window,
24841        cx: &mut Context<Self>,
24842    ) {
24843        if self.buffer.read(cx).is_singleton() {
24844            cx.propagate();
24845            return;
24846        }
24847
24848        let mut new_selections_by_buffer = HashMap::default();
24849        match &jump_data {
24850            Some(JumpData::MultiBufferPoint {
24851                anchor,
24852                position,
24853                line_offset_from_top,
24854            }) => {
24855                if let Some(buffer) = self.buffer.read(cx).buffer(anchor.buffer_id) {
24856                    let buffer_snapshot = buffer.read(cx).snapshot();
24857                    let jump_to_point = if buffer_snapshot.can_resolve(&anchor) {
24858                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24859                    } else {
24860                        buffer_snapshot.clip_point(*position, Bias::Left)
24861                    };
24862                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24863                    new_selections_by_buffer.insert(
24864                        buffer,
24865                        (
24866                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24867                            Some(*line_offset_from_top),
24868                        ),
24869                    );
24870                }
24871            }
24872            Some(JumpData::MultiBufferRow {
24873                row,
24874                line_offset_from_top,
24875            }) => {
24876                let point = MultiBufferPoint::new(row.0, 0);
24877                if let Some((buffer, buffer_point)) =
24878                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24879                {
24880                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24881                    new_selections_by_buffer
24882                        .entry(buffer)
24883                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24884                        .0
24885                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24886                }
24887            }
24888            None => {
24889                let selections = self
24890                    .selections
24891                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24892                let multi_buffer = self.buffer.read(cx);
24893                let multi_buffer_snapshot = multi_buffer.snapshot(cx);
24894                for selection in selections {
24895                    for (snapshot, range, anchor) in multi_buffer_snapshot
24896                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24897                    {
24898                        if let Some((text_anchor, _)) = anchor.and_then(|anchor| {
24899                            multi_buffer_snapshot.anchor_to_buffer_anchor(anchor)
24900                        }) {
24901                            let Some(buffer_handle) = multi_buffer.buffer(text_anchor.buffer_id)
24902                            else {
24903                                continue;
24904                            };
24905                            let offset = text::ToOffset::to_offset(
24906                                &text_anchor,
24907                                &buffer_handle.read(cx).snapshot(),
24908                            );
24909                            let range = BufferOffset(offset)..BufferOffset(offset);
24910                            new_selections_by_buffer
24911                                .entry(buffer_handle)
24912                                .or_insert((Vec::new(), None))
24913                                .0
24914                                .push(range)
24915                        } else {
24916                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24917                            else {
24918                                continue;
24919                            };
24920                            new_selections_by_buffer
24921                                .entry(buffer_handle)
24922                                .or_insert((Vec::new(), None))
24923                                .0
24924                                .push(range)
24925                        }
24926                    }
24927                }
24928            }
24929        }
24930
24931        if self.delegate_open_excerpts {
24932            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24933                .into_iter()
24934                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24935                .collect();
24936            if !selections_by_buffer.is_empty() {
24937                cx.emit(EditorEvent::OpenExcerptsRequested {
24938                    selections_by_buffer,
24939                    split,
24940                });
24941            }
24942            return;
24943        }
24944
24945        let Some(workspace) = self.workspace() else {
24946            cx.propagate();
24947            return;
24948        };
24949
24950        new_selections_by_buffer
24951            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24952
24953        if new_selections_by_buffer.is_empty() {
24954            return;
24955        }
24956
24957        Self::open_buffers_in_workspace(
24958            workspace.downgrade(),
24959            new_selections_by_buffer,
24960            split,
24961            window,
24962            cx,
24963        );
24964    }
24965
24966    pub(crate) fn open_buffers_in_workspace(
24967        workspace: WeakEntity<Workspace>,
24968        new_selections_by_buffer: HashMap<
24969            Entity<language::Buffer>,
24970            (Vec<Range<BufferOffset>>, Option<u32>),
24971        >,
24972        split: bool,
24973        window: &mut Window,
24974        cx: &mut App,
24975    ) {
24976        // We defer the pane interaction because we ourselves are a workspace item
24977        // and activating a new item causes the pane to call a method on us reentrantly,
24978        // which panics if we're on the stack.
24979        window.defer(cx, move |window, cx| {
24980            workspace
24981                .update(cx, |workspace, cx| {
24982                    let pane = if split {
24983                        workspace.adjacent_pane(window, cx)
24984                    } else {
24985                        workspace.active_pane().clone()
24986                    };
24987
24988                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24989                        let buffer_read = buffer.read(cx);
24990                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24991                            (true, project::File::from_dyn(Some(file)).is_some())
24992                        } else {
24993                            (false, false)
24994                        };
24995
24996                        // If project file is none workspace.open_project_item will fail to open the excerpt
24997                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24998                        // so we check if there's a tab match in that case first
24999                        let editor = (!has_file || !is_project_file)
25000                            .then(|| {
25001                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
25002                                // so `workspace.open_project_item` will never find them, always opening a new editor.
25003                                // Instead, we try to activate the existing editor in the pane first.
25004                                let (editor, pane_item_index, pane_item_id) =
25005                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
25006                                        let editor = item.downcast::<Editor>()?;
25007                                        let singleton_buffer =
25008                                            editor.read(cx).buffer().read(cx).as_singleton()?;
25009                                        if singleton_buffer == buffer {
25010                                            Some((editor, i, item.item_id()))
25011                                        } else {
25012                                            None
25013                                        }
25014                                    })?;
25015                                pane.update(cx, |pane, cx| {
25016                                    pane.activate_item(pane_item_index, true, true, window, cx);
25017                                    if !PreviewTabsSettings::get_global(cx)
25018                                        .enable_preview_from_multibuffer
25019                                    {
25020                                        pane.unpreview_item_if_preview(pane_item_id);
25021                                    }
25022                                });
25023                                Some(editor)
25024                            })
25025                            .flatten()
25026                            .unwrap_or_else(|| {
25027                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
25028                                    .enable_keep_preview_on_code_navigation;
25029                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
25030                                    .enable_preview_from_multibuffer;
25031                                workspace.open_project_item::<Self>(
25032                                    pane.clone(),
25033                                    buffer,
25034                                    true,
25035                                    true,
25036                                    keep_old_preview,
25037                                    allow_new_preview,
25038                                    window,
25039                                    cx,
25040                                )
25041                            });
25042
25043                        editor.update(cx, |editor, cx| {
25044                            if has_file && !is_project_file {
25045                                editor.set_read_only(true);
25046                            }
25047                            let autoscroll = match scroll_offset {
25048                                Some(scroll_offset) => {
25049                                    Autoscroll::top_relative(scroll_offset as usize)
25050                                }
25051                                None => Autoscroll::newest(),
25052                            };
25053                            let nav_history = editor.nav_history.take();
25054                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
25055                            let Some(buffer_snapshot) = multibuffer_snapshot.as_singleton() else {
25056                                return;
25057                            };
25058                            editor.change_selections(
25059                                SelectionEffects::scroll(autoscroll),
25060                                window,
25061                                cx,
25062                                |s| {
25063                                    s.select_ranges(ranges.into_iter().map(|range| {
25064                                        let range = buffer_snapshot.anchor_before(range.start)
25065                                            ..buffer_snapshot.anchor_after(range.end);
25066                                        multibuffer_snapshot
25067                                            .buffer_anchor_range_to_anchor_range(range)
25068                                            .unwrap()
25069                                    }));
25070                                },
25071                            );
25072                            editor.nav_history = nav_history;
25073                        });
25074                    }
25075                })
25076                .ok();
25077        });
25078    }
25079
25080    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
25081        let snapshot = self.buffer.read(cx).read(cx);
25082        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
25083        Some(
25084            ranges
25085                .iter()
25086                .map(move |range| {
25087                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
25088                })
25089                .collect(),
25090        )
25091    }
25092
25093    fn selection_replacement_ranges(
25094        &self,
25095        range: Range<MultiBufferOffsetUtf16>,
25096        cx: &mut App,
25097    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
25098        let selections = self
25099            .selections
25100            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25101        let newest_selection = selections
25102            .iter()
25103            .max_by_key(|selection| selection.id)
25104            .unwrap();
25105        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
25106        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
25107        let snapshot = self.buffer.read(cx).read(cx);
25108        selections
25109            .into_iter()
25110            .map(|mut selection| {
25111                selection.start.0.0 =
25112                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
25113                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
25114                snapshot.clip_offset_utf16(selection.start, Bias::Left)
25115                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
25116            })
25117            .collect()
25118    }
25119
25120    fn report_editor_event(
25121        &self,
25122        reported_event: ReportEditorEvent,
25123        file_extension: Option<String>,
25124        cx: &App,
25125    ) {
25126        if cfg!(any(test, feature = "test-support")) {
25127            return;
25128        }
25129
25130        let Some(project) = &self.project else { return };
25131
25132        // If None, we are in a file without an extension
25133        let file = self
25134            .buffer
25135            .read(cx)
25136            .as_singleton()
25137            .and_then(|b| b.read(cx).file());
25138        let file_extension = file_extension.or(file
25139            .as_ref()
25140            .and_then(|file| Path::new(file.file_name(cx)).extension())
25141            .and_then(|e| e.to_str())
25142            .map(|a| a.to_string()));
25143
25144        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
25145            .map(|vim_mode| vim_mode.0)
25146            .unwrap_or(false);
25147
25148        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
25149        let copilot_enabled = edit_predictions_provider
25150            == language::language_settings::EditPredictionProvider::Copilot;
25151        let copilot_enabled_for_language = self
25152            .buffer
25153            .read(cx)
25154            .language_settings(cx)
25155            .show_edit_predictions;
25156
25157        let project = project.read(cx);
25158        let event_type = reported_event.event_type();
25159
25160        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
25161            telemetry::event!(
25162                event_type,
25163                type = if auto_saved {"autosave"} else {"manual"},
25164                file_extension,
25165                vim_mode,
25166                copilot_enabled,
25167                copilot_enabled_for_language,
25168                edit_predictions_provider,
25169                is_via_ssh = project.is_via_remote_server(),
25170            );
25171        } else {
25172            telemetry::event!(
25173                event_type,
25174                file_extension,
25175                vim_mode,
25176                copilot_enabled,
25177                copilot_enabled_for_language,
25178                edit_predictions_provider,
25179                is_via_ssh = project.is_via_remote_server(),
25180            );
25181        };
25182    }
25183
25184    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
25185    /// with each line being an array of {text, highlight} objects.
25186    fn copy_highlight_json(
25187        &mut self,
25188        _: &CopyHighlightJson,
25189        _: &mut Window,
25190        cx: &mut Context<Self>,
25191    ) {
25192        #[derive(Serialize)]
25193        struct Chunk<'a> {
25194            text: String,
25195            highlight: Option<&'a str>,
25196        }
25197
25198        let snapshot = self.buffer.read(cx).snapshot(cx);
25199        let mut selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
25200        let max_point = snapshot.max_point();
25201
25202        let range = if self.selections.line_mode() {
25203            selection.start = Point::new(selection.start.row, 0);
25204            selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
25205            selection.goal = SelectionGoal::None;
25206            selection.range()
25207        } else if selection.is_empty() {
25208            Point::new(0, 0)..max_point
25209        } else {
25210            selection.range()
25211        };
25212
25213        let chunks = snapshot.chunks(
25214            range,
25215            LanguageAwareStyling {
25216                tree_sitter: true,
25217                diagnostics: true,
25218            },
25219        );
25220        let mut lines = Vec::new();
25221        let mut line: VecDeque<Chunk> = VecDeque::new();
25222
25223        let Some(style) = self.style.as_ref() else {
25224            return;
25225        };
25226
25227        for chunk in chunks {
25228            let highlight = chunk
25229                .syntax_highlight_id
25230                .and_then(|id| style.syntax.get_capture_name(id));
25231
25232            let mut chunk_lines = chunk.text.split('\n').peekable();
25233            while let Some(text) = chunk_lines.next() {
25234                let mut merged_with_last_token = false;
25235                if let Some(last_token) = line.back_mut()
25236                    && last_token.highlight == highlight
25237                {
25238                    last_token.text.push_str(text);
25239                    merged_with_last_token = true;
25240                }
25241
25242                if !merged_with_last_token {
25243                    line.push_back(Chunk {
25244                        text: text.into(),
25245                        highlight,
25246                    });
25247                }
25248
25249                if chunk_lines.peek().is_some() {
25250                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
25251                        line.pop_front();
25252                    }
25253                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
25254                        line.pop_back();
25255                    }
25256
25257                    lines.push(mem::take(&mut line));
25258                }
25259            }
25260        }
25261
25262        if line.iter().any(|chunk| !chunk.text.is_empty()) {
25263            lines.push(line);
25264        }
25265
25266        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
25267            return;
25268        };
25269        cx.write_to_clipboard(ClipboardItem::new_string(lines));
25270    }
25271
25272    pub fn open_context_menu(
25273        &mut self,
25274        _: &OpenContextMenu,
25275        window: &mut Window,
25276        cx: &mut Context<Self>,
25277    ) {
25278        self.request_autoscroll(Autoscroll::newest(), cx);
25279        let position = self
25280            .selections
25281            .newest_display(&self.display_snapshot(cx))
25282            .start;
25283        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
25284    }
25285
25286    pub fn replay_insert_event(
25287        &mut self,
25288        text: &str,
25289        relative_utf16_range: Option<Range<isize>>,
25290        window: &mut Window,
25291        cx: &mut Context<Self>,
25292    ) {
25293        if !self.input_enabled {
25294            cx.emit(EditorEvent::InputIgnored { text: text.into() });
25295            return;
25296        }
25297        if let Some(relative_utf16_range) = relative_utf16_range {
25298            let selections = self
25299                .selections
25300                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
25301            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25302                let new_ranges = selections.into_iter().map(|range| {
25303                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
25304                        range
25305                            .head()
25306                            .0
25307                            .0
25308                            .saturating_add_signed(relative_utf16_range.start),
25309                    ));
25310                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
25311                        range
25312                            .head()
25313                            .0
25314                            .0
25315                            .saturating_add_signed(relative_utf16_range.end),
25316                    ));
25317                    start..end
25318                });
25319                s.select_ranges(new_ranges);
25320            });
25321        }
25322
25323        self.handle_input(text, window, cx);
25324    }
25325
25326    pub fn is_focused(&self, window: &Window) -> bool {
25327        self.focus_handle.is_focused(window)
25328    }
25329
25330    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25331        cx.emit(EditorEvent::Focused);
25332
25333        if let Some(descendant) = self
25334            .last_focused_descendant
25335            .take()
25336            .and_then(|descendant| descendant.upgrade())
25337        {
25338            window.focus(&descendant, cx);
25339        } else {
25340            if let Some(blame) = self.blame.as_ref() {
25341                blame.update(cx, GitBlame::focus)
25342            }
25343
25344            self.blink_manager.update(cx, BlinkManager::enable);
25345            self.show_cursor_names(window, cx);
25346            self.buffer.update(cx, |buffer, cx| {
25347                buffer.finalize_last_transaction(cx);
25348                if self.leader_id.is_none() {
25349                    buffer.set_active_selections(
25350                        &self.selections.disjoint_anchors_arc(),
25351                        self.selections.line_mode(),
25352                        self.cursor_shape,
25353                        cx,
25354                    );
25355                }
25356            });
25357
25358            if let Some(position_map) = self.last_position_map.clone()
25359                && !self.mouse_cursor_hidden
25360            {
25361                EditorElement::mouse_moved(
25362                    self,
25363                    &MouseMoveEvent {
25364                        position: window.mouse_position(),
25365                        pressed_button: None,
25366                        modifiers: window.modifiers(),
25367                    },
25368                    &position_map,
25369                    None,
25370                    window,
25371                    cx,
25372                );
25373            }
25374        }
25375    }
25376
25377    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
25378        cx.emit(EditorEvent::FocusedIn)
25379    }
25380
25381    fn handle_focus_out(
25382        &mut self,
25383        event: FocusOutEvent,
25384        _window: &mut Window,
25385        cx: &mut Context<Self>,
25386    ) {
25387        if event.blurred != self.focus_handle {
25388            self.last_focused_descendant = Some(event.blurred);
25389        }
25390        self.selection_drag_state = SelectionDragState::None;
25391        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
25392    }
25393
25394    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25395        self.blink_manager.update(cx, BlinkManager::disable);
25396        self.buffer
25397            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
25398
25399        if let Some(blame) = self.blame.as_ref() {
25400            blame.update(cx, GitBlame::blur)
25401        }
25402        if !self.hover_state.focused(window, cx) {
25403            hide_hover(self, cx);
25404        }
25405        if !self
25406            .context_menu
25407            .borrow()
25408            .as_ref()
25409            .is_some_and(|context_menu| context_menu.focused(window, cx))
25410        {
25411            self.hide_context_menu(window, cx);
25412        }
25413        self.take_active_edit_prediction(true, cx);
25414        cx.emit(EditorEvent::Blurred);
25415        cx.notify();
25416    }
25417
25418    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
25419        let mut pending: String = window
25420            .pending_input_keystrokes()
25421            .into_iter()
25422            .flatten()
25423            .filter_map(|keystroke| keystroke.key_char.clone())
25424            .collect();
25425
25426        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
25427            pending = "".to_string();
25428        }
25429
25430        let existing_pending = self
25431            .text_highlights(HighlightKey::PendingInput, cx)
25432            .map(|(_, ranges)| ranges.to_vec());
25433        if existing_pending.is_none() && pending.is_empty() {
25434            return;
25435        }
25436        let transaction =
25437            self.transact(window, cx, |this, window, cx| {
25438                let selections = this
25439                    .selections
25440                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
25441                let edits = selections
25442                    .iter()
25443                    .map(|selection| (selection.end..selection.end, pending.clone()));
25444                this.edit(edits, cx);
25445                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25446                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
25447                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
25448                    }));
25449                });
25450                if let Some(existing_ranges) = existing_pending {
25451                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
25452                    this.edit(edits, cx);
25453                }
25454            });
25455
25456        let snapshot = self.snapshot(window, cx);
25457        let ranges = self
25458            .selections
25459            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
25460            .into_iter()
25461            .map(|selection| {
25462                snapshot.buffer_snapshot().anchor_after(selection.end)
25463                    ..snapshot
25464                        .buffer_snapshot()
25465                        .anchor_before(selection.end + pending.len())
25466            })
25467            .collect();
25468
25469        if pending.is_empty() {
25470            self.clear_highlights(HighlightKey::PendingInput, cx);
25471        } else {
25472            self.highlight_text(
25473                HighlightKey::PendingInput,
25474                ranges,
25475                HighlightStyle {
25476                    underline: Some(UnderlineStyle {
25477                        thickness: px(1.),
25478                        color: None,
25479                        wavy: false,
25480                    }),
25481                    ..Default::default()
25482                },
25483                cx,
25484            );
25485        }
25486
25487        self.ime_transaction = self.ime_transaction.or(transaction);
25488        if let Some(transaction) = self.ime_transaction {
25489            self.buffer.update(cx, |buffer, cx| {
25490                buffer.group_until_transaction(transaction, cx);
25491            });
25492        }
25493
25494        if self
25495            .text_highlights(HighlightKey::PendingInput, cx)
25496            .is_none()
25497        {
25498            self.ime_transaction.take();
25499        }
25500    }
25501
25502    pub fn register_action_renderer(
25503        &mut self,
25504        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
25505    ) -> Subscription {
25506        let id = self.next_editor_action_id.post_inc();
25507        self.editor_actions
25508            .borrow_mut()
25509            .insert(id, Box::new(listener));
25510
25511        let editor_actions = self.editor_actions.clone();
25512        Subscription::new(move || {
25513            editor_actions.borrow_mut().remove(&id);
25514        })
25515    }
25516
25517    pub fn register_action<A: Action>(
25518        &mut self,
25519        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
25520    ) -> Subscription {
25521        let id = self.next_editor_action_id.post_inc();
25522        let listener = Arc::new(listener);
25523        self.editor_actions.borrow_mut().insert(
25524            id,
25525            Box::new(move |_, window, _| {
25526                let listener = listener.clone();
25527                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
25528                    let action = action.downcast_ref().unwrap();
25529                    if phase == DispatchPhase::Bubble {
25530                        listener(action, window, cx)
25531                    }
25532                })
25533            }),
25534        );
25535
25536        let editor_actions = self.editor_actions.clone();
25537        Subscription::new(move || {
25538            editor_actions.borrow_mut().remove(&id);
25539        })
25540    }
25541
25542    pub fn file_header_size(&self) -> u32 {
25543        FILE_HEADER_HEIGHT
25544    }
25545
25546    pub fn restore(
25547        &mut self,
25548        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
25549        window: &mut Window,
25550        cx: &mut Context<Self>,
25551    ) {
25552        self.buffer().update(cx, |multi_buffer, cx| {
25553            for (buffer_id, changes) in revert_changes {
25554                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
25555                    buffer.update(cx, |buffer, cx| {
25556                        buffer.edit(
25557                            changes
25558                                .into_iter()
25559                                .map(|(range, text)| (range, text.to_string())),
25560                            None,
25561                            cx,
25562                        );
25563                    });
25564                }
25565            }
25566        });
25567        let selections = self
25568            .selections
25569            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
25570        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25571            s.select(selections);
25572        });
25573    }
25574
25575    pub fn to_pixel_point(
25576        &mut self,
25577        source: Anchor,
25578        editor_snapshot: &EditorSnapshot,
25579        window: &mut Window,
25580        cx: &mut App,
25581    ) -> Option<gpui::Point<Pixels>> {
25582        let source_point = source.to_display_point(editor_snapshot);
25583        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
25584    }
25585
25586    pub fn display_to_pixel_point(
25587        &mut self,
25588        source: DisplayPoint,
25589        editor_snapshot: &EditorSnapshot,
25590        window: &mut Window,
25591        cx: &mut App,
25592    ) -> Option<gpui::Point<Pixels>> {
25593        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
25594        let text_layout_details = self.text_layout_details(window, cx);
25595        let scroll_top = text_layout_details
25596            .scroll_anchor
25597            .scroll_position(editor_snapshot)
25598            .y;
25599
25600        if source.row().as_f64() < scroll_top.floor() {
25601            return None;
25602        }
25603        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
25604        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
25605        Some(gpui::Point::new(source_x, source_y))
25606    }
25607
25608    pub fn has_visible_completions_menu(&self) -> bool {
25609        !self.edit_prediction_preview_is_active()
25610            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
25611                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
25612            })
25613    }
25614
25615    pub fn register_addon<T: Addon>(&mut self, instance: T) {
25616        if self.mode.is_minimap() {
25617            return;
25618        }
25619        self.addons
25620            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
25621    }
25622
25623    pub fn unregister_addon<T: Addon>(&mut self) {
25624        self.addons.remove(&std::any::TypeId::of::<T>());
25625    }
25626
25627    pub fn addon<T: Addon>(&self) -> Option<&T> {
25628        let type_id = std::any::TypeId::of::<T>();
25629        self.addons
25630            .get(&type_id)
25631            .and_then(|item| item.to_any().downcast_ref::<T>())
25632    }
25633
25634    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
25635        let type_id = std::any::TypeId::of::<T>();
25636        self.addons
25637            .get_mut(&type_id)
25638            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
25639    }
25640
25641    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
25642        let text_layout_details = self.text_layout_details(window, cx);
25643        let style = &text_layout_details.editor_style;
25644        let font_id = window.text_system().resolve_font(&style.text.font());
25645        let font_size = style.text.font_size.to_pixels(window.rem_size());
25646        let line_height = style.text.line_height_in_pixels(window.rem_size());
25647        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
25648        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
25649
25650        CharacterDimensions {
25651            em_width,
25652            em_advance,
25653            line_height,
25654        }
25655    }
25656
25657    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
25658        self.load_diff_task.clone()
25659    }
25660
25661    fn read_metadata_from_db(
25662        &mut self,
25663        item_id: u64,
25664        workspace_id: WorkspaceId,
25665        window: &mut Window,
25666        cx: &mut Context<Editor>,
25667    ) {
25668        if self.buffer_kind(cx) == ItemBufferKind::Singleton
25669            && !self.mode.is_minimap()
25670            && WorkspaceSettings::get(None, cx).restore_on_startup
25671                != RestoreOnStartupBehavior::EmptyTab
25672        {
25673            let buffer_snapshot = OnceCell::new();
25674
25675            // Get file path for path-based fold lookup
25676            let file_path: Option<Arc<Path>> =
25677                self.buffer().read(cx).as_singleton().and_then(|buffer| {
25678                    project::File::from_dyn(buffer.read(cx).file())
25679                        .map(|file| Arc::from(file.abs_path(cx)))
25680                });
25681
25682            // Try file_folds (path-based) first, fallback to editor_folds (migration)
25683            let db = EditorDb::global(cx);
25684            let (folds, needs_migration) = if let Some(ref path) = file_path {
25685                if let Some(folds) = db.get_file_folds(workspace_id, path).log_err()
25686                    && !folds.is_empty()
25687                {
25688                    (Some(folds), false)
25689                } else if let Some(folds) = db.get_editor_folds(item_id, workspace_id).log_err()
25690                    && !folds.is_empty()
25691                {
25692                    // Found old editor_folds data, will migrate to file_folds
25693                    (Some(folds), true)
25694                } else {
25695                    (None, false)
25696                }
25697            } else {
25698                // No file path, try editor_folds as fallback
25699                let folds = db.get_editor_folds(item_id, workspace_id).log_err();
25700                (folds.filter(|f| !f.is_empty()), false)
25701            };
25702
25703            if let Some(folds) = folds {
25704                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25705                let snapshot_len = snapshot.len().0;
25706
25707                // Helper: search for fingerprint in buffer, return offset if found
25708                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25709                    // Ensure we start at a character boundary (defensive)
25710                    let search_start = snapshot
25711                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25712                        .0;
25713                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25714
25715                    let mut byte_offset = search_start;
25716                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25717                        if byte_offset > search_end {
25718                            break;
25719                        }
25720                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25721                            return Some(byte_offset);
25722                        }
25723                        byte_offset += ch.len_utf8();
25724                    }
25725                    None
25726                };
25727
25728                // Track search position to handle duplicate fingerprints correctly.
25729                // Folds are stored in document order, so we advance after each match.
25730                let mut search_start = 0usize;
25731
25732                // Collect db_folds for migration (only folds with valid fingerprints)
25733                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25734
25735                let valid_folds: Vec<_> = folds
25736                    .into_iter()
25737                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25738                        // Skip folds without fingerprints (old data before migration)
25739                        let sfp = start_fp?;
25740                        let efp = end_fp?;
25741                        let efp_len = efp.len();
25742
25743                        // Fast path: check if fingerprints match at stored offsets
25744                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25745                        let start_matches = stored_start < snapshot_len
25746                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25747                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25748                        let end_matches = efp_check_pos >= stored_start
25749                            && stored_end <= snapshot_len
25750                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25751
25752                        let (new_start, new_end) = if start_matches && end_matches {
25753                            // Offsets unchanged, use stored values
25754                            (stored_start, stored_end)
25755                        } else if sfp == efp {
25756                            // Short fold: identical fingerprints can only match once per search
25757                            // Use stored fold length to compute new_end
25758                            let new_start = find_fingerprint(&sfp, search_start)?;
25759                            let fold_len = stored_end - stored_start;
25760                            let new_end = new_start + fold_len;
25761                            (new_start, new_end)
25762                        } else {
25763                            // Slow path: search for fingerprints in buffer
25764                            let new_start = find_fingerprint(&sfp, search_start)?;
25765                            // Search for end_fp after start, then add efp_len to get actual fold end
25766                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25767                            let new_end = efp_pos + efp_len;
25768                            (new_start, new_end)
25769                        };
25770
25771                        // Advance search position for next fold
25772                        search_start = new_end;
25773
25774                        // Validate fold makes sense (end must be after start)
25775                        if new_end <= new_start {
25776                            return None;
25777                        }
25778
25779                        // Collect for migration if needed
25780                        if needs_migration {
25781                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25782                        }
25783
25784                        Some(
25785                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25786                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25787                        )
25788                    })
25789                    .collect();
25790
25791                if !valid_folds.is_empty() {
25792                    self.fold_ranges(valid_folds, false, window, cx);
25793
25794                    // Migrate from editor_folds to file_folds if we loaded from old table
25795                    if needs_migration {
25796                        if let Some(ref path) = file_path {
25797                            let path = path.clone();
25798                            let db = EditorDb::global(cx);
25799                            cx.spawn(async move |_, _| {
25800                                db.save_file_folds(workspace_id, path, db_folds_for_migration)
25801                                    .await
25802                                    .log_err();
25803                            })
25804                            .detach();
25805                        }
25806                    }
25807                }
25808            }
25809
25810            if let Some(selections) = db.get_editor_selections(item_id, workspace_id).log_err()
25811                && !selections.is_empty()
25812            {
25813                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25814                // skip adding the initial selection to selection history
25815                self.selection_history.mode = SelectionHistoryMode::Skipping;
25816                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25817                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25818                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25819                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25820                    }));
25821                });
25822                self.selection_history.mode = SelectionHistoryMode::Normal;
25823            };
25824        }
25825
25826        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25827    }
25828
25829    /// Load folds from the file_folds database table by file path.
25830    /// Used when manually opening a file that was previously closed.
25831    fn load_folds_from_db(
25832        &mut self,
25833        workspace_id: WorkspaceId,
25834        file_path: PathBuf,
25835        window: &mut Window,
25836        cx: &mut Context<Editor>,
25837    ) {
25838        if self.mode.is_minimap()
25839            || WorkspaceSettings::get(None, cx).restore_on_startup
25840                == RestoreOnStartupBehavior::EmptyTab
25841        {
25842            return;
25843        }
25844
25845        let Some(folds) = EditorDb::global(cx)
25846            .get_file_folds(workspace_id, &file_path)
25847            .log_err()
25848        else {
25849            return;
25850        };
25851        if folds.is_empty() {
25852            return;
25853        }
25854
25855        let snapshot = self.buffer.read(cx).snapshot(cx);
25856        let snapshot_len = snapshot.len().0;
25857
25858        // Helper: search for fingerprint in buffer, return offset if found
25859        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25860            let search_start = snapshot
25861                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25862                .0;
25863            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25864
25865            let mut byte_offset = search_start;
25866            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25867                if byte_offset > search_end {
25868                    break;
25869                }
25870                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25871                    return Some(byte_offset);
25872                }
25873                byte_offset += ch.len_utf8();
25874            }
25875            None
25876        };
25877
25878        let mut search_start = 0usize;
25879
25880        let valid_folds: Vec<_> = folds
25881            .into_iter()
25882            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25883                let sfp = start_fp?;
25884                let efp = end_fp?;
25885                let efp_len = efp.len();
25886
25887                let start_matches = stored_start < snapshot_len
25888                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25889                let efp_check_pos = stored_end.saturating_sub(efp_len);
25890                let end_matches = efp_check_pos >= stored_start
25891                    && stored_end <= snapshot_len
25892                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25893
25894                let (new_start, new_end) = if start_matches && end_matches {
25895                    (stored_start, stored_end)
25896                } else if sfp == efp {
25897                    let new_start = find_fingerprint(&sfp, search_start)?;
25898                    let fold_len = stored_end - stored_start;
25899                    let new_end = new_start + fold_len;
25900                    (new_start, new_end)
25901                } else {
25902                    let new_start = find_fingerprint(&sfp, search_start)?;
25903                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25904                    let new_end = efp_pos + efp_len;
25905                    (new_start, new_end)
25906                };
25907
25908                search_start = new_end;
25909
25910                if new_end <= new_start {
25911                    return None;
25912                }
25913
25914                Some(
25915                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25916                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25917                )
25918            })
25919            .collect();
25920
25921        if !valid_folds.is_empty() {
25922            self.fold_ranges(valid_folds, false, window, cx);
25923        }
25924    }
25925
25926    fn lsp_data_enabled(&self) -> bool {
25927        self.enable_lsp_data && self.mode().is_full()
25928    }
25929
25930    fn update_lsp_data(
25931        &mut self,
25932        for_buffer: Option<BufferId>,
25933        window: &mut Window,
25934        cx: &mut Context<'_, Self>,
25935    ) {
25936        if !self.lsp_data_enabled() {
25937            return;
25938        }
25939
25940        if let Some(buffer_id) = for_buffer {
25941            self.pull_diagnostics(buffer_id, window, cx);
25942        }
25943        self.refresh_semantic_tokens(for_buffer, None, cx);
25944        self.refresh_document_colors(for_buffer, window, cx);
25945        self.refresh_folding_ranges(for_buffer, window, cx);
25946        self.refresh_document_symbols(for_buffer, cx);
25947    }
25948
25949    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25950        if !self.lsp_data_enabled() {
25951            return;
25952        }
25953        let visible_buffers: Vec<_> = self
25954            .visible_buffers(cx)
25955            .into_iter()
25956            .filter(|buffer| self.is_lsp_relevant(buffer.read(cx).file(), cx))
25957            .collect();
25958        for visible_buffer in visible_buffers {
25959            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25960        }
25961    }
25962
25963    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25964        if !self.lsp_data_enabled() {
25965            return;
25966        }
25967
25968        if !self.registered_buffers.contains_key(&buffer_id)
25969            && let Some(project) = self.project.as_ref()
25970        {
25971            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25972                project.update(cx, |project, cx| {
25973                    self.registered_buffers.insert(
25974                        buffer_id,
25975                        project.register_buffer_with_language_servers(&buffer, cx),
25976                    );
25977                });
25978            } else {
25979                self.registered_buffers.remove(&buffer_id);
25980            }
25981        }
25982    }
25983
25984    fn create_style(&self, cx: &App) -> EditorStyle {
25985        let settings = ThemeSettings::get_global(cx);
25986
25987        let mut text_style = match self.mode {
25988            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25989                color: cx.theme().colors().editor_foreground,
25990                font_family: settings.ui_font.family.clone(),
25991                font_features: settings.ui_font.features.clone(),
25992                font_fallbacks: settings.ui_font.fallbacks.clone(),
25993                font_size: rems(0.875).into(),
25994                font_weight: settings.ui_font.weight,
25995                line_height: relative(settings.buffer_line_height.value()),
25996                ..Default::default()
25997            },
25998            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25999                color: cx.theme().colors().editor_foreground,
26000                font_family: settings.buffer_font.family.clone(),
26001                font_features: settings.buffer_font.features.clone(),
26002                font_fallbacks: settings.buffer_font.fallbacks.clone(),
26003                font_size: settings.buffer_font_size(cx).into(),
26004                font_weight: settings.buffer_font.weight,
26005                line_height: relative(settings.buffer_line_height.value()),
26006                ..Default::default()
26007            },
26008        };
26009        if let Some(text_style_refinement) = &self.text_style_refinement {
26010            text_style.refine(text_style_refinement)
26011        }
26012
26013        let background = match self.mode {
26014            EditorMode::SingleLine => cx.theme().system().transparent,
26015            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
26016            EditorMode::Full { .. } => cx.theme().colors().editor_background,
26017            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
26018        };
26019
26020        EditorStyle {
26021            background,
26022            border: cx.theme().colors().border,
26023            local_player: cx.theme().players().local(),
26024            text: text_style,
26025            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
26026            syntax: cx.theme().syntax().clone(),
26027            status: cx.theme().status().clone(),
26028            inlay_hints_style: make_inlay_hints_style(cx),
26029            edit_prediction_styles: make_suggestion_styles(cx),
26030            unnecessary_code_fade: settings.unnecessary_code_fade,
26031            show_underlines: self.diagnostics_enabled(),
26032        }
26033    }
26034
26035    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
26036        let multibuffer = self.buffer().read(cx);
26037        let is_singleton = multibuffer.is_singleton();
26038        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
26039        let buffer = multibuffer.buffer(*buffer_id)?;
26040
26041        let buffer = buffer.read(cx);
26042        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
26043        let mut breadcrumbs = if is_singleton {
26044            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
26045                buffer
26046                    .snapshot()
26047                    .resolve_file_path(
26048                        self.project
26049                            .as_ref()
26050                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
26051                            .unwrap_or_default(),
26052                        cx,
26053                    )
26054                    .unwrap_or_else(|| {
26055                        if multibuffer.is_singleton() {
26056                            multibuffer.title(cx).to_string()
26057                        } else {
26058                            "untitled".to_string()
26059                        }
26060                    })
26061            });
26062            vec![HighlightedText {
26063                text: text.into(),
26064                highlights: vec![],
26065            }]
26066        } else {
26067            vec![]
26068        };
26069
26070        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
26071            text: symbol.text.clone().into(),
26072            highlights: symbol.highlight_ranges.clone(),
26073        }));
26074        Some(breadcrumbs)
26075    }
26076
26077    fn disable_lsp_data(&mut self) {
26078        self.enable_lsp_data = false;
26079    }
26080
26081    fn disable_runnables(&mut self) {
26082        self.enable_runnables = false;
26083    }
26084
26085    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
26086        self.register_visible_buffers(cx);
26087        self.colorize_brackets(false, cx);
26088        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
26089        if !self.buffer().read(cx).is_singleton() {
26090            self.update_lsp_data(None, window, cx);
26091            self.refresh_runnables(None, window, cx);
26092        }
26093    }
26094}
26095
26096fn edit_for_markdown_paste<'a>(
26097    buffer: &MultiBufferSnapshot,
26098    range: Range<MultiBufferOffset>,
26099    to_insert: &'a str,
26100    url: Option<url::Url>,
26101) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
26102    if url.is_none() {
26103        return (range, Cow::Borrowed(to_insert));
26104    };
26105
26106    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
26107
26108    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
26109        Cow::Borrowed(to_insert)
26110    } else {
26111        Cow::Owned(format!("[{old_text}]({to_insert})"))
26112    };
26113    (range, new_text)
26114}
26115
26116fn process_completion_for_edit(
26117    completion: &Completion,
26118    intent: CompletionIntent,
26119    buffer: &Entity<Buffer>,
26120    cursor_position: &text::Anchor,
26121    cx: &mut Context<Editor>,
26122) -> CompletionEdit {
26123    let buffer = buffer.read(cx);
26124    let buffer_snapshot = buffer.snapshot();
26125    let (snippet, new_text) = if completion.is_snippet() {
26126        let mut snippet_source = completion.new_text.clone();
26127        // Workaround for typescript language server issues so that methods don't expand within
26128        // strings and functions with type expressions. The previous point is used because the query
26129        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
26130        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
26131        let previous_point = if previous_point.column > 0 {
26132            cursor_position.to_previous_offset(&buffer_snapshot)
26133        } else {
26134            cursor_position.to_offset(&buffer_snapshot)
26135        };
26136        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
26137            && scope.prefers_label_for_snippet_in_completion()
26138            && let Some(label) = completion.label()
26139            && matches!(
26140                completion.kind(),
26141                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
26142            )
26143        {
26144            snippet_source = label;
26145        }
26146        match Snippet::parse(&snippet_source).log_err() {
26147            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
26148            None => (None, completion.new_text.clone()),
26149        }
26150    } else {
26151        (None, completion.new_text.clone())
26152    };
26153
26154    let mut range_to_replace = {
26155        let replace_range = &completion.replace_range;
26156        if let CompletionSource::Lsp {
26157            insert_range: Some(insert_range),
26158            ..
26159        } = &completion.source
26160        {
26161            debug_assert_eq!(
26162                insert_range.start, replace_range.start,
26163                "insert_range and replace_range should start at the same position"
26164            );
26165            debug_assert!(
26166                insert_range
26167                    .start
26168                    .cmp(cursor_position, &buffer_snapshot)
26169                    .is_le(),
26170                "insert_range should start before or at cursor position"
26171            );
26172            debug_assert!(
26173                replace_range
26174                    .start
26175                    .cmp(cursor_position, &buffer_snapshot)
26176                    .is_le(),
26177                "replace_range should start before or at cursor position"
26178            );
26179
26180            let should_replace = match intent {
26181                CompletionIntent::CompleteWithInsert => false,
26182                CompletionIntent::CompleteWithReplace => true,
26183                CompletionIntent::Complete | CompletionIntent::Compose => {
26184                    let insert_mode = LanguageSettings::for_buffer(&buffer, cx)
26185                        .completions
26186                        .lsp_insert_mode;
26187                    match insert_mode {
26188                        LspInsertMode::Insert => false,
26189                        LspInsertMode::Replace => true,
26190                        LspInsertMode::ReplaceSubsequence => {
26191                            let mut text_to_replace = buffer.chars_for_range(
26192                                buffer.anchor_before(replace_range.start)
26193                                    ..buffer.anchor_after(replace_range.end),
26194                            );
26195                            let mut current_needle = text_to_replace.next();
26196                            for haystack_ch in completion.label.text.chars() {
26197                                if let Some(needle_ch) = current_needle
26198                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
26199                                {
26200                                    current_needle = text_to_replace.next();
26201                                }
26202                            }
26203                            current_needle.is_none()
26204                        }
26205                        LspInsertMode::ReplaceSuffix => {
26206                            if replace_range
26207                                .end
26208                                .cmp(cursor_position, &buffer_snapshot)
26209                                .is_gt()
26210                            {
26211                                let range_after_cursor = *cursor_position..replace_range.end;
26212                                let text_after_cursor = buffer
26213                                    .text_for_range(
26214                                        buffer.anchor_before(range_after_cursor.start)
26215                                            ..buffer.anchor_after(range_after_cursor.end),
26216                                    )
26217                                    .collect::<String>()
26218                                    .to_ascii_lowercase();
26219                                completion
26220                                    .label
26221                                    .text
26222                                    .to_ascii_lowercase()
26223                                    .ends_with(&text_after_cursor)
26224                            } else {
26225                                true
26226                            }
26227                        }
26228                    }
26229                }
26230            };
26231
26232            if should_replace {
26233                replace_range.clone()
26234            } else {
26235                insert_range.clone()
26236            }
26237        } else {
26238            replace_range.clone()
26239        }
26240    };
26241
26242    if range_to_replace
26243        .end
26244        .cmp(cursor_position, &buffer_snapshot)
26245        .is_lt()
26246    {
26247        range_to_replace.end = *cursor_position;
26248    }
26249
26250    CompletionEdit {
26251        new_text,
26252        replace_range: range_to_replace,
26253        snippet,
26254    }
26255}
26256
26257struct CompletionEdit {
26258    new_text: String,
26259    replace_range: Range<text::Anchor>,
26260    snippet: Option<Snippet>,
26261}
26262
26263fn comment_delimiter_for_newline(
26264    start_point: &Point,
26265    buffer: &MultiBufferSnapshot,
26266    language: &LanguageScope,
26267) -> Option<Arc<str>> {
26268    let delimiters = language.line_comment_prefixes();
26269    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
26270    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26271
26272    let num_of_whitespaces = snapshot
26273        .chars_for_range(range.clone())
26274        .take_while(|c| c.is_whitespace())
26275        .count();
26276    let comment_candidate = snapshot
26277        .chars_for_range(range.clone())
26278        .skip(num_of_whitespaces)
26279        .take(max_len_of_delimiter + 2)
26280        .collect::<String>();
26281    let (delimiter, trimmed_len, is_repl) = delimiters
26282        .iter()
26283        .filter_map(|delimiter| {
26284            let prefix = delimiter.trim_end();
26285            if comment_candidate.starts_with(prefix) {
26286                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
26287                {
26288                    stripped_comment.starts_with(" %%")
26289                } else {
26290                    false
26291                };
26292                Some((delimiter, prefix.len(), is_repl))
26293            } else {
26294                None
26295            }
26296        })
26297        .max_by_key(|(_, len, _)| *len)?;
26298
26299    if let Some(BlockCommentConfig {
26300        start: block_start, ..
26301    }) = language.block_comment()
26302    {
26303        let block_start_trimmed = block_start.trim_end();
26304        if block_start_trimmed.starts_with(delimiter.trim_end()) {
26305            let line_content = snapshot
26306                .chars_for_range(range.clone())
26307                .skip(num_of_whitespaces)
26308                .take(block_start_trimmed.len())
26309                .collect::<String>();
26310
26311            if line_content.starts_with(block_start_trimmed) {
26312                return None;
26313            }
26314        }
26315    }
26316
26317    let cursor_is_placed_after_comment_marker =
26318        num_of_whitespaces + trimmed_len <= start_point.column as usize;
26319    if cursor_is_placed_after_comment_marker {
26320        if !is_repl {
26321            return Some(delimiter.clone());
26322        }
26323
26324        let line_content_after_cursor: String = snapshot
26325            .chars_for_range(range)
26326            .skip(start_point.column as usize)
26327            .collect();
26328
26329        if line_content_after_cursor.trim().is_empty() {
26330            return None;
26331        } else {
26332            return Some(delimiter.clone());
26333        }
26334    } else {
26335        None
26336    }
26337}
26338
26339fn documentation_delimiter_for_newline(
26340    start_point: &Point,
26341    buffer: &MultiBufferSnapshot,
26342    language: &LanguageScope,
26343    newline_config: &mut NewlineConfig,
26344) -> Option<Arc<str>> {
26345    let BlockCommentConfig {
26346        start: start_tag,
26347        end: end_tag,
26348        prefix: delimiter,
26349        tab_size: len,
26350    } = language.documentation_comment()?;
26351    let is_within_block_comment = buffer
26352        .language_scope_at(*start_point)
26353        .is_some_and(|scope| scope.override_name() == Some("comment"));
26354    if !is_within_block_comment {
26355        return None;
26356    }
26357
26358    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26359
26360    let num_of_whitespaces = snapshot
26361        .chars_for_range(range.clone())
26362        .take_while(|c| c.is_whitespace())
26363        .count();
26364
26365    // 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.
26366    let column = start_point.column;
26367    let cursor_is_after_start_tag = {
26368        let start_tag_len = start_tag.len();
26369        let start_tag_line = snapshot
26370            .chars_for_range(range.clone())
26371            .skip(num_of_whitespaces)
26372            .take(start_tag_len)
26373            .collect::<String>();
26374        if start_tag_line.starts_with(start_tag.as_ref()) {
26375            num_of_whitespaces + start_tag_len <= column as usize
26376        } else {
26377            false
26378        }
26379    };
26380
26381    let cursor_is_after_delimiter = {
26382        let delimiter_trim = delimiter.trim_end();
26383        let delimiter_line = snapshot
26384            .chars_for_range(range.clone())
26385            .skip(num_of_whitespaces)
26386            .take(delimiter_trim.len())
26387            .collect::<String>();
26388        if delimiter_line.starts_with(delimiter_trim) {
26389            num_of_whitespaces + delimiter_trim.len() <= column as usize
26390        } else {
26391            false
26392        }
26393    };
26394
26395    let mut needs_extra_line = false;
26396    let mut extra_line_additional_indent = IndentSize::spaces(0);
26397
26398    let cursor_is_before_end_tag_if_exists = {
26399        let mut char_position = 0u32;
26400        let mut end_tag_offset = None;
26401
26402        'outer: for chunk in snapshot.text_for_range(range) {
26403            if let Some(byte_pos) = chunk.find(&**end_tag) {
26404                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
26405                end_tag_offset = Some(char_position + chars_before_match);
26406                break 'outer;
26407            }
26408            char_position += chunk.chars().count() as u32;
26409        }
26410
26411        if let Some(end_tag_offset) = end_tag_offset {
26412            let cursor_is_before_end_tag = column <= end_tag_offset;
26413            if cursor_is_after_start_tag {
26414                if cursor_is_before_end_tag {
26415                    needs_extra_line = true;
26416                }
26417                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
26418                if cursor_is_at_start_of_end_tag {
26419                    extra_line_additional_indent.len = *len;
26420                }
26421            }
26422            cursor_is_before_end_tag
26423        } else {
26424            true
26425        }
26426    };
26427
26428    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
26429        && cursor_is_before_end_tag_if_exists
26430    {
26431        let additional_indent = if cursor_is_after_start_tag {
26432            IndentSize::spaces(*len)
26433        } else {
26434            IndentSize::spaces(0)
26435        };
26436
26437        *newline_config = NewlineConfig::Newline {
26438            additional_indent,
26439            extra_line_additional_indent: if needs_extra_line {
26440                Some(extra_line_additional_indent)
26441            } else {
26442                None
26443            },
26444            prevent_auto_indent: true,
26445        };
26446        Some(delimiter.clone())
26447    } else {
26448        None
26449    }
26450}
26451
26452const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
26453
26454fn list_delimiter_for_newline(
26455    start_point: &Point,
26456    buffer: &MultiBufferSnapshot,
26457    language: &LanguageScope,
26458    newline_config: &mut NewlineConfig,
26459) -> Option<Arc<str>> {
26460    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
26461
26462    let num_of_whitespaces = snapshot
26463        .chars_for_range(range.clone())
26464        .take_while(|c| c.is_whitespace())
26465        .count();
26466
26467    let task_list_entries: Vec<_> = language
26468        .task_list()
26469        .into_iter()
26470        .flat_map(|config| {
26471            config
26472                .prefixes
26473                .iter()
26474                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
26475        })
26476        .collect();
26477    let unordered_list_entries: Vec<_> = language
26478        .unordered_list()
26479        .iter()
26480        .map(|marker| (marker.as_ref(), marker.as_ref()))
26481        .collect();
26482
26483    let all_entries: Vec<_> = task_list_entries
26484        .into_iter()
26485        .chain(unordered_list_entries)
26486        .collect();
26487
26488    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
26489        let candidate: String = snapshot
26490            .chars_for_range(range.clone())
26491            .skip(num_of_whitespaces)
26492            .take(max_prefix_len)
26493            .collect();
26494
26495        if let Some((prefix, continuation)) = all_entries
26496            .iter()
26497            .filter(|(prefix, _)| candidate.starts_with(*prefix))
26498            .max_by_key(|(prefix, _)| prefix.len())
26499        {
26500            let end_of_prefix = num_of_whitespaces + prefix.len();
26501            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26502            let has_content_after_marker = snapshot
26503                .chars_for_range(range)
26504                .skip(end_of_prefix)
26505                .any(|c| !c.is_whitespace());
26506
26507            if has_content_after_marker && cursor_is_after_prefix {
26508                return Some((*continuation).into());
26509            }
26510
26511            if start_point.column as usize == end_of_prefix {
26512                if num_of_whitespaces == 0 {
26513                    *newline_config = NewlineConfig::ClearCurrentLine;
26514                } else {
26515                    *newline_config = NewlineConfig::UnindentCurrentLine {
26516                        continuation: (*continuation).into(),
26517                    };
26518                }
26519            }
26520
26521            return None;
26522        }
26523    }
26524
26525    let candidate: String = snapshot
26526        .chars_for_range(range.clone())
26527        .skip(num_of_whitespaces)
26528        .take(ORDERED_LIST_MAX_MARKER_LEN)
26529        .collect();
26530
26531    for ordered_config in language.ordered_list() {
26532        let regex = match Regex::new(&ordered_config.pattern) {
26533            Ok(r) => r,
26534            Err(_) => continue,
26535        };
26536
26537        if let Some(captures) = regex.captures(&candidate) {
26538            let full_match = captures.get(0)?;
26539            let marker_len = full_match.len();
26540            let end_of_prefix = num_of_whitespaces + marker_len;
26541            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
26542
26543            let has_content_after_marker = snapshot
26544                .chars_for_range(range)
26545                .skip(end_of_prefix)
26546                .any(|c| !c.is_whitespace());
26547
26548            if has_content_after_marker && cursor_is_after_prefix {
26549                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
26550                let continuation = ordered_config
26551                    .format
26552                    .replace("{1}", &(number + 1).to_string());
26553                return Some(continuation.into());
26554            }
26555
26556            if start_point.column as usize == end_of_prefix {
26557                let continuation = ordered_config.format.replace("{1}", "1");
26558                if num_of_whitespaces == 0 {
26559                    *newline_config = NewlineConfig::ClearCurrentLine;
26560                } else {
26561                    *newline_config = NewlineConfig::UnindentCurrentLine {
26562                        continuation: continuation.into(),
26563                    };
26564                }
26565            }
26566
26567            return None;
26568        }
26569    }
26570
26571    None
26572}
26573
26574fn is_list_prefix_row(
26575    row: MultiBufferRow,
26576    buffer: &MultiBufferSnapshot,
26577    language: &LanguageScope,
26578) -> bool {
26579    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
26580        return false;
26581    };
26582
26583    let num_of_whitespaces = snapshot
26584        .chars_for_range(range.clone())
26585        .take_while(|c| c.is_whitespace())
26586        .count();
26587
26588    let task_list_prefixes: Vec<_> = language
26589        .task_list()
26590        .into_iter()
26591        .flat_map(|config| {
26592            config
26593                .prefixes
26594                .iter()
26595                .map(|p| p.as_ref())
26596                .collect::<Vec<_>>()
26597        })
26598        .collect();
26599    let unordered_list_markers: Vec<_> = language
26600        .unordered_list()
26601        .iter()
26602        .map(|marker| marker.as_ref())
26603        .collect();
26604    let all_prefixes: Vec<_> = task_list_prefixes
26605        .into_iter()
26606        .chain(unordered_list_markers)
26607        .collect();
26608    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
26609        let candidate: String = snapshot
26610            .chars_for_range(range.clone())
26611            .skip(num_of_whitespaces)
26612            .take(max_prefix_len)
26613            .collect();
26614        if all_prefixes
26615            .iter()
26616            .any(|prefix| candidate.starts_with(*prefix))
26617        {
26618            return true;
26619        }
26620    }
26621
26622    let ordered_list_candidate: String = snapshot
26623        .chars_for_range(range)
26624        .skip(num_of_whitespaces)
26625        .take(ORDERED_LIST_MAX_MARKER_LEN)
26626        .collect();
26627    for ordered_config in language.ordered_list() {
26628        let regex = match Regex::new(&ordered_config.pattern) {
26629            Ok(r) => r,
26630            Err(_) => continue,
26631        };
26632        if let Some(captures) = regex.captures(&ordered_list_candidate) {
26633            return captures.get(0).is_some();
26634        }
26635    }
26636
26637    false
26638}
26639
26640#[derive(Debug)]
26641enum NewlineConfig {
26642    /// Insert newline with optional additional indent and optional extra blank line
26643    Newline {
26644        additional_indent: IndentSize,
26645        extra_line_additional_indent: Option<IndentSize>,
26646        prevent_auto_indent: bool,
26647    },
26648    /// Clear the current line
26649    ClearCurrentLine,
26650    /// Unindent the current line and add continuation
26651    UnindentCurrentLine { continuation: Arc<str> },
26652}
26653
26654impl NewlineConfig {
26655    fn has_extra_line(&self) -> bool {
26656        matches!(
26657            self,
26658            Self::Newline {
26659                extra_line_additional_indent: Some(_),
26660                ..
26661            }
26662        )
26663    }
26664
26665    fn insert_extra_newline_brackets(
26666        buffer: &MultiBufferSnapshot,
26667        range: Range<MultiBufferOffset>,
26668        language: &language::LanguageScope,
26669    ) -> bool {
26670        let leading_whitespace_len = buffer
26671            .reversed_chars_at(range.start)
26672            .take_while(|c| c.is_whitespace() && *c != '\n')
26673            .map(|c| c.len_utf8())
26674            .sum::<usize>();
26675        let trailing_whitespace_len = buffer
26676            .chars_at(range.end)
26677            .take_while(|c| c.is_whitespace() && *c != '\n')
26678            .map(|c| c.len_utf8())
26679            .sum::<usize>();
26680        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
26681
26682        language.brackets().any(|(pair, enabled)| {
26683            let pair_start = pair.start.trim_end();
26684            let pair_end = pair.end.trim_start();
26685
26686            enabled
26687                && pair.newline
26688                && buffer.contains_str_at(range.end, pair_end)
26689                && buffer.contains_str_at(
26690                    range.start.saturating_sub_usize(pair_start.len()),
26691                    pair_start,
26692                )
26693        })
26694    }
26695
26696    fn insert_extra_newline_tree_sitter(
26697        buffer: &MultiBufferSnapshot,
26698        range: Range<MultiBufferOffset>,
26699    ) -> bool {
26700        let (buffer, range) = match buffer
26701            .range_to_buffer_ranges(range.start..range.end)
26702            .as_slice()
26703        {
26704            [(buffer_snapshot, range, _)] => (buffer_snapshot.clone(), range.clone()),
26705            _ => return false,
26706        };
26707        let pair = {
26708            let mut result: Option<BracketMatch<usize>> = None;
26709
26710            for pair in buffer
26711                .all_bracket_ranges(range.start.0..range.end.0)
26712                .filter(move |pair| {
26713                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26714                })
26715            {
26716                let len = pair.close_range.end - pair.open_range.start;
26717
26718                if let Some(existing) = &result {
26719                    let existing_len = existing.close_range.end - existing.open_range.start;
26720                    if len > existing_len {
26721                        continue;
26722                    }
26723                }
26724
26725                result = Some(pair);
26726            }
26727
26728            result
26729        };
26730        let Some(pair) = pair else {
26731            return false;
26732        };
26733        pair.newline_only
26734            && buffer
26735                .chars_for_range(pair.open_range.end..range.start.0)
26736                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26737                .all(|c| c.is_whitespace() && c != '\n')
26738    }
26739}
26740
26741fn update_uncommitted_diff_for_buffer(
26742    editor: Entity<Editor>,
26743    project: &Entity<Project>,
26744    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26745    buffer: Entity<MultiBuffer>,
26746    cx: &mut App,
26747) -> Task<()> {
26748    let mut tasks = Vec::new();
26749    project.update(cx, |project, cx| {
26750        for buffer in buffers {
26751            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26752                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26753            }
26754        }
26755    });
26756    cx.spawn(async move |cx| {
26757        let diffs = future::join_all(tasks).await;
26758        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26759            return;
26760        }
26761
26762        buffer.update(cx, |buffer, cx| {
26763            for diff in diffs.into_iter().flatten() {
26764                buffer.add_diff(diff, cx);
26765            }
26766        });
26767    })
26768}
26769
26770fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26771    let tab_size = tab_size.get() as usize;
26772    let mut width = offset;
26773
26774    for ch in text.chars() {
26775        width += if ch == '\t' {
26776            tab_size - (width % tab_size)
26777        } else {
26778            1
26779        };
26780    }
26781
26782    width - offset
26783}
26784
26785#[cfg(test)]
26786mod tests {
26787    use super::*;
26788
26789    #[test]
26790    fn test_string_size_with_expanded_tabs() {
26791        let nz = |val| NonZeroU32::new(val).unwrap();
26792        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26793        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26794        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26795        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26796        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26797        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26798        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26799        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26800    }
26801}
26802
26803/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26804struct WordBreakingTokenizer<'a> {
26805    input: &'a str,
26806}
26807
26808impl<'a> WordBreakingTokenizer<'a> {
26809    fn new(input: &'a str) -> Self {
26810        Self { input }
26811    }
26812}
26813
26814fn is_char_ideographic(ch: char) -> bool {
26815    use unicode_script::Script::*;
26816    use unicode_script::UnicodeScript;
26817    matches!(ch.script(), Han | Tangut | Yi)
26818}
26819
26820fn is_grapheme_ideographic(text: &str) -> bool {
26821    text.chars().any(is_char_ideographic)
26822}
26823
26824fn is_grapheme_whitespace(text: &str) -> bool {
26825    text.chars().any(|x| x.is_whitespace())
26826}
26827
26828fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26829    text.chars()
26830        .next()
26831        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26832}
26833
26834#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26835enum WordBreakToken<'a> {
26836    Word { token: &'a str, grapheme_len: usize },
26837    InlineWhitespace { token: &'a str, grapheme_len: usize },
26838    Newline,
26839}
26840
26841impl<'a> Iterator for WordBreakingTokenizer<'a> {
26842    /// Yields a span, the count of graphemes in the token, and whether it was
26843    /// whitespace. Note that it also breaks at word boundaries.
26844    type Item = WordBreakToken<'a>;
26845
26846    fn next(&mut self) -> Option<Self::Item> {
26847        use unicode_segmentation::UnicodeSegmentation;
26848        if self.input.is_empty() {
26849            return None;
26850        }
26851
26852        let mut iter = self.input.graphemes(true).peekable();
26853        let mut offset = 0;
26854        let mut grapheme_len = 0;
26855        if let Some(first_grapheme) = iter.next() {
26856            let is_newline = first_grapheme == "\n";
26857            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26858            offset += first_grapheme.len();
26859            grapheme_len += 1;
26860            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26861                if let Some(grapheme) = iter.peek().copied()
26862                    && should_stay_with_preceding_ideograph(grapheme)
26863                {
26864                    offset += grapheme.len();
26865                    grapheme_len += 1;
26866                }
26867            } else {
26868                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26869                let mut next_word_bound = words.peek().copied();
26870                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26871                    next_word_bound = words.next();
26872                }
26873                while let Some(grapheme) = iter.peek().copied() {
26874                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26875                        break;
26876                    };
26877                    if is_grapheme_whitespace(grapheme) != is_whitespace
26878                        || (grapheme == "\n") != is_newline
26879                    {
26880                        break;
26881                    };
26882                    offset += grapheme.len();
26883                    grapheme_len += 1;
26884                    iter.next();
26885                }
26886            }
26887            let token = &self.input[..offset];
26888            self.input = &self.input[offset..];
26889            if token == "\n" {
26890                Some(WordBreakToken::Newline)
26891            } else if is_whitespace {
26892                Some(WordBreakToken::InlineWhitespace {
26893                    token,
26894                    grapheme_len,
26895                })
26896            } else {
26897                Some(WordBreakToken::Word {
26898                    token,
26899                    grapheme_len,
26900                })
26901            }
26902        } else {
26903            None
26904        }
26905    }
26906}
26907
26908#[test]
26909fn test_word_breaking_tokenizer() {
26910    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26911        ("", &[]),
26912        ("  ", &[whitespace("  ", 2)]),
26913        ("Ʒ", &[word("Ʒ", 1)]),
26914        ("Ǽ", &[word("Ǽ", 1)]),
26915        ("", &[word("", 1)]),
26916        ("⋑⋑", &[word("⋑⋑", 2)]),
26917        (
26918            "原理,进而",
26919            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26920        ),
26921        (
26922            "hello world",
26923            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26924        ),
26925        (
26926            "hello, world",
26927            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26928        ),
26929        (
26930            "  hello world",
26931            &[
26932                whitespace("  ", 2),
26933                word("hello", 5),
26934                whitespace(" ", 1),
26935                word("world", 5),
26936            ],
26937        ),
26938        (
26939            "这是什么 \n 钢笔",
26940            &[
26941                word("", 1),
26942                word("", 1),
26943                word("", 1),
26944                word("", 1),
26945                whitespace(" ", 1),
26946                newline(),
26947                whitespace(" ", 1),
26948                word("", 1),
26949                word("", 1),
26950            ],
26951        ),
26952        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26953    ];
26954
26955    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26956        WordBreakToken::Word {
26957            token,
26958            grapheme_len,
26959        }
26960    }
26961
26962    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26963        WordBreakToken::InlineWhitespace {
26964            token,
26965            grapheme_len,
26966        }
26967    }
26968
26969    fn newline() -> WordBreakToken<'static> {
26970        WordBreakToken::Newline
26971    }
26972
26973    for (input, result) in tests {
26974        assert_eq!(
26975            WordBreakingTokenizer::new(input)
26976                .collect::<Vec<_>>()
26977                .as_slice(),
26978            *result,
26979        );
26980    }
26981}
26982
26983fn wrap_with_prefix(
26984    first_line_prefix: String,
26985    subsequent_lines_prefix: String,
26986    unwrapped_text: String,
26987    wrap_column: usize,
26988    tab_size: NonZeroU32,
26989    preserve_existing_whitespace: bool,
26990) -> String {
26991    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26992    let subsequent_lines_prefix_len =
26993        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26994    let mut wrapped_text = String::new();
26995    let mut current_line = first_line_prefix;
26996    let mut is_first_line = true;
26997
26998    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26999    let mut current_line_len = first_line_prefix_len;
27000    let mut in_whitespace = false;
27001    for token in tokenizer {
27002        let have_preceding_whitespace = in_whitespace;
27003        match token {
27004            WordBreakToken::Word {
27005                token,
27006                grapheme_len,
27007            } => {
27008                in_whitespace = false;
27009                let current_prefix_len = if is_first_line {
27010                    first_line_prefix_len
27011                } else {
27012                    subsequent_lines_prefix_len
27013                };
27014                if current_line_len + grapheme_len > wrap_column
27015                    && current_line_len != current_prefix_len
27016                {
27017                    wrapped_text.push_str(current_line.trim_end());
27018                    wrapped_text.push('\n');
27019                    is_first_line = false;
27020                    current_line = subsequent_lines_prefix.clone();
27021                    current_line_len = subsequent_lines_prefix_len;
27022                }
27023                current_line.push_str(token);
27024                current_line_len += grapheme_len;
27025            }
27026            WordBreakToken::InlineWhitespace {
27027                mut token,
27028                mut grapheme_len,
27029            } => {
27030                in_whitespace = true;
27031                if have_preceding_whitespace && !preserve_existing_whitespace {
27032                    continue;
27033                }
27034                if !preserve_existing_whitespace {
27035                    // Keep a single whitespace grapheme as-is
27036                    if let Some(first) =
27037                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
27038                    {
27039                        token = first;
27040                    } else {
27041                        token = " ";
27042                    }
27043                    grapheme_len = 1;
27044                }
27045                let current_prefix_len = if is_first_line {
27046                    first_line_prefix_len
27047                } else {
27048                    subsequent_lines_prefix_len
27049                };
27050                if current_line_len + grapheme_len > wrap_column {
27051                    wrapped_text.push_str(current_line.trim_end());
27052                    wrapped_text.push('\n');
27053                    is_first_line = false;
27054                    current_line = subsequent_lines_prefix.clone();
27055                    current_line_len = subsequent_lines_prefix_len;
27056                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
27057                    current_line.push_str(token);
27058                    current_line_len += grapheme_len;
27059                }
27060            }
27061            WordBreakToken::Newline => {
27062                in_whitespace = true;
27063                let current_prefix_len = if is_first_line {
27064                    first_line_prefix_len
27065                } else {
27066                    subsequent_lines_prefix_len
27067                };
27068                if preserve_existing_whitespace {
27069                    wrapped_text.push_str(current_line.trim_end());
27070                    wrapped_text.push('\n');
27071                    is_first_line = false;
27072                    current_line = subsequent_lines_prefix.clone();
27073                    current_line_len = subsequent_lines_prefix_len;
27074                } else if have_preceding_whitespace {
27075                    continue;
27076                } else if current_line_len + 1 > wrap_column
27077                    && current_line_len != current_prefix_len
27078                {
27079                    wrapped_text.push_str(current_line.trim_end());
27080                    wrapped_text.push('\n');
27081                    is_first_line = false;
27082                    current_line = subsequent_lines_prefix.clone();
27083                    current_line_len = subsequent_lines_prefix_len;
27084                } else if current_line_len != current_prefix_len {
27085                    current_line.push(' ');
27086                    current_line_len += 1;
27087                }
27088            }
27089        }
27090    }
27091
27092    if !current_line.is_empty() {
27093        wrapped_text.push_str(&current_line);
27094    }
27095    wrapped_text
27096}
27097
27098#[test]
27099fn test_wrap_with_prefix() {
27100    assert_eq!(
27101        wrap_with_prefix(
27102            "# ".to_string(),
27103            "# ".to_string(),
27104            "abcdefg".to_string(),
27105            4,
27106            NonZeroU32::new(4).unwrap(),
27107            false,
27108        ),
27109        "# abcdefg"
27110    );
27111    assert_eq!(
27112        wrap_with_prefix(
27113            "".to_string(),
27114            "".to_string(),
27115            "\thello world".to_string(),
27116            8,
27117            NonZeroU32::new(4).unwrap(),
27118            false,
27119        ),
27120        "hello\nworld"
27121    );
27122    assert_eq!(
27123        wrap_with_prefix(
27124            "// ".to_string(),
27125            "// ".to_string(),
27126            "xx \nyy zz aa bb cc".to_string(),
27127            12,
27128            NonZeroU32::new(4).unwrap(),
27129            false,
27130        ),
27131        "// xx yy zz\n// aa bb cc"
27132    );
27133    assert_eq!(
27134        wrap_with_prefix(
27135            String::new(),
27136            String::new(),
27137            "这是什么 \n 钢笔".to_string(),
27138            3,
27139            NonZeroU32::new(4).unwrap(),
27140            false,
27141        ),
27142        "这是什\n么 钢\n"
27143    );
27144    assert_eq!(
27145        wrap_with_prefix(
27146            String::new(),
27147            String::new(),
27148            format!("foo{}bar", '\u{2009}'), // thin space
27149            80,
27150            NonZeroU32::new(4).unwrap(),
27151            false,
27152        ),
27153        format!("foo{}bar", '\u{2009}')
27154    );
27155}
27156
27157pub trait CollaborationHub {
27158    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
27159    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
27160    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
27161}
27162
27163impl CollaborationHub for Entity<Project> {
27164    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
27165        self.read(cx).collaborators()
27166    }
27167
27168    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
27169        self.read(cx).user_store().read(cx).participant_indices()
27170    }
27171
27172    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
27173        let this = self.read(cx);
27174        let user_ids = this.collaborators().values().map(|c| c.user_id);
27175        this.user_store().read(cx).participant_names(user_ids, cx)
27176    }
27177}
27178
27179pub trait SemanticsProvider {
27180    fn hover(
27181        &self,
27182        buffer: &Entity<Buffer>,
27183        position: text::Anchor,
27184        cx: &mut App,
27185    ) -> Option<Task<Option<Vec<project::Hover>>>>;
27186
27187    fn inline_values(
27188        &self,
27189        buffer_handle: Entity<Buffer>,
27190        range: Range<text::Anchor>,
27191        cx: &mut App,
27192    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
27193
27194    fn applicable_inlay_chunks(
27195        &self,
27196        buffer: &Entity<Buffer>,
27197        ranges: &[Range<text::Anchor>],
27198        cx: &mut App,
27199    ) -> Vec<Range<BufferRow>>;
27200
27201    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
27202
27203    fn inlay_hints(
27204        &self,
27205        invalidate: InvalidationStrategy,
27206        buffer: Entity<Buffer>,
27207        ranges: Vec<Range<text::Anchor>>,
27208        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27209        cx: &mut App,
27210    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
27211
27212    fn semantic_tokens(
27213        &self,
27214        buffer: Entity<Buffer>,
27215        refresh: Option<RefreshForServer>,
27216        cx: &mut App,
27217    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
27218
27219    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27220
27221    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
27222
27223    fn document_highlights(
27224        &self,
27225        buffer: &Entity<Buffer>,
27226        position: text::Anchor,
27227        cx: &mut App,
27228    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
27229
27230    fn definitions(
27231        &self,
27232        buffer: &Entity<Buffer>,
27233        position: text::Anchor,
27234        kind: GotoDefinitionKind,
27235        cx: &mut App,
27236    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
27237
27238    fn range_for_rename(
27239        &self,
27240        buffer: &Entity<Buffer>,
27241        position: text::Anchor,
27242        cx: &mut App,
27243    ) -> Task<Result<Option<Range<text::Anchor>>>>;
27244
27245    fn perform_rename(
27246        &self,
27247        buffer: &Entity<Buffer>,
27248        position: text::Anchor,
27249        new_name: String,
27250        cx: &mut App,
27251    ) -> Option<Task<Result<ProjectTransaction>>>;
27252}
27253
27254pub trait CompletionProvider {
27255    fn completions(
27256        &self,
27257        buffer: &Entity<Buffer>,
27258        buffer_position: text::Anchor,
27259        trigger: CompletionContext,
27260        window: &mut Window,
27261        cx: &mut Context<Editor>,
27262    ) -> Task<Result<Vec<CompletionResponse>>>;
27263
27264    fn resolve_completions(
27265        &self,
27266        _buffer: Entity<Buffer>,
27267        _completion_indices: Vec<usize>,
27268        _completions: Rc<RefCell<Box<[Completion]>>>,
27269        _cx: &mut Context<Editor>,
27270    ) -> Task<Result<bool>> {
27271        Task::ready(Ok(false))
27272    }
27273
27274    fn apply_additional_edits_for_completion(
27275        &self,
27276        _buffer: Entity<Buffer>,
27277        _completions: Rc<RefCell<Box<[Completion]>>>,
27278        _completion_index: usize,
27279        _push_to_history: bool,
27280        _all_commit_ranges: Vec<Range<language::Anchor>>,
27281        _cx: &mut Context<Editor>,
27282    ) -> Task<Result<Option<language::Transaction>>> {
27283        Task::ready(Ok(None))
27284    }
27285
27286    fn is_completion_trigger(
27287        &self,
27288        buffer: &Entity<Buffer>,
27289        position: language::Anchor,
27290        text: &str,
27291        trigger_in_words: bool,
27292        cx: &mut Context<Editor>,
27293    ) -> bool;
27294
27295    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
27296
27297    fn sort_completions(&self) -> bool {
27298        true
27299    }
27300
27301    fn filter_completions(&self) -> bool {
27302        true
27303    }
27304
27305    fn show_snippets(&self) -> bool {
27306        false
27307    }
27308}
27309
27310pub trait CodeActionProvider {
27311    fn id(&self) -> Arc<str>;
27312
27313    fn code_actions(
27314        &self,
27315        buffer: &Entity<Buffer>,
27316        range: Range<text::Anchor>,
27317        window: &mut Window,
27318        cx: &mut App,
27319    ) -> Task<Result<Vec<CodeAction>>>;
27320
27321    fn apply_code_action(
27322        &self,
27323        buffer_handle: Entity<Buffer>,
27324        action: CodeAction,
27325        push_to_history: bool,
27326        window: &mut Window,
27327        cx: &mut App,
27328    ) -> Task<Result<ProjectTransaction>>;
27329}
27330
27331impl CodeActionProvider for Entity<Project> {
27332    fn id(&self) -> Arc<str> {
27333        "project".into()
27334    }
27335
27336    fn code_actions(
27337        &self,
27338        buffer: &Entity<Buffer>,
27339        range: Range<text::Anchor>,
27340        _window: &mut Window,
27341        cx: &mut App,
27342    ) -> Task<Result<Vec<CodeAction>>> {
27343        self.update(cx, |project, cx| {
27344            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
27345            let code_actions = project.code_actions(buffer, range, None, cx);
27346            cx.background_spawn(async move {
27347                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
27348                Ok(code_lens_actions
27349                    .context("code lens fetch")?
27350                    .into_iter()
27351                    .flatten()
27352                    .chain(
27353                        code_actions
27354                            .context("code action fetch")?
27355                            .into_iter()
27356                            .flatten(),
27357                    )
27358                    .collect())
27359            })
27360        })
27361    }
27362
27363    fn apply_code_action(
27364        &self,
27365        buffer_handle: Entity<Buffer>,
27366        action: CodeAction,
27367        push_to_history: bool,
27368        _window: &mut Window,
27369        cx: &mut App,
27370    ) -> Task<Result<ProjectTransaction>> {
27371        self.update(cx, |project, cx| {
27372            project.apply_code_action(buffer_handle, action, push_to_history, cx)
27373        })
27374    }
27375}
27376
27377fn snippet_completions(
27378    project: &Project,
27379    buffer: &Entity<Buffer>,
27380    buffer_anchor: text::Anchor,
27381    classifier: CharClassifier,
27382    cx: &mut App,
27383) -> Task<Result<CompletionResponse>> {
27384    let languages = buffer.read(cx).languages_at(buffer_anchor);
27385    let snippet_store = project.snippets().read(cx);
27386
27387    let scopes: Vec<_> = languages
27388        .iter()
27389        .filter_map(|language| {
27390            let language_name = language.lsp_id();
27391            let snippets = snippet_store.snippets_for(Some(language_name), cx);
27392
27393            if snippets.is_empty() {
27394                None
27395            } else {
27396                Some((language.default_scope(), snippets))
27397            }
27398        })
27399        .collect();
27400
27401    if scopes.is_empty() {
27402        return Task::ready(Ok(CompletionResponse {
27403            completions: vec![],
27404            display_options: CompletionDisplayOptions::default(),
27405            is_incomplete: false,
27406        }));
27407    }
27408
27409    let snapshot = buffer.read(cx).text_snapshot();
27410    let executor = cx.background_executor().clone();
27411
27412    cx.background_spawn(async move {
27413        let is_word_char = |c| classifier.is_word(c);
27414
27415        let mut is_incomplete = false;
27416        let mut completions: Vec<Completion> = Vec::new();
27417
27418        const MAX_PREFIX_LEN: usize = 128;
27419        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
27420        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
27421        let window_start = snapshot.clip_offset(window_start, Bias::Left);
27422
27423        let max_buffer_window: String = snapshot
27424            .text_for_range(window_start..buffer_offset)
27425            .collect();
27426
27427        if max_buffer_window.is_empty() {
27428            return Ok(CompletionResponse {
27429                completions: vec![],
27430                display_options: CompletionDisplayOptions::default(),
27431                is_incomplete: true,
27432            });
27433        }
27434
27435        for (_scope, snippets) in scopes.into_iter() {
27436            // Sort snippets by word count to match longer snippet prefixes first.
27437            let mut sorted_snippet_candidates = snippets
27438                .iter()
27439                .enumerate()
27440                .flat_map(|(snippet_ix, snippet)| {
27441                    snippet
27442                        .prefix
27443                        .iter()
27444                        .enumerate()
27445                        .map(move |(prefix_ix, prefix)| {
27446                            let word_count =
27447                                snippet_candidate_suffixes(prefix, &is_word_char).count();
27448                            ((snippet_ix, prefix_ix), prefix, word_count)
27449                        })
27450                })
27451                .collect_vec();
27452            sorted_snippet_candidates
27453                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
27454
27455            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
27456
27457            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
27458                .take(
27459                    sorted_snippet_candidates
27460                        .first()
27461                        .map(|(_, _, word_count)| *word_count)
27462                        .unwrap_or_default(),
27463                )
27464                .collect_vec();
27465
27466            const MAX_RESULTS: usize = 100;
27467            // Each match also remembers how many characters from the buffer it consumed
27468            let mut matches: Vec<(StringMatch, usize)> = vec![];
27469
27470            let mut snippet_list_cutoff_index = 0;
27471            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
27472                let word_count = buffer_index + 1;
27473                // Increase `snippet_list_cutoff_index` until we have all of the
27474                // snippets with sufficiently many words.
27475                while sorted_snippet_candidates
27476                    .get(snippet_list_cutoff_index)
27477                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
27478                        *snippet_word_count >= word_count
27479                    })
27480                {
27481                    snippet_list_cutoff_index += 1;
27482                }
27483
27484                // Take only the candidates with at least `word_count` many words
27485                let snippet_candidates_at_word_len =
27486                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
27487
27488                let candidates = snippet_candidates_at_word_len
27489                    .iter()
27490                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
27491                    .enumerate() // index in `sorted_snippet_candidates`
27492                    // First char must match
27493                    .filter(|(_ix, prefix)| {
27494                        itertools::equal(
27495                            prefix
27496                                .chars()
27497                                .next()
27498                                .into_iter()
27499                                .flat_map(|c| c.to_lowercase()),
27500                            buffer_window
27501                                .chars()
27502                                .next()
27503                                .into_iter()
27504                                .flat_map(|c| c.to_lowercase()),
27505                        )
27506                    })
27507                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
27508                    .collect::<Vec<StringMatchCandidate>>();
27509
27510                matches.extend(
27511                    fuzzy::match_strings(
27512                        &candidates,
27513                        &buffer_window,
27514                        buffer_window.chars().any(|c| c.is_uppercase()),
27515                        true,
27516                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
27517                        &Default::default(),
27518                        executor.clone(),
27519                    )
27520                    .await
27521                    .into_iter()
27522                    .map(|string_match| (string_match, buffer_window.len())),
27523                );
27524
27525                if matches.len() >= MAX_RESULTS {
27526                    break;
27527                }
27528            }
27529
27530            let to_lsp = |point: &text::Anchor| {
27531                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
27532                point_to_lsp(end)
27533            };
27534            let lsp_end = to_lsp(&buffer_anchor);
27535
27536            if matches.len() >= MAX_RESULTS {
27537                is_incomplete = true;
27538            }
27539
27540            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
27541                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
27542                    sorted_snippet_candidates[string_match.candidate_id];
27543                let snippet = &snippets[snippet_index];
27544                let start = buffer_offset - buffer_window_len;
27545                let start = snapshot.anchor_before(start);
27546                let range = start..buffer_anchor;
27547                let lsp_start = to_lsp(&start);
27548                let lsp_range = lsp::Range {
27549                    start: lsp_start,
27550                    end: lsp_end,
27551                };
27552                Completion {
27553                    replace_range: range,
27554                    new_text: snippet.body.clone(),
27555                    source: CompletionSource::Lsp {
27556                        insert_range: None,
27557                        server_id: LanguageServerId(usize::MAX),
27558                        resolved: true,
27559                        lsp_completion: Box::new(lsp::CompletionItem {
27560                            label: snippet.prefix.first().unwrap().clone(),
27561                            kind: Some(CompletionItemKind::SNIPPET),
27562                            label_details: snippet.description.as_ref().map(|description| {
27563                                lsp::CompletionItemLabelDetails {
27564                                    detail: Some(description.clone()),
27565                                    description: None,
27566                                }
27567                            }),
27568                            insert_text_format: Some(InsertTextFormat::SNIPPET),
27569                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
27570                                lsp::InsertReplaceEdit {
27571                                    new_text: snippet.body.clone(),
27572                                    insert: lsp_range,
27573                                    replace: lsp_range,
27574                                },
27575                            )),
27576                            filter_text: Some(snippet.body.clone()),
27577                            sort_text: Some(char::MAX.to_string()),
27578                            ..lsp::CompletionItem::default()
27579                        }),
27580                        lsp_defaults: None,
27581                    },
27582                    label: CodeLabel {
27583                        text: matching_prefix.clone(),
27584                        runs: Vec::new(),
27585                        filter_range: 0..matching_prefix.len(),
27586                    },
27587                    icon_path: None,
27588                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
27589                        single_line: snippet.name.clone().into(),
27590                        plain_text: snippet
27591                            .description
27592                            .clone()
27593                            .map(|description| description.into()),
27594                    }),
27595                    insert_text_mode: None,
27596                    confirm: None,
27597                    match_start: Some(start),
27598                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
27599                }
27600            }));
27601        }
27602
27603        Ok(CompletionResponse {
27604            completions,
27605            display_options: CompletionDisplayOptions::default(),
27606            is_incomplete,
27607        })
27608    })
27609}
27610
27611impl CompletionProvider for Entity<Project> {
27612    fn completions(
27613        &self,
27614        buffer: &Entity<Buffer>,
27615        buffer_position: text::Anchor,
27616        options: CompletionContext,
27617        _window: &mut Window,
27618        cx: &mut Context<Editor>,
27619    ) -> Task<Result<Vec<CompletionResponse>>> {
27620        self.update(cx, |project, cx| {
27621            let task = project.completions(buffer, buffer_position, options, cx);
27622            cx.background_spawn(task)
27623        })
27624    }
27625
27626    fn resolve_completions(
27627        &self,
27628        buffer: Entity<Buffer>,
27629        completion_indices: Vec<usize>,
27630        completions: Rc<RefCell<Box<[Completion]>>>,
27631        cx: &mut Context<Editor>,
27632    ) -> Task<Result<bool>> {
27633        self.update(cx, |project, cx| {
27634            project.lsp_store().update(cx, |lsp_store, cx| {
27635                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
27636            })
27637        })
27638    }
27639
27640    fn apply_additional_edits_for_completion(
27641        &self,
27642        buffer: Entity<Buffer>,
27643        completions: Rc<RefCell<Box<[Completion]>>>,
27644        completion_index: usize,
27645        push_to_history: bool,
27646        all_commit_ranges: Vec<Range<language::Anchor>>,
27647        cx: &mut Context<Editor>,
27648    ) -> Task<Result<Option<language::Transaction>>> {
27649        self.update(cx, |project, cx| {
27650            project.lsp_store().update(cx, |lsp_store, cx| {
27651                lsp_store.apply_additional_edits_for_completion(
27652                    buffer,
27653                    completions,
27654                    completion_index,
27655                    push_to_history,
27656                    all_commit_ranges,
27657                    cx,
27658                )
27659            })
27660        })
27661    }
27662
27663    fn is_completion_trigger(
27664        &self,
27665        buffer: &Entity<Buffer>,
27666        position: language::Anchor,
27667        text: &str,
27668        trigger_in_words: bool,
27669        cx: &mut Context<Editor>,
27670    ) -> bool {
27671        let mut chars = text.chars();
27672        let char = if let Some(char) = chars.next() {
27673            char
27674        } else {
27675            return false;
27676        };
27677        if chars.next().is_some() {
27678            return false;
27679        }
27680
27681        let buffer = buffer.read(cx);
27682        let snapshot = buffer.snapshot();
27683        let classifier = snapshot
27684            .char_classifier_at(position)
27685            .scope_context(Some(CharScopeContext::Completion));
27686        if trigger_in_words && classifier.is_word(char) {
27687            return true;
27688        }
27689
27690        buffer.completion_triggers().contains(text)
27691    }
27692
27693    fn show_snippets(&self) -> bool {
27694        true
27695    }
27696}
27697
27698impl SemanticsProvider for WeakEntity<Project> {
27699    fn hover(
27700        &self,
27701        buffer: &Entity<Buffer>,
27702        position: text::Anchor,
27703        cx: &mut App,
27704    ) -> Option<Task<Option<Vec<project::Hover>>>> {
27705        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27706            .ok()
27707    }
27708
27709    fn document_highlights(
27710        &self,
27711        buffer: &Entity<Buffer>,
27712        position: text::Anchor,
27713        cx: &mut App,
27714    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27715        self.update(cx, |project, cx| {
27716            project.document_highlights(buffer, position, cx)
27717        })
27718        .ok()
27719    }
27720
27721    fn definitions(
27722        &self,
27723        buffer: &Entity<Buffer>,
27724        position: text::Anchor,
27725        kind: GotoDefinitionKind,
27726        cx: &mut App,
27727    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27728        self.update(cx, |project, cx| match kind {
27729            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27730            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27731            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27732            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27733        })
27734        .ok()
27735    }
27736
27737    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27738        self.update(cx, |project, cx| {
27739            if project
27740                .active_debug_session(cx)
27741                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27742            {
27743                return true;
27744            }
27745
27746            buffer.update(cx, |buffer, cx| {
27747                project.any_language_server_supports_inlay_hints(buffer, cx)
27748            })
27749        })
27750        .unwrap_or(false)
27751    }
27752
27753    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27754        self.update(cx, |project, cx| {
27755            buffer.update(cx, |buffer, cx| {
27756                project.any_language_server_supports_semantic_tokens(buffer, cx)
27757            })
27758        })
27759        .unwrap_or(false)
27760    }
27761
27762    fn inline_values(
27763        &self,
27764        buffer_handle: Entity<Buffer>,
27765        range: Range<text::Anchor>,
27766        cx: &mut App,
27767    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27768        self.update(cx, |project, cx| {
27769            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27770
27771            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27772        })
27773        .ok()
27774        .flatten()
27775    }
27776
27777    fn applicable_inlay_chunks(
27778        &self,
27779        buffer: &Entity<Buffer>,
27780        ranges: &[Range<text::Anchor>],
27781        cx: &mut App,
27782    ) -> Vec<Range<BufferRow>> {
27783        self.update(cx, |project, cx| {
27784            project.lsp_store().update(cx, |lsp_store, cx| {
27785                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27786            })
27787        })
27788        .unwrap_or_default()
27789    }
27790
27791    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27792        self.update(cx, |project, cx| {
27793            project.lsp_store().update(cx, |lsp_store, _| {
27794                lsp_store.invalidate_inlay_hints(for_buffers)
27795            })
27796        })
27797        .ok();
27798    }
27799
27800    fn inlay_hints(
27801        &self,
27802        invalidate: InvalidationStrategy,
27803        buffer: Entity<Buffer>,
27804        ranges: Vec<Range<text::Anchor>>,
27805        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27806        cx: &mut App,
27807    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27808        self.update(cx, |project, cx| {
27809            project.lsp_store().update(cx, |lsp_store, cx| {
27810                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27811            })
27812        })
27813        .ok()
27814    }
27815
27816    fn semantic_tokens(
27817        &self,
27818        buffer: Entity<Buffer>,
27819        refresh: Option<RefreshForServer>,
27820        cx: &mut App,
27821    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27822        self.update(cx, |this, cx| {
27823            this.lsp_store().update(cx, |lsp_store, cx| {
27824                lsp_store.semantic_tokens(buffer, refresh, cx)
27825            })
27826        })
27827        .ok()
27828    }
27829
27830    fn range_for_rename(
27831        &self,
27832        buffer: &Entity<Buffer>,
27833        position: text::Anchor,
27834        cx: &mut App,
27835    ) -> Task<Result<Option<Range<text::Anchor>>>> {
27836        let Some(this) = self.upgrade() else {
27837            return Task::ready(Ok(None));
27838        };
27839
27840        this.update(cx, |project, cx| {
27841            let buffer = buffer.clone();
27842            let task = project.prepare_rename(buffer.clone(), position, cx);
27843            cx.spawn(async move |_, cx| {
27844                Ok(match task.await? {
27845                    PrepareRenameResponse::Success(range) => Some(range),
27846                    PrepareRenameResponse::InvalidPosition => None,
27847                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27848                        // Fallback on using TreeSitter info to determine identifier range
27849                        buffer.read_with(cx, |buffer, _| {
27850                            let snapshot = buffer.snapshot();
27851                            let (range, kind) = snapshot.surrounding_word(position, None);
27852                            if kind != Some(CharKind::Word) {
27853                                return None;
27854                            }
27855                            Some(
27856                                snapshot.anchor_before(range.start)
27857                                    ..snapshot.anchor_after(range.end),
27858                            )
27859                        })
27860                    }
27861                })
27862            })
27863        })
27864    }
27865
27866    fn perform_rename(
27867        &self,
27868        buffer: &Entity<Buffer>,
27869        position: text::Anchor,
27870        new_name: String,
27871        cx: &mut App,
27872    ) -> Option<Task<Result<ProjectTransaction>>> {
27873        self.update(cx, |project, cx| {
27874            project.perform_rename(buffer.clone(), position, new_name, cx)
27875        })
27876        .ok()
27877    }
27878}
27879
27880fn consume_contiguous_rows(
27881    contiguous_row_selections: &mut Vec<Selection<Point>>,
27882    selection: &Selection<Point>,
27883    display_map: &DisplaySnapshot,
27884    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27885) -> (MultiBufferRow, MultiBufferRow) {
27886    contiguous_row_selections.push(selection.clone());
27887    let start_row = starting_row(selection, display_map);
27888    let mut end_row = ending_row(selection, display_map);
27889
27890    while let Some(next_selection) = selections.peek() {
27891        if next_selection.start.row <= end_row.0 {
27892            end_row = ending_row(next_selection, display_map);
27893            contiguous_row_selections.push(selections.next().unwrap().clone());
27894        } else {
27895            break;
27896        }
27897    }
27898    (start_row, end_row)
27899}
27900
27901fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27902    if selection.start.column > 0 {
27903        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27904    } else {
27905        MultiBufferRow(selection.start.row)
27906    }
27907}
27908
27909fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27910    if next_selection.end.column > 0 || next_selection.is_empty() {
27911        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27912    } else {
27913        MultiBufferRow(next_selection.end.row)
27914    }
27915}
27916
27917impl EditorSnapshot {
27918    pub fn remote_selections_in_range<'a>(
27919        &'a self,
27920        range: &'a Range<Anchor>,
27921        collaboration_hub: &dyn CollaborationHub,
27922        cx: &'a App,
27923    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27924        let participant_names = collaboration_hub.user_names(cx);
27925        let participant_indices = collaboration_hub.user_participant_indices(cx);
27926        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27927        let collaborators_by_replica_id = collaborators_by_peer_id
27928            .values()
27929            .map(|collaborator| (collaborator.replica_id, collaborator))
27930            .collect::<HashMap<_, _>>();
27931        self.buffer_snapshot()
27932            .selections_in_range(range, false)
27933            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27934                if replica_id == ReplicaId::AGENT {
27935                    Some(RemoteSelection {
27936                        replica_id,
27937                        selection,
27938                        cursor_shape,
27939                        line_mode,
27940                        collaborator_id: CollaboratorId::Agent,
27941                        user_name: Some("Agent".into()),
27942                        color: cx.theme().players().agent(),
27943                    })
27944                } else {
27945                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27946                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27947                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27948                    Some(RemoteSelection {
27949                        replica_id,
27950                        selection,
27951                        cursor_shape,
27952                        line_mode,
27953                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27954                        user_name,
27955                        color: if let Some(index) = participant_index {
27956                            cx.theme().players().color_for_participant(index.0)
27957                        } else {
27958                            cx.theme().players().absent()
27959                        },
27960                    })
27961                }
27962            })
27963    }
27964
27965    pub fn hunks_for_ranges(
27966        &self,
27967        ranges: impl IntoIterator<Item = Range<Point>>,
27968    ) -> Vec<MultiBufferDiffHunk> {
27969        let mut hunks = Vec::new();
27970        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27971            HashMap::default();
27972        for query_range in ranges {
27973            let query_rows =
27974                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27975            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27976                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27977            ) {
27978                // Include deleted hunks that are adjacent to the query range, because
27979                // otherwise they would be missed.
27980                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27981                if hunk.status().is_deleted() {
27982                    intersects_range |= hunk.row_range.start == query_rows.end;
27983                    intersects_range |= hunk.row_range.end == query_rows.start;
27984                }
27985                if intersects_range {
27986                    if !processed_buffer_rows
27987                        .entry(hunk.buffer_id)
27988                        .or_default()
27989                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27990                    {
27991                        continue;
27992                    }
27993                    hunks.push(hunk);
27994                }
27995            }
27996        }
27997
27998        hunks
27999    }
28000
28001    fn display_diff_hunks_for_rows<'a>(
28002        &'a self,
28003        display_rows: Range<DisplayRow>,
28004        folded_buffers: &'a HashSet<BufferId>,
28005    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
28006        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
28007        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
28008
28009        self.buffer_snapshot()
28010            .diff_hunks_in_range(buffer_start..buffer_end)
28011            .filter_map(|hunk| {
28012                if folded_buffers.contains(&hunk.buffer_id)
28013                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
28014                {
28015                    return None;
28016                }
28017
28018                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
28019                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
28020                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
28021                    let line_len = self.buffer_snapshot().line_len(last_row);
28022                    Point::new(last_row.0, line_len)
28023                } else {
28024                    Point::new(hunk.row_range.end.0, 0)
28025                };
28026
28027                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
28028                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
28029
28030                let display_hunk = if hunk_display_start.column() != 0 {
28031                    DisplayDiffHunk::Folded {
28032                        display_row: hunk_display_start.row(),
28033                    }
28034                } else {
28035                    let mut end_row = hunk_display_end.row();
28036                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
28037                        end_row.0 += 1;
28038                    }
28039                    let is_created_file = hunk.is_created_file();
28040                    let multi_buffer_range = hunk.multi_buffer_range.clone();
28041
28042                    DisplayDiffHunk::Unfolded {
28043                        status: hunk.status(),
28044                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
28045                            ..hunk.diff_base_byte_range.end.0,
28046                        word_diffs: hunk.word_diffs,
28047                        display_row_range: hunk_display_start.row()..end_row,
28048                        multi_buffer_range,
28049                        is_created_file,
28050                    }
28051                };
28052
28053                Some(display_hunk)
28054            })
28055    }
28056
28057    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
28058        self.display_snapshot
28059            .buffer_snapshot()
28060            .language_at(position)
28061    }
28062
28063    pub fn is_focused(&self) -> bool {
28064        self.is_focused
28065    }
28066
28067    pub fn placeholder_text(&self) -> Option<String> {
28068        self.placeholder_display_snapshot
28069            .as_ref()
28070            .map(|display_map| display_map.text())
28071    }
28072
28073    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
28074        self.scroll_anchor.scroll_position(&self.display_snapshot)
28075    }
28076
28077    pub fn gutter_dimensions(
28078        &self,
28079        font_id: FontId,
28080        font_size: Pixels,
28081        style: &EditorStyle,
28082        window: &mut Window,
28083        cx: &App,
28084    ) -> GutterDimensions {
28085        if self.show_gutter
28086            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
28087            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
28088        {
28089            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
28090                matches!(
28091                    ProjectSettings::get_global(cx).git.git_gutter,
28092                    GitGutterSetting::TrackedFiles
28093                )
28094            });
28095            let gutter_settings = EditorSettings::get_global(cx).gutter;
28096            let show_line_numbers = self
28097                .show_line_numbers
28098                .unwrap_or(gutter_settings.line_numbers);
28099            let line_gutter_width = if show_line_numbers {
28100                // Avoid flicker-like gutter resizes when the line number gains another digit by
28101                // only resizing the gutter on files with > 10**min_line_number_digits lines.
28102                let min_width_for_number_on_gutter =
28103                    ch_advance * gutter_settings.min_line_number_digits as f32;
28104                self.max_line_number_width(style, window)
28105                    .max(min_width_for_number_on_gutter)
28106            } else {
28107                0.0.into()
28108            };
28109
28110            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
28111            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
28112
28113            let git_blame_entries_width =
28114                self.git_blame_gutter_max_author_length
28115                    .map(|max_author_length| {
28116                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
28117                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
28118
28119                        /// The number of characters to dedicate to gaps and margins.
28120                        const SPACING_WIDTH: usize = 4;
28121
28122                        let max_char_count = max_author_length.min(renderer.max_author_length())
28123                            + ::git::SHORT_SHA_LENGTH
28124                            + MAX_RELATIVE_TIMESTAMP.len()
28125                            + SPACING_WIDTH;
28126
28127                        ch_advance * max_char_count
28128                    });
28129
28130            let is_singleton = self.buffer_snapshot().is_singleton();
28131
28132            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
28133            left_padding += if !is_singleton {
28134                ch_width * 4.0
28135            } else if show_runnables || show_breakpoints {
28136                ch_width * 3.0
28137            } else if show_git_gutter && show_line_numbers {
28138                ch_width * 2.0
28139            } else if show_git_gutter || show_line_numbers {
28140                ch_width
28141            } else {
28142                px(0.)
28143            };
28144
28145            let shows_folds = is_singleton && gutter_settings.folds;
28146
28147            let right_padding = if shows_folds && show_line_numbers {
28148                ch_width * 4.0
28149            } else if shows_folds || (!is_singleton && show_line_numbers) {
28150                ch_width * 3.0
28151            } else if show_line_numbers {
28152                ch_width
28153            } else {
28154                px(0.)
28155            };
28156
28157            GutterDimensions {
28158                left_padding,
28159                right_padding,
28160                width: line_gutter_width + left_padding + right_padding,
28161                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
28162                git_blame_entries_width,
28163            }
28164        } else if self.offset_content {
28165            GutterDimensions::default_with_margin(font_id, font_size, cx)
28166        } else {
28167            GutterDimensions::default()
28168        }
28169    }
28170
28171    pub fn render_crease_toggle(
28172        &self,
28173        buffer_row: MultiBufferRow,
28174        row_contains_cursor: bool,
28175        editor: Entity<Editor>,
28176        window: &mut Window,
28177        cx: &mut App,
28178    ) -> Option<AnyElement> {
28179        let folded = self.is_line_folded(buffer_row);
28180        let mut is_foldable = false;
28181
28182        if let Some(crease) = self
28183            .crease_snapshot
28184            .query_row(buffer_row, self.buffer_snapshot())
28185        {
28186            is_foldable = true;
28187            match crease {
28188                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
28189                    if let Some(render_toggle) = render_toggle {
28190                        let toggle_callback =
28191                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
28192                                if folded {
28193                                    editor.update(cx, |editor, cx| {
28194                                        editor.fold_at(buffer_row, window, cx)
28195                                    });
28196                                } else {
28197                                    editor.update(cx, |editor, cx| {
28198                                        editor.unfold_at(buffer_row, window, cx)
28199                                    });
28200                                }
28201                            });
28202                        return Some((render_toggle)(
28203                            buffer_row,
28204                            folded,
28205                            toggle_callback,
28206                            window,
28207                            cx,
28208                        ));
28209                    }
28210                }
28211            }
28212        }
28213
28214        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
28215
28216        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
28217            Some(
28218                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
28219                    .toggle_state(folded)
28220                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
28221                        if folded {
28222                            this.unfold_at(buffer_row, window, cx);
28223                        } else {
28224                            this.fold_at(buffer_row, window, cx);
28225                        }
28226                    }))
28227                    .into_any_element(),
28228            )
28229        } else {
28230            None
28231        }
28232    }
28233
28234    pub fn render_crease_trailer(
28235        &self,
28236        buffer_row: MultiBufferRow,
28237        window: &mut Window,
28238        cx: &mut App,
28239    ) -> Option<AnyElement> {
28240        let folded = self.is_line_folded(buffer_row);
28241        if let Crease::Inline { render_trailer, .. } = self
28242            .crease_snapshot
28243            .query_row(buffer_row, self.buffer_snapshot())?
28244        {
28245            let render_trailer = render_trailer.as_ref()?;
28246            Some(render_trailer(buffer_row, folded, window, cx))
28247        } else {
28248            None
28249        }
28250    }
28251
28252    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
28253        let digit_count = self.widest_line_number().ilog10() + 1;
28254        column_pixels(style, digit_count as usize, window)
28255    }
28256
28257    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
28258    ///
28259    /// This is positive if `base` is before `line`.
28260    fn relative_line_delta(
28261        &self,
28262        current_selection_head: DisplayRow,
28263        first_visible_row: DisplayRow,
28264        consider_wrapped_lines: bool,
28265    ) -> i64 {
28266        let current_selection_head = current_selection_head.as_display_point().to_point(self);
28267        let first_visible_row = first_visible_row.as_display_point().to_point(self);
28268
28269        if consider_wrapped_lines {
28270            let wrap_snapshot = self.wrap_snapshot();
28271            let base_wrap_row = wrap_snapshot
28272                .make_wrap_point(current_selection_head, Bias::Left)
28273                .row();
28274            let wrap_row = wrap_snapshot
28275                .make_wrap_point(first_visible_row, Bias::Left)
28276                .row();
28277
28278            wrap_row.0 as i64 - base_wrap_row.0 as i64
28279        } else {
28280            let fold_snapshot = self.fold_snapshot();
28281            let base_fold_row = fold_snapshot
28282                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
28283                .row();
28284            let fold_row = fold_snapshot
28285                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
28286                .row();
28287
28288            fold_row as i64 - base_fold_row as i64
28289        }
28290    }
28291
28292    /// Returns the unsigned relative line number to display for each row in `rows`.
28293    ///
28294    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
28295    pub fn calculate_relative_line_numbers(
28296        &self,
28297        rows: &Range<DisplayRow>,
28298        current_selection_head: DisplayRow,
28299        count_wrapped_lines: bool,
28300    ) -> HashMap<DisplayRow, u32> {
28301        let initial_offset =
28302            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
28303
28304        self.row_infos(rows.start)
28305            .take(rows.len())
28306            .enumerate()
28307            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
28308            .filter(|(_row, row_info)| {
28309                row_info.buffer_row.is_some()
28310                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
28311            })
28312            .enumerate()
28313            .filter_map(|(i, (row, row_info))| {
28314                // We want to ensure here that the current line has absolute
28315                // numbering, even if we are in a soft-wrapped line. With the
28316                // exception that if we are in a deleted line, we should number this
28317                // relative with 0, as otherwise it would have no line number at all
28318                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
28319
28320                (relative_line_number != 0
28321                    || row_info
28322                        .diff_status
28323                        .is_some_and(|status| status.is_deleted()))
28324                .then_some((row, relative_line_number))
28325            })
28326            .collect()
28327    }
28328}
28329
28330pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
28331    let font_size = style.text.font_size.to_pixels(window.rem_size());
28332    let layout = window.text_system().shape_line(
28333        SharedString::from(" ".repeat(column)),
28334        font_size,
28335        &[TextRun {
28336            len: column,
28337            font: style.text.font(),
28338            color: Hsla::default(),
28339            ..Default::default()
28340        }],
28341        None,
28342    );
28343
28344    layout.width
28345}
28346
28347impl Deref for EditorSnapshot {
28348    type Target = DisplaySnapshot;
28349
28350    fn deref(&self) -> &Self::Target {
28351        &self.display_snapshot
28352    }
28353}
28354
28355#[derive(Clone, Debug, PartialEq, Eq)]
28356pub enum EditorEvent {
28357    /// Emitted when the stored review comments change (added, removed, or updated).
28358    ReviewCommentsChanged {
28359        /// The new total count of review comments.
28360        total_count: usize,
28361    },
28362    InputIgnored {
28363        text: Arc<str>,
28364    },
28365    InputHandled {
28366        utf16_range_to_replace: Option<Range<isize>>,
28367        text: Arc<str>,
28368    },
28369    BufferRangesUpdated {
28370        buffer: Entity<Buffer>,
28371        path_key: PathKey,
28372        ranges: Vec<ExcerptRange<text::Anchor>>,
28373    },
28374    BuffersRemoved {
28375        removed_buffer_ids: Vec<BufferId>,
28376    },
28377    BuffersEdited {
28378        buffer_ids: Vec<BufferId>,
28379    },
28380    BufferFoldToggled {
28381        ids: Vec<BufferId>,
28382        folded: bool,
28383    },
28384    ExpandExcerptsRequested {
28385        excerpt_anchors: Vec<Anchor>,
28386        lines: u32,
28387        direction: ExpandExcerptDirection,
28388    },
28389    StageOrUnstageRequested {
28390        stage: bool,
28391        hunks: Vec<MultiBufferDiffHunk>,
28392    },
28393    OpenExcerptsRequested {
28394        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
28395        split: bool,
28396    },
28397    RestoreRequested {
28398        hunks: Vec<MultiBufferDiffHunk>,
28399    },
28400    BufferEdited,
28401    Edited {
28402        transaction_id: clock::Lamport,
28403    },
28404    Reparsed(BufferId),
28405    Focused,
28406    FocusedIn,
28407    Blurred,
28408    DirtyChanged,
28409    Saved,
28410    TitleChanged,
28411    SelectionsChanged {
28412        local: bool,
28413    },
28414    ScrollPositionChanged {
28415        local: bool,
28416        autoscroll: bool,
28417    },
28418    TransactionUndone {
28419        transaction_id: clock::Lamport,
28420    },
28421    TransactionBegun {
28422        transaction_id: clock::Lamport,
28423    },
28424    CursorShapeChanged,
28425    BreadcrumbsChanged,
28426    OutlineSymbolsChanged,
28427    PushedToNavHistory {
28428        anchor: Anchor,
28429        is_deactivate: bool,
28430    },
28431}
28432
28433impl EventEmitter<EditorEvent> for Editor {}
28434
28435impl Focusable for Editor {
28436    fn focus_handle(&self, _cx: &App) -> FocusHandle {
28437        self.focus_handle.clone()
28438    }
28439}
28440
28441impl Render for Editor {
28442    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28443        EditorElement::new(&cx.entity(), self.create_style(cx))
28444    }
28445}
28446
28447impl EntityInputHandler for Editor {
28448    fn text_for_range(
28449        &mut self,
28450        range_utf16: Range<usize>,
28451        adjusted_range: &mut Option<Range<usize>>,
28452        _: &mut Window,
28453        cx: &mut Context<Self>,
28454    ) -> Option<String> {
28455        let snapshot = self.buffer.read(cx).read(cx);
28456        let start = snapshot.clip_offset_utf16(
28457            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
28458            Bias::Left,
28459        );
28460        let end = snapshot.clip_offset_utf16(
28461            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
28462            Bias::Right,
28463        );
28464        if (start.0.0..end.0.0) != range_utf16 {
28465            adjusted_range.replace(start.0.0..end.0.0);
28466        }
28467        Some(snapshot.text_for_range(start..end).collect())
28468    }
28469
28470    fn selected_text_range(
28471        &mut self,
28472        ignore_disabled_input: bool,
28473        _: &mut Window,
28474        cx: &mut Context<Self>,
28475    ) -> Option<UTF16Selection> {
28476        // Prevent the IME menu from appearing when holding down an alphabetic key
28477        // while input is disabled.
28478        if !ignore_disabled_input && !self.input_enabled {
28479            return None;
28480        }
28481
28482        let selection = self
28483            .selections
28484            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
28485        let range = selection.range();
28486
28487        Some(UTF16Selection {
28488            range: range.start.0.0..range.end.0.0,
28489            reversed: selection.reversed,
28490        })
28491    }
28492
28493    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
28494        let snapshot = self.buffer.read(cx).read(cx);
28495        let range = self
28496            .text_highlights(HighlightKey::InputComposition, cx)?
28497            .1
28498            .first()?;
28499        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
28500    }
28501
28502    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
28503        self.clear_highlights(HighlightKey::InputComposition, cx);
28504        self.ime_transaction.take();
28505    }
28506
28507    fn replace_text_in_range(
28508        &mut self,
28509        range_utf16: Option<Range<usize>>,
28510        text: &str,
28511        window: &mut Window,
28512        cx: &mut Context<Self>,
28513    ) {
28514        if !self.input_enabled {
28515            cx.emit(EditorEvent::InputIgnored { text: text.into() });
28516            return;
28517        }
28518
28519        self.transact(window, cx, |this, window, cx| {
28520            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
28521                if let Some(marked_ranges) = this.marked_text_ranges(cx) {
28522                    // During IME composition, macOS reports the replacement range
28523                    // relative to the first marked region (the only one visible via
28524                    // marked_text_range). The correct targets for replacement are the
28525                    // marked ranges themselves — one per cursor — so use them directly.
28526                    Some(marked_ranges)
28527                } else if range_utf16.start == range_utf16.end {
28528                    // An empty replacement range means "insert at cursor" with no text
28529                    // to replace. macOS reports the cursor position from its own
28530                    // (single-cursor) view of the buffer, which diverges from our actual
28531                    // cursor positions after multi-cursor edits have shifted offsets.
28532                    // Treating this as range_utf16=None lets each cursor insert in place.
28533                    None
28534                } else {
28535                    // Outside of IME composition (e.g. Accessibility Keyboard word
28536                    // completion), the range is an absolute document offset for the
28537                    // newest cursor. Fan it out to all cursors via
28538                    // selection_replacement_ranges, which applies the delta relative
28539                    // to the newest selection to every cursor.
28540                    let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28541                        ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28542                    Some(this.selection_replacement_ranges(range_utf16, cx))
28543                }
28544            } else {
28545                this.marked_text_ranges(cx)
28546            };
28547
28548            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
28549                let newest_selection_id = this.selections.newest_anchor().id;
28550                this.selections
28551                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28552                    .iter()
28553                    .zip(ranges_to_replace.iter())
28554                    .find_map(|(selection, range)| {
28555                        if selection.id == newest_selection_id {
28556                            Some(
28557                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28558                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28559                            )
28560                        } else {
28561                            None
28562                        }
28563                    })
28564            });
28565
28566            cx.emit(EditorEvent::InputHandled {
28567                utf16_range_to_replace: range_to_replace,
28568                text: text.into(),
28569            });
28570
28571            if let Some(new_selected_ranges) = new_selected_ranges {
28572                // Only backspace if at least one range covers actual text. When all
28573                // ranges are empty (e.g. a trailing-space insertion from Accessibility
28574                // Keyboard sends replacementRange=cursor..cursor), backspace would
28575                // incorrectly delete the character just before the cursor.
28576                let should_backspace = new_selected_ranges.iter().any(|r| r.start != r.end);
28577                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28578                    selections.select_ranges(new_selected_ranges)
28579                });
28580                if should_backspace {
28581                    this.backspace(&Default::default(), window, cx);
28582                }
28583            }
28584
28585            this.handle_input(text, window, cx);
28586        });
28587
28588        if let Some(transaction) = self.ime_transaction {
28589            self.buffer.update(cx, |buffer, cx| {
28590                buffer.group_until_transaction(transaction, cx);
28591            });
28592        }
28593
28594        self.unmark_text(window, cx);
28595    }
28596
28597    fn replace_and_mark_text_in_range(
28598        &mut self,
28599        range_utf16: Option<Range<usize>>,
28600        text: &str,
28601        new_selected_range_utf16: Option<Range<usize>>,
28602        window: &mut Window,
28603        cx: &mut Context<Self>,
28604    ) {
28605        if !self.input_enabled {
28606            return;
28607        }
28608
28609        let transaction = self.transact(window, cx, |this, window, cx| {
28610            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
28611                let snapshot = this.buffer.read(cx).read(cx);
28612                if let Some(relative_range_utf16) = range_utf16.as_ref() {
28613                    for marked_range in &mut marked_ranges {
28614                        marked_range.end = marked_range.start + relative_range_utf16.end;
28615                        marked_range.start += relative_range_utf16.start;
28616                        marked_range.start =
28617                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
28618                        marked_range.end =
28619                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
28620                    }
28621                }
28622                Some(marked_ranges)
28623            } else if let Some(range_utf16) = range_utf16 {
28624                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
28625                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
28626                Some(this.selection_replacement_ranges(range_utf16, cx))
28627            } else {
28628                None
28629            };
28630
28631            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
28632                let newest_selection_id = this.selections.newest_anchor().id;
28633                this.selections
28634                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
28635                    .iter()
28636                    .zip(ranges_to_replace.iter())
28637                    .find_map(|(selection, range)| {
28638                        if selection.id == newest_selection_id {
28639                            Some(
28640                                (range.start.0.0 as isize - selection.head().0.0 as isize)
28641                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
28642                            )
28643                        } else {
28644                            None
28645                        }
28646                    })
28647            });
28648
28649            cx.emit(EditorEvent::InputHandled {
28650                utf16_range_to_replace: range_to_replace,
28651                text: text.into(),
28652            });
28653
28654            if let Some(ranges) = ranges_to_replace {
28655                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
28656                    s.select_ranges(ranges)
28657                });
28658            }
28659
28660            let marked_ranges = {
28661                let snapshot = this.buffer.read(cx).read(cx);
28662                this.selections
28663                    .disjoint_anchors_arc()
28664                    .iter()
28665                    .map(|selection| {
28666                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
28667                    })
28668                    .collect::<Vec<_>>()
28669            };
28670
28671            if text.is_empty() {
28672                this.unmark_text(window, cx);
28673            } else {
28674                this.highlight_text(
28675                    HighlightKey::InputComposition,
28676                    marked_ranges.clone(),
28677                    HighlightStyle {
28678                        underline: Some(UnderlineStyle {
28679                            thickness: px(1.),
28680                            color: None,
28681                            wavy: false,
28682                        }),
28683                        ..Default::default()
28684                    },
28685                    cx,
28686                );
28687            }
28688
28689            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
28690            let use_autoclose = this.use_autoclose;
28691            let use_auto_surround = this.use_auto_surround;
28692            this.set_use_autoclose(false);
28693            this.set_use_auto_surround(false);
28694            this.handle_input(text, window, cx);
28695            this.set_use_autoclose(use_autoclose);
28696            this.set_use_auto_surround(use_auto_surround);
28697
28698            if let Some(new_selected_range) = new_selected_range_utf16 {
28699                let snapshot = this.buffer.read(cx).read(cx);
28700                let new_selected_ranges = marked_ranges
28701                    .into_iter()
28702                    .map(|marked_range| {
28703                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
28704                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
28705                            insertion_start.0 + new_selected_range.start,
28706                        ));
28707                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
28708                            insertion_start.0 + new_selected_range.end,
28709                        ));
28710                        snapshot.clip_offset_utf16(new_start, Bias::Left)
28711                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
28712                    })
28713                    .collect::<Vec<_>>();
28714
28715                drop(snapshot);
28716                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
28717                    selections.select_ranges(new_selected_ranges)
28718                });
28719            }
28720        });
28721
28722        self.ime_transaction = self.ime_transaction.or(transaction);
28723        if let Some(transaction) = self.ime_transaction {
28724            self.buffer.update(cx, |buffer, cx| {
28725                buffer.group_until_transaction(transaction, cx);
28726            });
28727        }
28728
28729        if self
28730            .text_highlights(HighlightKey::InputComposition, cx)
28731            .is_none()
28732        {
28733            self.ime_transaction.take();
28734        }
28735    }
28736
28737    fn bounds_for_range(
28738        &mut self,
28739        range_utf16: Range<usize>,
28740        element_bounds: gpui::Bounds<Pixels>,
28741        window: &mut Window,
28742        cx: &mut Context<Self>,
28743    ) -> Option<gpui::Bounds<Pixels>> {
28744        let text_layout_details = self.text_layout_details(window, cx);
28745        let CharacterDimensions {
28746            em_width,
28747            em_advance,
28748            line_height,
28749        } = self.character_dimensions(window, cx);
28750
28751        let snapshot = self.snapshot(window, cx);
28752        let scroll_position = snapshot.scroll_position();
28753        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28754
28755        let start =
28756            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28757        let x = Pixels::from(
28758            ScrollOffset::from(
28759                snapshot.x_for_display_point(start, &text_layout_details)
28760                    + self.gutter_dimensions.full_width(),
28761            ) - scroll_left,
28762        );
28763        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28764
28765        Some(Bounds {
28766            origin: element_bounds.origin + point(x, y),
28767            size: size(em_width, line_height),
28768        })
28769    }
28770
28771    fn character_index_for_point(
28772        &mut self,
28773        point: gpui::Point<Pixels>,
28774        _window: &mut Window,
28775        _cx: &mut Context<Self>,
28776    ) -> Option<usize> {
28777        let position_map = self.last_position_map.as_ref()?;
28778        if !position_map.text_hitbox.contains(&point) {
28779            return None;
28780        }
28781        let display_point = position_map.point_for_position(point).previous_valid;
28782        let anchor = position_map
28783            .snapshot
28784            .display_point_to_anchor(display_point, Bias::Left);
28785        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28786        Some(utf16_offset.0.0)
28787    }
28788
28789    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28790        self.expects_character_input
28791    }
28792}
28793
28794trait SelectionExt {
28795    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28796    fn spanned_rows(
28797        &self,
28798        include_end_if_at_line_start: bool,
28799        map: &DisplaySnapshot,
28800    ) -> Range<MultiBufferRow>;
28801}
28802
28803impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28804    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28805        let start = self
28806            .start
28807            .to_point(map.buffer_snapshot())
28808            .to_display_point(map);
28809        let end = self
28810            .end
28811            .to_point(map.buffer_snapshot())
28812            .to_display_point(map);
28813        if self.reversed {
28814            end..start
28815        } else {
28816            start..end
28817        }
28818    }
28819
28820    fn spanned_rows(
28821        &self,
28822        include_end_if_at_line_start: bool,
28823        map: &DisplaySnapshot,
28824    ) -> Range<MultiBufferRow> {
28825        let start = self.start.to_point(map.buffer_snapshot());
28826        let mut end = self.end.to_point(map.buffer_snapshot());
28827        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28828            end.row -= 1;
28829        }
28830
28831        let buffer_start = map.prev_line_boundary(start).0;
28832        let buffer_end = map.next_line_boundary(end).0;
28833        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28834    }
28835}
28836
28837impl<T: InvalidationRegion> InvalidationStack<T> {
28838    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28839    where
28840        S: Clone + ToOffset,
28841    {
28842        while let Some(region) = self.last() {
28843            let all_selections_inside_invalidation_ranges =
28844                if selections.len() == region.ranges().len() {
28845                    selections
28846                        .iter()
28847                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28848                        .all(|(selection, invalidation_range)| {
28849                            let head = selection.head().to_offset(buffer);
28850                            invalidation_range.start <= head && invalidation_range.end >= head
28851                        })
28852                } else {
28853                    false
28854                };
28855
28856            if all_selections_inside_invalidation_ranges {
28857                break;
28858            } else {
28859                self.pop();
28860            }
28861        }
28862    }
28863}
28864
28865#[derive(Clone)]
28866struct ErasedEditorImpl(Entity<Editor>);
28867
28868impl ui_input::ErasedEditor for ErasedEditorImpl {
28869    fn text(&self, cx: &App) -> String {
28870        self.0.read(cx).text(cx)
28871    }
28872
28873    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28874        self.0.update(cx, |this, cx| {
28875            this.set_text(text, window, cx);
28876        })
28877    }
28878
28879    fn clear(&self, window: &mut Window, cx: &mut App) {
28880        self.0.update(cx, |this, cx| this.clear(window, cx));
28881    }
28882
28883    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28884        self.0.update(cx, |this, cx| {
28885            this.set_placeholder_text(text, window, cx);
28886        });
28887    }
28888
28889    fn focus_handle(&self, cx: &App) -> FocusHandle {
28890        self.0.read(cx).focus_handle(cx)
28891    }
28892
28893    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28894        let settings = ThemeSettings::get_global(cx);
28895        let theme_color = cx.theme().colors();
28896
28897        let text_style = TextStyle {
28898            font_family: settings.ui_font.family.clone(),
28899            font_features: settings.ui_font.features.clone(),
28900            font_size: rems(0.875).into(),
28901            font_weight: settings.ui_font.weight,
28902            font_style: FontStyle::Normal,
28903            line_height: relative(1.2),
28904            color: theme_color.text,
28905            ..Default::default()
28906        };
28907        let editor_style = EditorStyle {
28908            background: theme_color.ghost_element_background,
28909            local_player: cx.theme().players().local(),
28910            syntax: cx.theme().syntax().clone(),
28911            text: text_style,
28912            ..Default::default()
28913        };
28914        EditorElement::new(&self.0, editor_style).into_any()
28915    }
28916
28917    fn as_any(&self) -> &dyn Any {
28918        &self.0
28919    }
28920
28921    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28922        self.0.update(cx, |editor, cx| {
28923            let editor_offset = editor.buffer().read(cx).len(cx);
28924            editor.change_selections(
28925                SelectionEffects::scroll(Autoscroll::Next),
28926                window,
28927                cx,
28928                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28929            );
28930        });
28931    }
28932
28933    fn subscribe(
28934        &self,
28935        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28936        window: &mut Window,
28937        cx: &mut App,
28938    ) -> Subscription {
28939        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28940            let event = match event {
28941                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28942                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28943                _ => return,
28944            };
28945            (callback)(event, window, cx);
28946        })
28947    }
28948
28949    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28950        self.0.update(cx, |editor, cx| {
28951            editor.set_masked(masked, cx);
28952        });
28953    }
28954}
28955impl<T> Default for InvalidationStack<T> {
28956    fn default() -> Self {
28957        Self(Default::default())
28958    }
28959}
28960
28961impl<T> Deref for InvalidationStack<T> {
28962    type Target = Vec<T>;
28963
28964    fn deref(&self) -> &Self::Target {
28965        &self.0
28966    }
28967}
28968
28969impl<T> DerefMut for InvalidationStack<T> {
28970    fn deref_mut(&mut self) -> &mut Self::Target {
28971        &mut self.0
28972    }
28973}
28974
28975impl InvalidationRegion for SnippetState {
28976    fn ranges(&self) -> &[Range<Anchor>] {
28977        &self.ranges[self.active_index]
28978    }
28979}
28980
28981fn edit_prediction_edit_text(
28982    current_snapshot: &BufferSnapshot,
28983    edits: &[(Range<Anchor>, impl AsRef<str>)],
28984    edit_preview: &EditPreview,
28985    include_deletions: bool,
28986    multibuffer_snapshot: &MultiBufferSnapshot,
28987    cx: &App,
28988) -> HighlightedText {
28989    let edits = edits
28990        .iter()
28991        .filter_map(|(anchor, text)| {
28992            Some((
28993                multibuffer_snapshot
28994                    .anchor_range_to_buffer_anchor_range(anchor.clone())?
28995                    .1,
28996                text,
28997            ))
28998        })
28999        .collect::<Vec<_>>();
29000
29001    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
29002}
29003
29004fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
29005    // Fallback for providers that don't provide edit_preview (like Copilot)
29006    // Just show the raw edit text with basic styling
29007    let mut text = String::new();
29008    let mut highlights = Vec::new();
29009
29010    let insertion_highlight_style = HighlightStyle {
29011        color: Some(cx.theme().colors().text),
29012        ..Default::default()
29013    };
29014
29015    for (_, edit_text) in edits {
29016        let start_offset = text.len();
29017        text.push_str(edit_text);
29018        let end_offset = text.len();
29019
29020        if start_offset < end_offset {
29021            highlights.push((start_offset..end_offset, insertion_highlight_style));
29022        }
29023    }
29024
29025    HighlightedText {
29026        text: text.into(),
29027        highlights,
29028    }
29029}
29030
29031pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
29032    match severity {
29033        lsp::DiagnosticSeverity::ERROR => colors.error,
29034        lsp::DiagnosticSeverity::WARNING => colors.warning,
29035        lsp::DiagnosticSeverity::INFORMATION => colors.info,
29036        lsp::DiagnosticSeverity::HINT => colors.info,
29037        _ => colors.ignored,
29038    }
29039}
29040
29041pub fn styled_runs_for_code_label<'a>(
29042    label: &'a CodeLabel,
29043    syntax_theme: &'a theme::SyntaxTheme,
29044    local_player: &'a theme::PlayerColor,
29045) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
29046    let fade_out = HighlightStyle {
29047        fade_out: Some(0.35),
29048        ..Default::default()
29049    };
29050
29051    if label.runs.is_empty() {
29052        let desc_start = label.filter_range.end;
29053        let fade_run =
29054            (desc_start < label.text.len()).then(|| (desc_start..label.text.len(), fade_out));
29055        return Either::Left(fade_run.into_iter());
29056    }
29057
29058    let mut prev_end = label.filter_range.end;
29059    Either::Right(
29060        label
29061            .runs
29062            .iter()
29063            .enumerate()
29064            .flat_map(move |(ix, (range, highlight_id))| {
29065                let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
29066                    HighlightStyle {
29067                        color: Some(local_player.cursor),
29068                        ..Default::default()
29069                    }
29070                } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
29071                    HighlightStyle {
29072                        background_color: Some(local_player.selection),
29073                        ..Default::default()
29074                    }
29075                } else if let Some(style) = syntax_theme.get(*highlight_id).cloned() {
29076                    style
29077                } else {
29078                    return Default::default();
29079                };
29080
29081                let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
29082                let muted_style = style.highlight(fade_out);
29083                if range.start >= label.filter_range.end {
29084                    if range.start > prev_end {
29085                        runs.push((prev_end..range.start, fade_out));
29086                    }
29087                    runs.push((range.clone(), muted_style));
29088                } else if range.end <= label.filter_range.end {
29089                    runs.push((range.clone(), style));
29090                } else {
29091                    runs.push((range.start..label.filter_range.end, style));
29092                    runs.push((label.filter_range.end..range.end, muted_style));
29093                }
29094                prev_end = cmp::max(prev_end, range.end);
29095
29096                if ix + 1 == label.runs.len() && label.text.len() > prev_end {
29097                    runs.push((prev_end..label.text.len(), fade_out));
29098                }
29099
29100                runs
29101            }),
29102    )
29103}
29104
29105pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
29106    let mut prev_index = 0;
29107    let mut prev_codepoint: Option<char> = None;
29108    text.char_indices()
29109        .chain([(text.len(), '\0')])
29110        .filter_map(move |(index, codepoint)| {
29111            let prev_codepoint = prev_codepoint.replace(codepoint)?;
29112            let is_boundary = index == text.len()
29113                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
29114                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
29115            if is_boundary {
29116                let chunk = &text[prev_index..index];
29117                prev_index = index;
29118                Some(chunk)
29119            } else {
29120                None
29121            }
29122        })
29123}
29124
29125/// Given a string of text immediately before the cursor, iterates over possible
29126/// strings a snippet could match to. More precisely: returns an iterator over
29127/// suffixes of `text` created by splitting at word boundaries (before & after
29128/// every non-word character).
29129///
29130/// Shorter suffixes are returned first.
29131pub(crate) fn snippet_candidate_suffixes<'a>(
29132    text: &'a str,
29133    is_word_char: &'a dyn Fn(char) -> bool,
29134) -> impl std::iter::Iterator<Item = &'a str> + 'a {
29135    let mut prev_index = text.len();
29136    let mut prev_codepoint = None;
29137    text.char_indices()
29138        .rev()
29139        .chain([(0, '\0')])
29140        .filter_map(move |(index, codepoint)| {
29141            let prev_index = std::mem::replace(&mut prev_index, index);
29142            let prev_codepoint = prev_codepoint.replace(codepoint)?;
29143            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
29144                None
29145            } else {
29146                let chunk = &text[prev_index..]; // go to end of string
29147                Some(chunk)
29148            }
29149        })
29150}
29151
29152pub trait RangeToAnchorExt: Sized {
29153    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
29154
29155    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
29156        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
29157        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
29158    }
29159}
29160
29161impl<T: ToOffset> RangeToAnchorExt for Range<T> {
29162    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
29163        let start_offset = self.start.to_offset(snapshot);
29164        let end_offset = self.end.to_offset(snapshot);
29165        if start_offset == end_offset {
29166            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
29167        } else {
29168            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
29169        }
29170    }
29171}
29172
29173pub trait RowExt {
29174    fn as_f64(&self) -> f64;
29175
29176    fn next_row(&self) -> Self;
29177
29178    fn previous_row(&self) -> Self;
29179
29180    fn minus(&self, other: Self) -> u32;
29181}
29182
29183impl RowExt for DisplayRow {
29184    fn as_f64(&self) -> f64 {
29185        self.0 as _
29186    }
29187
29188    fn next_row(&self) -> Self {
29189        Self(self.0 + 1)
29190    }
29191
29192    fn previous_row(&self) -> Self {
29193        Self(self.0.saturating_sub(1))
29194    }
29195
29196    fn minus(&self, other: Self) -> u32 {
29197        self.0 - other.0
29198    }
29199}
29200
29201impl RowExt for MultiBufferRow {
29202    fn as_f64(&self) -> f64 {
29203        self.0 as _
29204    }
29205
29206    fn next_row(&self) -> Self {
29207        Self(self.0 + 1)
29208    }
29209
29210    fn previous_row(&self) -> Self {
29211        Self(self.0.saturating_sub(1))
29212    }
29213
29214    fn minus(&self, other: Self) -> u32 {
29215        self.0 - other.0
29216    }
29217}
29218
29219trait RowRangeExt {
29220    type Row;
29221
29222    fn len(&self) -> usize;
29223
29224    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
29225}
29226
29227impl RowRangeExt for Range<MultiBufferRow> {
29228    type Row = MultiBufferRow;
29229
29230    fn len(&self) -> usize {
29231        (self.end.0 - self.start.0) as usize
29232    }
29233
29234    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
29235        (self.start.0..self.end.0).map(MultiBufferRow)
29236    }
29237}
29238
29239impl RowRangeExt for Range<DisplayRow> {
29240    type Row = DisplayRow;
29241
29242    fn len(&self) -> usize {
29243        (self.end.0 - self.start.0) as usize
29244    }
29245
29246    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
29247        (self.start.0..self.end.0).map(DisplayRow)
29248    }
29249}
29250
29251/// If select range has more than one line, we
29252/// just point the cursor to range.start.
29253fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
29254    if range.start.row == range.end.row {
29255        range
29256    } else {
29257        range.start..range.start
29258    }
29259}
29260pub struct KillRing(ClipboardItem);
29261impl Global for KillRing {}
29262
29263const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
29264
29265enum BreakpointPromptEditAction {
29266    Log,
29267    Condition,
29268    HitCondition,
29269}
29270
29271struct BreakpointPromptEditor {
29272    pub(crate) prompt: Entity<Editor>,
29273    editor: WeakEntity<Editor>,
29274    breakpoint_anchor: Anchor,
29275    breakpoint: Breakpoint,
29276    edit_action: BreakpointPromptEditAction,
29277    block_ids: HashSet<CustomBlockId>,
29278    editor_margins: Arc<Mutex<EditorMargins>>,
29279    _subscriptions: Vec<Subscription>,
29280}
29281
29282impl BreakpointPromptEditor {
29283    const MAX_LINES: u8 = 4;
29284
29285    fn new(
29286        editor: WeakEntity<Editor>,
29287        breakpoint_anchor: Anchor,
29288        breakpoint: Breakpoint,
29289        edit_action: BreakpointPromptEditAction,
29290        window: &mut Window,
29291        cx: &mut Context<Self>,
29292    ) -> Self {
29293        let base_text = match edit_action {
29294            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
29295            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
29296            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
29297        }
29298        .map(|msg| msg.to_string())
29299        .unwrap_or_default();
29300
29301        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
29302        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
29303
29304        let prompt = cx.new(|cx| {
29305            let mut prompt = Editor::new(
29306                EditorMode::AutoHeight {
29307                    min_lines: 1,
29308                    max_lines: Some(Self::MAX_LINES as usize),
29309                },
29310                buffer,
29311                None,
29312                window,
29313                cx,
29314            );
29315            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
29316            prompt.set_show_cursor_when_unfocused(false, cx);
29317            prompt.set_placeholder_text(
29318                match edit_action {
29319                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
29320                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
29321                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
29322                },
29323                window,
29324                cx,
29325            );
29326
29327            prompt
29328        });
29329
29330        Self {
29331            prompt,
29332            editor,
29333            breakpoint_anchor,
29334            breakpoint,
29335            edit_action,
29336            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
29337            block_ids: Default::default(),
29338            _subscriptions: vec![],
29339        }
29340    }
29341
29342    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
29343        self.block_ids.extend(block_ids)
29344    }
29345
29346    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
29347        if let Some(editor) = self.editor.upgrade() {
29348            let message = self
29349                .prompt
29350                .read(cx)
29351                .buffer
29352                .read(cx)
29353                .as_singleton()
29354                .expect("A multi buffer in breakpoint prompt isn't possible")
29355                .read(cx)
29356                .as_rope()
29357                .to_string();
29358
29359            editor.update(cx, |editor, cx| {
29360                editor.edit_breakpoint_at_anchor(
29361                    self.breakpoint_anchor,
29362                    self.breakpoint.clone(),
29363                    match self.edit_action {
29364                        BreakpointPromptEditAction::Log => {
29365                            BreakpointEditAction::EditLogMessage(message.into())
29366                        }
29367                        BreakpointPromptEditAction::Condition => {
29368                            BreakpointEditAction::EditCondition(message.into())
29369                        }
29370                        BreakpointPromptEditAction::HitCondition => {
29371                            BreakpointEditAction::EditHitCondition(message.into())
29372                        }
29373                    },
29374                    cx,
29375                );
29376
29377                editor.remove_blocks(self.block_ids.clone(), None, cx);
29378                cx.focus_self(window);
29379            });
29380        }
29381    }
29382
29383    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
29384        self.editor
29385            .update(cx, |editor, cx| {
29386                editor.remove_blocks(self.block_ids.clone(), None, cx);
29387                window.focus(&editor.focus_handle, cx);
29388            })
29389            .log_err();
29390    }
29391
29392    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
29393        let settings = ThemeSettings::get_global(cx);
29394        let text_style = TextStyle {
29395            color: if self.prompt.read(cx).read_only(cx) {
29396                cx.theme().colors().text_disabled
29397            } else {
29398                cx.theme().colors().text
29399            },
29400            font_family: settings.buffer_font.family.clone(),
29401            font_fallbacks: settings.buffer_font.fallbacks.clone(),
29402            font_size: settings.buffer_font_size(cx).into(),
29403            font_weight: settings.buffer_font.weight,
29404            line_height: relative(settings.buffer_line_height.value()),
29405            ..Default::default()
29406        };
29407        EditorElement::new(
29408            &self.prompt,
29409            EditorStyle {
29410                background: cx.theme().colors().editor_background,
29411                local_player: cx.theme().players().local(),
29412                text: text_style,
29413                ..Default::default()
29414            },
29415        )
29416    }
29417
29418    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29419        let focus_handle = self.prompt.focus_handle(cx);
29420        IconButton::new("cancel", IconName::Close)
29421            .icon_color(Color::Muted)
29422            .shape(IconButtonShape::Square)
29423            .tooltip(move |_window, cx| {
29424                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
29425            })
29426            .on_click(cx.listener(|this, _, window, cx| {
29427                this.cancel(&menu::Cancel, window, cx);
29428            }))
29429    }
29430
29431    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
29432        let focus_handle = self.prompt.focus_handle(cx);
29433        IconButton::new("confirm", IconName::Return)
29434            .icon_color(Color::Muted)
29435            .shape(IconButtonShape::Square)
29436            .tooltip(move |_window, cx| {
29437                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
29438            })
29439            .on_click(cx.listener(|this, _, window, cx| {
29440                this.confirm(&menu::Confirm, window, cx);
29441            }))
29442    }
29443}
29444
29445impl Render for BreakpointPromptEditor {
29446    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29447        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
29448        let editor_margins = *self.editor_margins.lock();
29449        let gutter_dimensions = editor_margins.gutter;
29450        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
29451        let right_padding = editor_margins.right + px(9.);
29452        h_flex()
29453            .key_context("Editor")
29454            .bg(cx.theme().colors().editor_background)
29455            .border_y_1()
29456            .border_color(cx.theme().status().info_border)
29457            .size_full()
29458            .py(window.line_height() / 2.5)
29459            .pr(right_padding)
29460            .on_action(cx.listener(Self::confirm))
29461            .on_action(cx.listener(Self::cancel))
29462            .child(
29463                WithRemSize::new(ui_font_size)
29464                    .h_full()
29465                    .w(left_gutter_width)
29466                    .flex()
29467                    .flex_row()
29468                    .flex_shrink_0()
29469                    .items_center()
29470                    .justify_center()
29471                    .gap_1()
29472                    .child(self.render_close_button(cx)),
29473            )
29474            .child(
29475                h_flex()
29476                    .w_full()
29477                    .justify_between()
29478                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
29479                    .child(
29480                        WithRemSize::new(ui_font_size)
29481                            .flex()
29482                            .flex_row()
29483                            .items_center()
29484                            .child(self.render_confirm_button(cx)),
29485                    ),
29486            )
29487    }
29488}
29489
29490impl Focusable for BreakpointPromptEditor {
29491    fn focus_handle(&self, cx: &App) -> FocusHandle {
29492        self.prompt.focus_handle(cx)
29493    }
29494}
29495
29496fn all_edits_insertions_or_deletions(
29497    edits: &Vec<(Range<Anchor>, Arc<str>)>,
29498    snapshot: &MultiBufferSnapshot,
29499) -> bool {
29500    let mut all_insertions = true;
29501    let mut all_deletions = true;
29502
29503    for (range, new_text) in edits.iter() {
29504        let range_is_empty = range.to_offset(snapshot).is_empty();
29505        let text_is_empty = new_text.is_empty();
29506
29507        if range_is_empty != text_is_empty {
29508            if range_is_empty {
29509                all_deletions = false;
29510            } else {
29511                all_insertions = false;
29512            }
29513        } else {
29514            return false;
29515        }
29516
29517        if !all_insertions && !all_deletions {
29518            return false;
29519        }
29520    }
29521    all_insertions || all_deletions
29522}
29523
29524struct MissingEditPredictionKeybindingTooltip;
29525
29526impl Render for MissingEditPredictionKeybindingTooltip {
29527    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
29528        ui::tooltip_container(cx, |container, cx| {
29529            container
29530                .flex_shrink_0()
29531                .max_w_80()
29532                .min_h(rems_from_px(124.))
29533                .justify_between()
29534                .child(
29535                    v_flex()
29536                        .flex_1()
29537                        .text_ui_sm(cx)
29538                        .child(Label::new("Conflict with Accept Keybinding"))
29539                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
29540                )
29541                .child(
29542                    h_flex()
29543                        .pb_1()
29544                        .gap_1()
29545                        .items_end()
29546                        .w_full()
29547                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
29548                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
29549                        }))
29550                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
29551                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
29552                        })),
29553                )
29554        })
29555    }
29556}
29557
29558#[derive(Debug, Clone, Copy, PartialEq)]
29559pub struct LineHighlight {
29560    pub background: Background,
29561    pub border: Option<gpui::Hsla>,
29562    pub include_gutter: bool,
29563    pub type_id: Option<TypeId>,
29564}
29565
29566struct LineManipulationResult {
29567    pub new_text: String,
29568    pub line_count_before: usize,
29569    pub line_count_after: usize,
29570}
29571
29572fn render_diff_hunk_controls(
29573    row: u32,
29574    status: &DiffHunkStatus,
29575    hunk_range: Range<Anchor>,
29576    is_created_file: bool,
29577    line_height: Pixels,
29578    editor: &Entity<Editor>,
29579    _window: &mut Window,
29580    cx: &mut App,
29581) -> AnyElement {
29582    h_flex()
29583        .h(line_height)
29584        .mr_1()
29585        .gap_1()
29586        .px_0p5()
29587        .pb_1()
29588        .border_x_1()
29589        .border_b_1()
29590        .border_color(cx.theme().colors().border_variant)
29591        .rounded_b_lg()
29592        .bg(cx.theme().colors().editor_background)
29593        .gap_1()
29594        .block_mouse_except_scroll()
29595        .shadow_md()
29596        .child(if status.has_secondary_hunk() {
29597            Button::new(("stage", row as u64), "Stage")
29598                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29599                .tooltip({
29600                    let focus_handle = editor.focus_handle(cx);
29601                    move |_window, cx| {
29602                        Tooltip::for_action_in(
29603                            "Stage Hunk",
29604                            &::git::ToggleStaged,
29605                            &focus_handle,
29606                            cx,
29607                        )
29608                    }
29609                })
29610                .on_click({
29611                    let editor = editor.clone();
29612                    move |_event, _window, cx| {
29613                        editor.update(cx, |editor, cx| {
29614                            editor.stage_or_unstage_diff_hunks(
29615                                true,
29616                                vec![hunk_range.start..hunk_range.start],
29617                                cx,
29618                            );
29619                        });
29620                    }
29621                })
29622        } else {
29623            Button::new(("unstage", row as u64), "Unstage")
29624                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
29625                .tooltip({
29626                    let focus_handle = editor.focus_handle(cx);
29627                    move |_window, cx| {
29628                        Tooltip::for_action_in(
29629                            "Unstage Hunk",
29630                            &::git::ToggleStaged,
29631                            &focus_handle,
29632                            cx,
29633                        )
29634                    }
29635                })
29636                .on_click({
29637                    let editor = editor.clone();
29638                    move |_event, _window, cx| {
29639                        editor.update(cx, |editor, cx| {
29640                            editor.stage_or_unstage_diff_hunks(
29641                                false,
29642                                vec![hunk_range.start..hunk_range.start],
29643                                cx,
29644                            );
29645                        });
29646                    }
29647                })
29648        })
29649        .child(
29650            Button::new(("restore", row as u64), "Restore")
29651                .tooltip({
29652                    let focus_handle = editor.focus_handle(cx);
29653                    move |_window, cx| {
29654                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
29655                    }
29656                })
29657                .on_click({
29658                    let editor = editor.clone();
29659                    move |_event, window, cx| {
29660                        editor.update(cx, |editor, cx| {
29661                            let snapshot = editor.snapshot(window, cx);
29662                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
29663                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
29664                        });
29665                    }
29666                })
29667                .disabled(is_created_file),
29668        )
29669        .when(
29670            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
29671            |el| {
29672                el.child(
29673                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
29674                        .shape(IconButtonShape::Square)
29675                        .icon_size(IconSize::Small)
29676                        // .disabled(!has_multiple_hunks)
29677                        .tooltip({
29678                            let focus_handle = editor.focus_handle(cx);
29679                            move |_window, cx| {
29680                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
29681                            }
29682                        })
29683                        .on_click({
29684                            let editor = editor.clone();
29685                            move |_event, window, cx| {
29686                                editor.update(cx, |editor, cx| {
29687                                    let snapshot = editor.snapshot(window, cx);
29688                                    let position =
29689                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
29690                                    editor.go_to_hunk_before_or_after_position(
29691                                        &snapshot,
29692                                        position,
29693                                        Direction::Next,
29694                                        true,
29695                                        window,
29696                                        cx,
29697                                    );
29698                                    editor.expand_selected_diff_hunks(cx);
29699                                });
29700                            }
29701                        }),
29702                )
29703                .child(
29704                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
29705                        .shape(IconButtonShape::Square)
29706                        .icon_size(IconSize::Small)
29707                        // .disabled(!has_multiple_hunks)
29708                        .tooltip({
29709                            let focus_handle = editor.focus_handle(cx);
29710                            move |_window, cx| {
29711                                Tooltip::for_action_in(
29712                                    "Previous Hunk",
29713                                    &GoToPreviousHunk,
29714                                    &focus_handle,
29715                                    cx,
29716                                )
29717                            }
29718                        })
29719                        .on_click({
29720                            let editor = editor.clone();
29721                            move |_event, window, cx| {
29722                                editor.update(cx, |editor, cx| {
29723                                    let snapshot = editor.snapshot(window, cx);
29724                                    let point =
29725                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
29726                                    editor.go_to_hunk_before_or_after_position(
29727                                        &snapshot,
29728                                        point,
29729                                        Direction::Prev,
29730                                        true,
29731                                        window,
29732                                        cx,
29733                                    );
29734                                    editor.expand_selected_diff_hunks(cx);
29735                                });
29736                            }
29737                        }),
29738                )
29739            },
29740        )
29741        .into_any_element()
29742}
29743
29744pub fn multibuffer_context_lines(cx: &App) -> u32 {
29745    EditorSettings::try_get(cx)
29746        .map(|settings| settings.excerpt_context_lines)
29747        .unwrap_or(2)
29748        .min(32)
29749}