editor.rs

    1#![allow(rustdoc::private_intra_doc_links)]
    2//! This is the place where everything editor-related is stored (data-wise) and displayed (ui-wise).
    3//! The main point of interest in this crate is [`Editor`] type, which is used in every other Zed part as a user input element.
    4//! It comes in different flavors: single line, multiline and a fixed height one.
    5//!
    6//! Editor contains of multiple large submodules:
    7//! * [`element`] — the place where all rendering happens
    8//! * [`display_map`] - chunks up text in the editor into the logical blocks, establishes coordinates and mapping between each of them.
    9//!   Contains all metadata related to text transformations (folds, fake inlay text insertions, soft wraps, tab markup, etc.).
   10//!
   11//! All other submodules and structs are mostly concerned with holding editor data about the way it displays current buffer region(s).
   12//!
   13//! If you're looking to improve Vim mode, you should check out Vim crate that wraps Editor and overrides its behavior.
   14pub mod actions;
   15pub mod blink_manager;
   16mod bracket_colorization;
   17mod clangd_ext;
   18pub mod code_context_menus;
   19pub mod display_map;
   20mod document_colors;
   21mod document_symbols;
   22mod editor_settings;
   23mod element;
   24mod folding_ranges;
   25mod git;
   26mod highlight_matching_bracket;
   27mod hover_links;
   28pub mod hover_popover;
   29mod indent_guides;
   30mod inlays;
   31pub mod items;
   32mod jsx_tag_auto_close;
   33mod linked_editing_ranges;
   34mod lsp_ext;
   35mod mouse_context_menu;
   36pub mod movement;
   37mod persistence;
   38mod runnables;
   39mod rust_analyzer_ext;
   40pub mod scroll;
   41mod selections_collection;
   42pub mod semantic_tokens;
   43mod split;
   44pub mod split_editor_view;
   45
   46#[cfg(test)]
   47mod code_completion_tests;
   48#[cfg(test)]
   49mod edit_prediction_tests;
   50#[cfg(test)]
   51mod editor_tests;
   52mod signature_help;
   53#[cfg(any(test, feature = "test-support"))]
   54pub mod test;
   55
   56pub(crate) use actions::*;
   57pub use display_map::{
   58    ChunkRenderer, ChunkRendererContext, DisplayPoint, FoldPlaceholder, HighlightKey,
   59    SemanticTokenHighlight,
   60};
   61pub use edit_prediction_types::Direction;
   62pub use editor_settings::{
   63    CompletionDetailAlignment, CurrentLineHighlight, DiffViewStyle, DocumentColorsRenderMode,
   64    EditorSettings, HideMouseMode, ScrollBeyondLastLine, ScrollbarAxes, SearchSettings,
   65    ShowMinimap,
   66};
   67pub use element::{
   68    CursorLayout, EditorElement, HighlightedRange, HighlightedRangeLine, PointForPosition,
   69    render_breadcrumb_text,
   70};
   71pub use git::blame::BlameRenderer;
   72pub use hover_popover::hover_markdown_style;
   73pub use inlays::Inlay;
   74pub use items::MAX_TAB_TITLE_LEN;
   75pub use linked_editing_ranges::LinkedEdits;
   76pub use lsp::CompletionContext;
   77pub use lsp_ext::lsp_tasks;
   78pub use multi_buffer::{
   79    Anchor, AnchorRangeExt, BufferOffset, ExcerptId, ExcerptRange, MBTextSummary, MultiBuffer,
   80    MultiBufferOffset, MultiBufferOffsetUtf16, MultiBufferSnapshot, PathKey, RowInfo, ToOffset,
   81    ToPoint,
   82};
   83pub use split::{SplittableEditor, ToggleSplitDiff};
   84pub use split_editor_view::SplitEditorView;
   85pub use text::Bias;
   86
   87use ::git::{Restore, blame::BlameEntry, commit::ParsedCommitMessage, status::FileStatus};
   88use aho_corasick::{AhoCorasick, AhoCorasickBuilder, BuildError};
   89use anyhow::{Context as _, Result, anyhow, bail};
   90use blink_manager::BlinkManager;
   91use buffer_diff::DiffHunkStatus;
   92use client::{Collaborator, ParticipantIndex, parse_zed_link};
   93use clock::ReplicaId;
   94use code_context_menus::{
   95    AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
   96    CompletionsMenu, ContextMenuOrigin,
   97};
   98use collections::{BTreeMap, HashMap, HashSet, VecDeque};
   99use convert_case::{Case, Casing};
  100use dap::TelemetrySpawnLocation;
  101use display_map::*;
  102use document_colors::LspColorData;
  103use edit_prediction_types::{
  104    EditPredictionDelegate, EditPredictionDelegateHandle, EditPredictionDiscardReason,
  105    EditPredictionGranularity, SuggestionDisplayType,
  106};
  107use editor_settings::{GoToDefinitionFallback, Minimap as MinimapSettings};
  108use element::{AcceptEditPredictionBinding, LineWithInvisibles, PositionMap, layout_line};
  109use futures::{
  110    FutureExt,
  111    future::{self, Shared, join},
  112};
  113use fuzzy::{StringMatch, StringMatchCandidate};
  114use git::blame::{GitBlame, GlobalBlameRenderer};
  115use gpui::{
  116    Action, Animation, AnimationExt, AnyElement, App, AppContext, AsyncWindowContext,
  117    AvailableSpace, Background, Bounds, ClickEvent, ClipboardEntry, ClipboardItem, Context,
  118    DispatchPhase, Edges, Entity, EntityId, EntityInputHandler, EventEmitter, FocusHandle,
  119    FocusOutEvent, Focusable, FontId, FontStyle, FontWeight, Global, HighlightStyle, Hsla,
  120    KeyContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, PaintQuad, ParentElement,
  121    Pixels, PressureStage, Render, ScrollHandle, SharedString, SharedUri, Size, Stateful, Styled,
  122    Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle,
  123    UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window, div, point, prelude::*,
  124    pulsating_between, px, relative, size,
  125};
  126use hover_links::{HoverLink, HoveredLinkState, find_file};
  127use hover_popover::{HoverState, hide_hover};
  128use indent_guides::ActiveIndentGuidesState;
  129use inlays::{InlaySplice, inlay_hints::InlayHintRefreshReason};
  130use itertools::{Either, Itertools};
  131use language::{
  132    AutoindentMode, BlockCommentConfig, BracketMatch, BracketPair, Buffer, BufferRow,
  133    BufferSnapshot, Capability, CharClassifier, CharKind, CharScopeContext, CodeLabel, CursorShape,
  134    DiagnosticEntryRef, DiffOptions, EditPredictionsMode, EditPreview, HighlightedText, IndentKind,
  135    IndentSize, Language, LanguageName, LanguageRegistry, LanguageScope, LocalFile, OffsetRangeExt,
  136    OutlineItem, Point, Selection, SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
  137    WordsQuery,
  138    language_settings::{
  139        self, LanguageSettings, LspInsertMode, RewrapBehavior, WordsCompletionMode,
  140        all_language_settings, language_settings,
  141    },
  142    point_from_lsp, point_to_lsp, text_diff_with_options,
  143};
  144use linked_editing_ranges::refresh_linked_ranges;
  145use lsp::{
  146    CodeActionKind, CompletionItemKind, CompletionTriggerKind, InsertTextFormat, InsertTextMode,
  147    LanguageServerId,
  148};
  149use markdown::Markdown;
  150use mouse_context_menu::MouseContextMenu;
  151use movement::TextLayoutDetails;
  152use multi_buffer::{
  153    ExcerptInfo, ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow,
  154};
  155use parking_lot::Mutex;
  156use persistence::DB;
  157use project::{
  158    BreakpointWithPosition, CodeAction, Completion, CompletionDisplayOptions, CompletionIntent,
  159    CompletionResponse, CompletionSource, DisableAiSettings, DocumentHighlight, InlayHint, InlayId,
  160    InvalidationStrategy, Location, LocationLink, LspAction, PrepareRenameResponse, Project,
  161    ProjectItem, ProjectPath, ProjectTransaction,
  162    debugger::{
  163        breakpoint_store::{
  164            Breakpoint, BreakpointEditAction, BreakpointSessionState, BreakpointState,
  165            BreakpointStore, BreakpointStoreEvent,
  166        },
  167        session::{Session, SessionEvent},
  168    },
  169    git_store::GitStoreEvent,
  170    lsp_store::{
  171        BufferSemanticTokens, CacheInlayHints, CompletionDocumentation, FormatTrigger,
  172        LspFormatTarget, OpenLspBufferHandle, RefreshForServer,
  173    },
  174    project_settings::{DiagnosticSeverity, GoToDiagnosticSeverityFilter, ProjectSettings},
  175};
  176use rand::seq::SliceRandom;
  177use regex::Regex;
  178use rpc::{ErrorCode, ErrorExt, proto::PeerId};
  179use scroll::{Autoscroll, OngoingScroll, ScrollAnchor, ScrollManager, SharedScrollAnchor};
  180use selections_collection::{MutableSelectionsCollection, SelectionsCollection};
  181use serde::{Deserialize, Serialize};
  182use settings::{
  183    GitGutterSetting, RelativeLineNumbers, Settings, SettingsLocation, SettingsStore,
  184    update_settings_file,
  185};
  186use smallvec::{SmallVec, smallvec};
  187use snippet::Snippet;
  188use std::{
  189    any::{Any, TypeId},
  190    borrow::Cow,
  191    cell::{OnceCell, RefCell},
  192    cmp::{self, Ordering, Reverse},
  193    collections::hash_map,
  194    iter::{self, Peekable},
  195    mem,
  196    num::NonZeroU32,
  197    ops::{ControlFlow, Deref, DerefMut, Not, Range, RangeInclusive},
  198    path::{Path, PathBuf},
  199    rc::Rc,
  200    sync::Arc,
  201    time::{Duration, Instant},
  202};
  203use task::TaskVariables;
  204use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};
  205use theme::{
  206    AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
  207    ThemeSettings, observe_buffer_font_size_adjustment,
  208};
  209use ui::{
  210    Avatar, ButtonSize, ButtonStyle, ContextMenu, Disclosure, IconButton, IconButtonShape,
  211    IconName, IconSize, Indicator, Key, Tooltip, h_flex, prelude::*, scrollbars::ScrollbarAutoHide,
  212    utils::WithRemSize,
  213};
  214use ui_input::ErasedEditor;
  215use util::{RangeExt, ResultExt, TryFutureExt, maybe, post_inc};
  216use workspace::{
  217    CollaboratorId, Item as WorkspaceItem, ItemId, ItemNavHistory, NavigationEntry, OpenInTerminal,
  218    OpenTerminal, Pane, RestoreOnStartupBehavior, SERIALIZATION_THROTTLE_TIME, SplitDirection,
  219    TabBarSettings, Toast, ViewId, Workspace, WorkspaceId, WorkspaceSettings,
  220    item::{ItemBufferKind, ItemHandle, PreviewTabsSettings, SaveOptions},
  221    notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
  222    searchable::SearchEvent,
  223};
  224use zed_actions::editor::{MoveDown, MoveUp};
  225
  226use crate::{
  227    code_context_menus::CompletionsMenuSource,
  228    editor_settings::MultiCursorModifier,
  229    hover_links::{find_url, find_url_from_range},
  230    inlays::{
  231        InlineValueCache,
  232        inlay_hints::{LspInlayHintData, inlay_hint_settings},
  233    },
  234    runnables::{ResolvedTasks, RunnableData, RunnableTasks},
  235    scroll::{ScrollOffset, ScrollPixelOffset},
  236    selections_collection::resolve_selections_wrapping_blocks,
  237    semantic_tokens::SemanticTokenState,
  238    signature_help::{SignatureHelpHiddenBy, SignatureHelpState},
  239};
  240
  241pub const FILE_HEADER_HEIGHT: u32 = 2;
  242pub const BUFFER_HEADER_PADDING: Rems = rems(0.25);
  243pub const MULTI_BUFFER_EXCERPT_HEADER_HEIGHT: u32 = 1;
  244const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  245const MAX_LINE_LEN: usize = 1024;
  246const MIN_NAVIGATION_HISTORY_ROW_DELTA: i64 = 10;
  247const MAX_SELECTION_HISTORY_LEN: usize = 1024;
  248pub(crate) const CURSORS_VISIBLE_FOR: Duration = Duration::from_millis(2000);
  249#[doc(hidden)]
  250pub const CODE_ACTIONS_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(250);
  251pub const SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(100);
  252
  253pub(crate) const CODE_ACTION_TIMEOUT: Duration = Duration::from_secs(5);
  254pub(crate) const FORMAT_TIMEOUT: Duration = Duration::from_secs(5);
  255pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration::from_secs(1);
  256pub const LSP_REQUEST_DEBOUNCE_TIMEOUT: Duration = Duration::from_millis(50);
  257
  258pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
  259pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
  260pub(crate) const MINIMAP_FONT_SIZE: AbsoluteLength = AbsoluteLength::Pixels(px(2.));
  261
  262pub type RenderDiffHunkControlsFn = Arc<
  263    dyn Fn(
  264        u32,
  265        &DiffHunkStatus,
  266        Range<Anchor>,
  267        bool,
  268        Pixels,
  269        &Entity<Editor>,
  270        &mut Window,
  271        &mut App,
  272    ) -> AnyElement,
  273>;
  274
  275enum ReportEditorEvent {
  276    Saved { auto_saved: bool },
  277    EditorOpened,
  278    Closed,
  279}
  280
  281impl ReportEditorEvent {
  282    pub fn event_type(&self) -> &'static str {
  283        match self {
  284            Self::Saved { .. } => "Editor Saved",
  285            Self::EditorOpened => "Editor Opened",
  286            Self::Closed => "Editor Closed",
  287        }
  288    }
  289}
  290
  291pub enum ActiveDebugLine {}
  292pub enum DebugStackFrameLine {}
  293
  294pub enum ConflictsOuter {}
  295pub enum ConflictsOurs {}
  296pub enum ConflictsTheirs {}
  297pub enum ConflictsOursMarker {}
  298pub enum ConflictsTheirsMarker {}
  299
  300pub struct HunkAddedColor;
  301pub struct HunkRemovedColor;
  302
  303#[derive(Debug, Copy, Clone, PartialEq, Eq)]
  304pub enum Navigated {
  305    Yes,
  306    No,
  307}
  308
  309impl Navigated {
  310    pub fn from_bool(yes: bool) -> Navigated {
  311        if yes { Navigated::Yes } else { Navigated::No }
  312    }
  313}
  314
  315#[derive(Debug, Clone, PartialEq, Eq)]
  316enum DisplayDiffHunk {
  317    Folded {
  318        display_row: DisplayRow,
  319    },
  320    Unfolded {
  321        is_created_file: bool,
  322        diff_base_byte_range: Range<usize>,
  323        display_row_range: Range<DisplayRow>,
  324        multi_buffer_range: Range<Anchor>,
  325        status: DiffHunkStatus,
  326        word_diffs: Vec<Range<MultiBufferOffset>>,
  327    },
  328}
  329
  330pub enum HideMouseCursorOrigin {
  331    TypingAction,
  332    MovementAction,
  333}
  334
  335pub fn init(cx: &mut App) {
  336    cx.set_global(GlobalBlameRenderer(Arc::new(())));
  337    cx.set_global(breadcrumbs::RenderBreadcrumbText(render_breadcrumb_text));
  338
  339    workspace::register_project_item::<Editor>(cx);
  340    workspace::FollowableViewRegistry::register::<Editor>(cx);
  341    workspace::register_serializable_item::<Editor>(cx);
  342
  343    cx.observe_new(
  344        |workspace: &mut Workspace, _: Option<&mut Window>, _cx: &mut Context<Workspace>| {
  345            workspace.register_action(Editor::new_file);
  346            workspace.register_action(Editor::new_file_split);
  347            workspace.register_action(Editor::new_file_vertical);
  348            workspace.register_action(Editor::new_file_horizontal);
  349            workspace.register_action(Editor::cancel_language_server_work);
  350            workspace.register_action(Editor::toggle_focus);
  351        },
  352    )
  353    .detach();
  354
  355    cx.on_action(move |_: &workspace::NewFile, cx| {
  356        let app_state = workspace::AppState::global(cx);
  357        if let Some(app_state) = app_state.upgrade() {
  358            workspace::open_new(
  359                Default::default(),
  360                app_state,
  361                cx,
  362                |workspace, window, cx| {
  363                    Editor::new_file(workspace, &Default::default(), window, cx)
  364                },
  365            )
  366            .detach_and_log_err(cx);
  367        }
  368    })
  369    .on_action(move |_: &workspace::NewWindow, cx| {
  370        let app_state = workspace::AppState::global(cx);
  371        if let Some(app_state) = app_state.upgrade() {
  372            workspace::open_new(
  373                Default::default(),
  374                app_state,
  375                cx,
  376                |workspace, window, cx| {
  377                    cx.activate(true);
  378                    Editor::new_file(workspace, &Default::default(), window, cx)
  379                },
  380            )
  381            .detach_and_log_err(cx);
  382        }
  383    });
  384    _ = ui_input::ERASED_EDITOR_FACTORY.set(|window, cx| {
  385        Arc::new(ErasedEditorImpl(
  386            cx.new(|cx| Editor::single_line(window, cx)),
  387        )) as Arc<dyn ErasedEditor>
  388    });
  389    _ = multi_buffer::EXCERPT_CONTEXT_LINES.set(multibuffer_context_lines);
  390}
  391
  392pub fn set_blame_renderer(renderer: impl BlameRenderer + 'static, cx: &mut App) {
  393    cx.set_global(GlobalBlameRenderer(Arc::new(renderer)));
  394}
  395
  396pub trait DiagnosticRenderer {
  397    fn render_group(
  398        &self,
  399        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  400        buffer_id: BufferId,
  401        snapshot: EditorSnapshot,
  402        editor: WeakEntity<Editor>,
  403        language_registry: Option<Arc<LanguageRegistry>>,
  404        cx: &mut App,
  405    ) -> Vec<BlockProperties<Anchor>>;
  406
  407    fn render_hover(
  408        &self,
  409        diagnostic_group: Vec<DiagnosticEntryRef<'_, Point>>,
  410        range: Range<Point>,
  411        buffer_id: BufferId,
  412        language_registry: Option<Arc<LanguageRegistry>>,
  413        cx: &mut App,
  414    ) -> Option<Entity<markdown::Markdown>>;
  415
  416    fn open_link(
  417        &self,
  418        editor: &mut Editor,
  419        link: SharedString,
  420        window: &mut Window,
  421        cx: &mut Context<Editor>,
  422    );
  423}
  424
  425pub(crate) struct GlobalDiagnosticRenderer(pub Arc<dyn DiagnosticRenderer>);
  426
  427impl GlobalDiagnosticRenderer {
  428    fn global(cx: &App) -> Option<Arc<dyn DiagnosticRenderer>> {
  429        cx.try_global::<Self>().map(|g| g.0.clone())
  430    }
  431}
  432
  433impl gpui::Global for GlobalDiagnosticRenderer {}
  434pub fn set_diagnostic_renderer(renderer: impl DiagnosticRenderer + 'static, cx: &mut App) {
  435    cx.set_global(GlobalDiagnosticRenderer(Arc::new(renderer)));
  436}
  437
  438pub struct SearchWithinRange;
  439
  440trait InvalidationRegion {
  441    fn ranges(&self) -> &[Range<Anchor>];
  442}
  443
  444#[derive(Clone, Debug, PartialEq)]
  445pub enum SelectPhase {
  446    Begin {
  447        position: DisplayPoint,
  448        add: bool,
  449        click_count: usize,
  450    },
  451    BeginColumnar {
  452        position: DisplayPoint,
  453        reset: bool,
  454        mode: ColumnarMode,
  455        goal_column: u32,
  456    },
  457    Extend {
  458        position: DisplayPoint,
  459        click_count: usize,
  460    },
  461    Update {
  462        position: DisplayPoint,
  463        goal_column: u32,
  464        scroll_delta: gpui::Point<f32>,
  465    },
  466    End,
  467}
  468
  469#[derive(Clone, Debug, PartialEq)]
  470pub enum ColumnarMode {
  471    FromMouse,
  472    FromSelection,
  473}
  474
  475#[derive(Clone, Debug)]
  476pub enum SelectMode {
  477    Character,
  478    Word(Range<Anchor>),
  479    Line(Range<Anchor>),
  480    All,
  481}
  482
  483#[derive(Copy, Clone, Default, PartialEq, Eq, Debug)]
  484pub enum SizingBehavior {
  485    /// The editor will layout itself using `size_full` and will include the vertical
  486    /// scroll margin as requested by user settings.
  487    #[default]
  488    Default,
  489    /// The editor will layout itself using `size_full`, but will not have any
  490    /// vertical overscroll.
  491    ExcludeOverscrollMargin,
  492    /// The editor will request a vertical size according to its content and will be
  493    /// layouted without a vertical scroll margin.
  494    SizeByContent,
  495}
  496
  497#[derive(Clone, PartialEq, Eq, Debug)]
  498pub enum EditorMode {
  499    SingleLine,
  500    AutoHeight {
  501        min_lines: usize,
  502        max_lines: Option<usize>,
  503    },
  504    Full {
  505        /// When set to `true`, the editor will scale its UI elements with the buffer font size.
  506        scale_ui_elements_with_buffer_font_size: bool,
  507        /// When set to `true`, the editor will render a background for the active line.
  508        show_active_line_background: bool,
  509        /// Determines the sizing behavior for this editor
  510        sizing_behavior: SizingBehavior,
  511    },
  512    Minimap {
  513        parent: WeakEntity<Editor>,
  514    },
  515}
  516
  517impl EditorMode {
  518    pub fn full() -> Self {
  519        Self::Full {
  520            scale_ui_elements_with_buffer_font_size: true,
  521            show_active_line_background: true,
  522            sizing_behavior: SizingBehavior::Default,
  523        }
  524    }
  525
  526    #[inline]
  527    pub fn is_full(&self) -> bool {
  528        matches!(self, Self::Full { .. })
  529    }
  530
  531    #[inline]
  532    pub fn is_single_line(&self) -> bool {
  533        matches!(self, Self::SingleLine { .. })
  534    }
  535
  536    #[inline]
  537    fn is_minimap(&self) -> bool {
  538        matches!(self, Self::Minimap { .. })
  539    }
  540}
  541
  542#[derive(Copy, Clone, Debug)]
  543pub enum SoftWrap {
  544    /// Prefer not to wrap at all.
  545    ///
  546    /// Note: this is currently internal, as actually limited by [`crate::MAX_LINE_LEN`] until it wraps.
  547    /// The mode is used inside git diff hunks, where it's seems currently more useful to not wrap as much as possible.
  548    GitDiff,
  549    /// Prefer a single line generally, unless an overly long line is encountered.
  550    None,
  551    /// Soft wrap lines that exceed the editor width.
  552    EditorWidth,
  553    /// Soft wrap lines at the preferred line length.
  554    Column(u32),
  555    /// Soft wrap line at the preferred line length or the editor width (whichever is smaller).
  556    Bounded(u32),
  557}
  558
  559#[derive(Clone)]
  560pub struct EditorStyle {
  561    pub background: Hsla,
  562    pub border: Hsla,
  563    pub local_player: PlayerColor,
  564    pub text: TextStyle,
  565    pub scrollbar_width: Pixels,
  566    pub syntax: Arc<SyntaxTheme>,
  567    pub status: StatusColors,
  568    pub inlay_hints_style: HighlightStyle,
  569    pub edit_prediction_styles: EditPredictionStyles,
  570    pub unnecessary_code_fade: f32,
  571    pub show_underlines: bool,
  572}
  573
  574impl Default for EditorStyle {
  575    fn default() -> Self {
  576        Self {
  577            background: Hsla::default(),
  578            border: Hsla::default(),
  579            local_player: PlayerColor::default(),
  580            text: TextStyle::default(),
  581            scrollbar_width: Pixels::default(),
  582            syntax: Default::default(),
  583            // HACK: Status colors don't have a real default.
  584            // We should look into removing the status colors from the editor
  585            // style and retrieve them directly from the theme.
  586            status: StatusColors::dark(),
  587            inlay_hints_style: HighlightStyle::default(),
  588            edit_prediction_styles: EditPredictionStyles {
  589                insertion: HighlightStyle::default(),
  590                whitespace: HighlightStyle::default(),
  591            },
  592            unnecessary_code_fade: Default::default(),
  593            show_underlines: true,
  594        }
  595    }
  596}
  597
  598pub fn make_inlay_hints_style(cx: &App) -> HighlightStyle {
  599    let show_background = language_settings::language_settings(None, None, cx)
  600        .inlay_hints
  601        .show_background;
  602
  603    let mut style = cx.theme().syntax().get("hint");
  604
  605    if style.color.is_none() {
  606        style.color = Some(cx.theme().status().hint);
  607    }
  608
  609    if !show_background {
  610        style.background_color = None;
  611        return style;
  612    }
  613
  614    if style.background_color.is_none() {
  615        style.background_color = Some(cx.theme().status().hint_background);
  616    }
  617
  618    style
  619}
  620
  621pub fn make_suggestion_styles(cx: &App) -> EditPredictionStyles {
  622    EditPredictionStyles {
  623        insertion: HighlightStyle {
  624            color: Some(cx.theme().status().predictive),
  625            ..HighlightStyle::default()
  626        },
  627        whitespace: HighlightStyle {
  628            background_color: Some(cx.theme().status().created_background),
  629            ..HighlightStyle::default()
  630        },
  631    }
  632}
  633
  634type CompletionId = usize;
  635
  636pub(crate) enum EditDisplayMode {
  637    TabAccept,
  638    DiffPopover,
  639    Inline,
  640}
  641
  642enum EditPrediction {
  643    Edit {
  644        edits: Vec<(Range<Anchor>, Arc<str>)>,
  645        /// Predicted cursor position as (anchor, offset_from_anchor).
  646        /// The anchor is in multibuffer coordinates; after applying edits,
  647        /// resolve the anchor and add the offset to get the final cursor position.
  648        cursor_position: Option<(Anchor, usize)>,
  649        edit_preview: Option<EditPreview>,
  650        display_mode: EditDisplayMode,
  651        snapshot: BufferSnapshot,
  652    },
  653    /// Move to a specific location in the active editor
  654    MoveWithin {
  655        target: Anchor,
  656        snapshot: BufferSnapshot,
  657    },
  658    /// Move to a specific location in a different editor (not the active one)
  659    MoveOutside {
  660        target: language::Anchor,
  661        snapshot: BufferSnapshot,
  662    },
  663}
  664
  665struct EditPredictionState {
  666    inlay_ids: Vec<InlayId>,
  667    completion: EditPrediction,
  668    completion_id: Option<SharedString>,
  669    invalidation_range: Option<Range<Anchor>>,
  670}
  671
  672enum EditPredictionSettings {
  673    Disabled,
  674    Enabled {
  675        show_in_menu: bool,
  676        preview_requires_modifier: bool,
  677    },
  678}
  679
  680#[derive(Debug, Clone)]
  681struct InlineDiagnostic {
  682    message: SharedString,
  683    group_id: usize,
  684    is_primary: bool,
  685    start: Point,
  686    severity: lsp::DiagnosticSeverity,
  687}
  688
  689pub enum MenuEditPredictionsPolicy {
  690    Never,
  691    ByProvider,
  692}
  693
  694pub enum EditPredictionPreview {
  695    /// Modifier is not pressed
  696    Inactive { released_too_fast: bool },
  697    /// Modifier pressed
  698    Active {
  699        since: Instant,
  700        previous_scroll_position: Option<SharedScrollAnchor>,
  701    },
  702}
  703
  704impl EditPredictionPreview {
  705    pub fn released_too_fast(&self) -> bool {
  706        match self {
  707            EditPredictionPreview::Inactive { released_too_fast } => *released_too_fast,
  708            EditPredictionPreview::Active { .. } => false,
  709        }
  710    }
  711
  712    pub fn set_previous_scroll_position(&mut self, scroll_position: Option<SharedScrollAnchor>) {
  713        if let EditPredictionPreview::Active {
  714            previous_scroll_position,
  715            ..
  716        } = self
  717        {
  718            *previous_scroll_position = scroll_position;
  719        }
  720    }
  721}
  722
  723pub struct ContextMenuOptions {
  724    pub min_entries_visible: usize,
  725    pub max_entries_visible: usize,
  726    pub placement: Option<ContextMenuPlacement>,
  727}
  728
  729#[derive(Debug, Clone, PartialEq, Eq)]
  730pub enum ContextMenuPlacement {
  731    Above,
  732    Below,
  733}
  734
  735#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Debug, Default)]
  736struct EditorActionId(usize);
  737
  738impl EditorActionId {
  739    pub fn post_inc(&mut self) -> Self {
  740        let answer = self.0;
  741
  742        *self = Self(answer + 1);
  743
  744        Self(answer)
  745    }
  746}
  747
  748// type GetFieldEditorTheme = dyn Fn(&theme::Theme) -> theme::FieldEditor;
  749// type OverrideTextStyle = dyn Fn(&EditorStyle) -> Option<HighlightStyle>;
  750
  751type BackgroundHighlight = (
  752    Arc<dyn Fn(&usize, &Theme) -> Hsla + Send + Sync>,
  753    Arc<[Range<Anchor>]>,
  754);
  755type GutterHighlight = (fn(&App) -> Hsla, Vec<Range<Anchor>>);
  756
  757#[derive(Default)]
  758struct ScrollbarMarkerState {
  759    scrollbar_size: Size<Pixels>,
  760    dirty: bool,
  761    markers: Arc<[PaintQuad]>,
  762    pending_refresh: Option<Task<Result<()>>>,
  763}
  764
  765impl ScrollbarMarkerState {
  766    fn should_refresh(&self, scrollbar_size: Size<Pixels>) -> bool {
  767        self.pending_refresh.is_none() && (self.scrollbar_size != scrollbar_size || self.dirty)
  768    }
  769}
  770
  771#[derive(Clone, Copy, PartialEq, Eq)]
  772pub enum MinimapVisibility {
  773    Disabled,
  774    Enabled {
  775        /// The configuration currently present in the users settings.
  776        setting_configuration: bool,
  777        /// Whether to override the currently set visibility from the users setting.
  778        toggle_override: bool,
  779    },
  780}
  781
  782impl MinimapVisibility {
  783    fn for_mode(mode: &EditorMode, cx: &App) -> Self {
  784        if mode.is_full() {
  785            Self::Enabled {
  786                setting_configuration: EditorSettings::get_global(cx).minimap.minimap_enabled(),
  787                toggle_override: false,
  788            }
  789        } else {
  790            Self::Disabled
  791        }
  792    }
  793
  794    fn hidden(&self) -> Self {
  795        match *self {
  796            Self::Enabled {
  797                setting_configuration,
  798                ..
  799            } => Self::Enabled {
  800                setting_configuration,
  801                toggle_override: setting_configuration,
  802            },
  803            Self::Disabled => Self::Disabled,
  804        }
  805    }
  806
  807    fn disabled(&self) -> bool {
  808        matches!(*self, Self::Disabled)
  809    }
  810
  811    fn settings_visibility(&self) -> bool {
  812        match *self {
  813            Self::Enabled {
  814                setting_configuration,
  815                ..
  816            } => setting_configuration,
  817            _ => false,
  818        }
  819    }
  820
  821    fn visible(&self) -> bool {
  822        match *self {
  823            Self::Enabled {
  824                setting_configuration,
  825                toggle_override,
  826            } => setting_configuration ^ toggle_override,
  827            _ => false,
  828        }
  829    }
  830
  831    fn toggle_visibility(&self) -> Self {
  832        match *self {
  833            Self::Enabled {
  834                toggle_override,
  835                setting_configuration,
  836            } => Self::Enabled {
  837                setting_configuration,
  838                toggle_override: !toggle_override,
  839            },
  840            Self::Disabled => Self::Disabled,
  841        }
  842    }
  843}
  844
  845#[derive(Debug, Clone, Copy, PartialEq, Eq)]
  846pub enum BufferSerialization {
  847    All,
  848    NonDirtyBuffers,
  849}
  850
  851impl BufferSerialization {
  852    fn new(restore_unsaved_buffers: bool) -> Self {
  853        if restore_unsaved_buffers {
  854            Self::All
  855        } else {
  856            Self::NonDirtyBuffers
  857        }
  858    }
  859}
  860
  861/// Addons allow storing per-editor state in other crates (e.g. Vim)
  862pub trait Addon: 'static {
  863    fn extend_key_context(&self, _: &mut KeyContext, _: &App) {}
  864
  865    fn render_buffer_header_controls(
  866        &self,
  867        _: &ExcerptInfo,
  868        _: &Window,
  869        _: &App,
  870    ) -> Option<AnyElement> {
  871        None
  872    }
  873
  874    fn override_status_for_buffer_id(&self, _: BufferId, _: &App) -> Option<FileStatus> {
  875        None
  876    }
  877
  878    fn to_any(&self) -> &dyn std::any::Any;
  879
  880    fn to_any_mut(&mut self) -> Option<&mut dyn std::any::Any> {
  881        None
  882    }
  883}
  884
  885struct ChangeLocation {
  886    current: Option<Vec<Anchor>>,
  887    original: Vec<Anchor>,
  888}
  889impl ChangeLocation {
  890    fn locations(&self) -> &[Anchor] {
  891        self.current.as_ref().unwrap_or(&self.original)
  892    }
  893}
  894
  895/// A set of caret positions, registered when the editor was edited.
  896pub struct ChangeList {
  897    changes: Vec<ChangeLocation>,
  898    /// Currently "selected" change.
  899    position: Option<usize>,
  900}
  901
  902impl ChangeList {
  903    pub fn new() -> Self {
  904        Self {
  905            changes: Vec::new(),
  906            position: None,
  907        }
  908    }
  909
  910    /// Moves to the next change in the list (based on the direction given) and returns the caret positions for the next change.
  911    /// If reaches the end of the list in the direction, returns the corresponding change until called for a different direction.
  912    pub fn next_change(&mut self, count: usize, direction: Direction) -> Option<&[Anchor]> {
  913        if self.changes.is_empty() {
  914            return None;
  915        }
  916
  917        let prev = self.position.unwrap_or(self.changes.len());
  918        let next = if direction == Direction::Prev {
  919            prev.saturating_sub(count)
  920        } else {
  921            (prev + count).min(self.changes.len() - 1)
  922        };
  923        self.position = Some(next);
  924        self.changes.get(next).map(|change| change.locations())
  925    }
  926
  927    /// Adds a new change to the list, resetting the change list position.
  928    pub fn push_to_change_list(&mut self, group: bool, new_positions: Vec<Anchor>) {
  929        self.position.take();
  930        if let Some(last) = self.changes.last_mut()
  931            && group
  932        {
  933            last.current = Some(new_positions)
  934        } else {
  935            self.changes.push(ChangeLocation {
  936                original: new_positions,
  937                current: None,
  938            });
  939        }
  940    }
  941
  942    pub fn last(&self) -> Option<&[Anchor]> {
  943        self.changes.last().map(|change| change.locations())
  944    }
  945
  946    pub fn last_before_grouping(&self) -> Option<&[Anchor]> {
  947        self.changes.last().map(|change| change.original.as_slice())
  948    }
  949
  950    pub fn invert_last_group(&mut self) {
  951        if let Some(last) = self.changes.last_mut()
  952            && let Some(current) = last.current.as_mut()
  953        {
  954            mem::swap(&mut last.original, current);
  955        }
  956    }
  957}
  958
  959#[derive(Clone)]
  960struct InlineBlamePopoverState {
  961    scroll_handle: ScrollHandle,
  962    commit_message: Option<ParsedCommitMessage>,
  963    markdown: Entity<Markdown>,
  964}
  965
  966struct InlineBlamePopover {
  967    position: gpui::Point<Pixels>,
  968    hide_task: Option<Task<()>>,
  969    popover_bounds: Option<Bounds<Pixels>>,
  970    popover_state: InlineBlamePopoverState,
  971    keyboard_grace: bool,
  972}
  973
  974enum SelectionDragState {
  975    /// State when no drag related activity is detected.
  976    None,
  977    /// State when the mouse is down on a selection that is about to be dragged.
  978    ReadyToDrag {
  979        selection: Selection<Anchor>,
  980        click_position: gpui::Point<Pixels>,
  981        mouse_down_time: Instant,
  982    },
  983    /// State when the mouse is dragging the selection in the editor.
  984    Dragging {
  985        selection: Selection<Anchor>,
  986        drop_cursor: Selection<Anchor>,
  987        hide_drop_cursor: bool,
  988    },
  989}
  990
  991enum ColumnarSelectionState {
  992    FromMouse {
  993        selection_tail: Anchor,
  994        display_point: Option<DisplayPoint>,
  995    },
  996    FromSelection {
  997        selection_tail: Anchor,
  998    },
  999}
 1000
 1001/// Represents a breakpoint indicator that shows up when hovering over lines in the gutter that don't have
 1002/// a breakpoint on them.
 1003#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1004struct PhantomBreakpointIndicator {
 1005    display_row: DisplayRow,
 1006    /// There's a small debounce between hovering over the line and showing the indicator.
 1007    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1008    is_active: bool,
 1009    collides_with_existing_breakpoint: bool,
 1010}
 1011
 1012/// Represents a diff review button indicator that shows up when hovering over lines in the gutter
 1013/// in diff view mode.
 1014#[derive(Clone, Copy, Debug, PartialEq, Eq)]
 1015pub(crate) struct PhantomDiffReviewIndicator {
 1016    /// The starting anchor of the selection (or the only row if not dragging).
 1017    pub start: Anchor,
 1018    /// The ending anchor of the selection. Equal to start_anchor for single-line selection.
 1019    pub end: Anchor,
 1020    /// There's a small debounce between hovering over the line and showing the indicator.
 1021    /// We don't want to show the indicator when moving the mouse from editor to e.g. project panel.
 1022    pub is_active: bool,
 1023}
 1024
 1025#[derive(Clone, Debug)]
 1026pub(crate) struct DiffReviewDragState {
 1027    pub start_anchor: Anchor,
 1028    pub current_anchor: Anchor,
 1029}
 1030
 1031impl DiffReviewDragState {
 1032    pub fn row_range(&self, snapshot: &DisplaySnapshot) -> std::ops::RangeInclusive<DisplayRow> {
 1033        let start = self.start_anchor.to_display_point(snapshot).row();
 1034        let current = self.current_anchor.to_display_point(snapshot).row();
 1035
 1036        (start..=current).sorted()
 1037    }
 1038}
 1039
 1040/// Identifies a specific hunk in the diff buffer.
 1041/// Used as a key to group comments by their location.
 1042#[derive(Clone, Debug)]
 1043pub struct DiffHunkKey {
 1044    /// The file path (relative to worktree) this hunk belongs to.
 1045    pub file_path: Arc<util::rel_path::RelPath>,
 1046    /// An anchor at the start of the hunk. This tracks position as the buffer changes.
 1047    pub hunk_start_anchor: Anchor,
 1048}
 1049
 1050/// A review comment stored locally before being sent to the Agent panel.
 1051#[derive(Clone)]
 1052pub struct StoredReviewComment {
 1053    /// Unique identifier for this comment (for edit/delete operations).
 1054    pub id: usize,
 1055    /// The comment text entered by the user.
 1056    pub comment: String,
 1057    /// Anchors for the code range being reviewed.
 1058    pub range: Range<Anchor>,
 1059    /// Timestamp when the comment was created (for chronological ordering).
 1060    pub created_at: Instant,
 1061    /// Whether this comment is currently being edited inline.
 1062    pub is_editing: bool,
 1063}
 1064
 1065impl StoredReviewComment {
 1066    pub fn new(id: usize, comment: String, anchor_range: Range<Anchor>) -> Self {
 1067        Self {
 1068            id,
 1069            comment,
 1070            range: anchor_range,
 1071            created_at: Instant::now(),
 1072            is_editing: false,
 1073        }
 1074    }
 1075}
 1076
 1077/// Represents an active diff review overlay that appears when clicking the "Add Review" button.
 1078pub(crate) struct DiffReviewOverlay {
 1079    pub anchor_range: Range<Anchor>,
 1080    /// The block ID for the overlay.
 1081    pub block_id: CustomBlockId,
 1082    /// The editor entity for the review input.
 1083    pub prompt_editor: Entity<Editor>,
 1084    /// The hunk key this overlay belongs to.
 1085    pub hunk_key: DiffHunkKey,
 1086    /// Whether the comments section is expanded.
 1087    pub comments_expanded: bool,
 1088    /// Editors for comments currently being edited inline.
 1089    /// Key: comment ID, Value: Editor entity for inline editing.
 1090    pub inline_edit_editors: HashMap<usize, Entity<Editor>>,
 1091    /// Subscriptions for inline edit editors' action handlers.
 1092    /// Key: comment ID, Value: Subscription keeping the Newline action handler alive.
 1093    pub inline_edit_subscriptions: HashMap<usize, Subscription>,
 1094    /// The current user's avatar URI for display in comment rows.
 1095    pub user_avatar_uri: Option<SharedUri>,
 1096    /// Subscription to keep the action handler alive.
 1097    _subscription: Subscription,
 1098}
 1099
 1100/// Zed's primary implementation of text input, allowing users to edit a [`MultiBuffer`].
 1101///
 1102/// See the [module level documentation](self) for more information.
 1103pub struct Editor {
 1104    focus_handle: FocusHandle,
 1105    last_focused_descendant: Option<WeakFocusHandle>,
 1106    /// The text buffer being edited
 1107    buffer: Entity<MultiBuffer>,
 1108    /// Map of how text in the buffer should be displayed.
 1109    /// Handles soft wraps, folds, fake inlay text insertions, etc.
 1110    pub display_map: Entity<DisplayMap>,
 1111    placeholder_display_map: Option<Entity<DisplayMap>>,
 1112    pub selections: SelectionsCollection,
 1113    pub scroll_manager: ScrollManager,
 1114    /// When inline assist editors are linked, they all render cursors because
 1115    /// typing enters text into each of them, even the ones that aren't focused.
 1116    pub(crate) show_cursor_when_unfocused: bool,
 1117    columnar_selection_state: Option<ColumnarSelectionState>,
 1118    add_selections_state: Option<AddSelectionsState>,
 1119    select_next_state: Option<SelectNextState>,
 1120    select_prev_state: Option<SelectNextState>,
 1121    selection_history: SelectionHistory,
 1122    defer_selection_effects: bool,
 1123    deferred_selection_effects_state: Option<DeferredSelectionEffectsState>,
 1124    autoclose_regions: Vec<AutocloseRegion>,
 1125    snippet_stack: InvalidationStack<SnippetState>,
 1126    select_syntax_node_history: SelectSyntaxNodeHistory,
 1127    ime_transaction: Option<TransactionId>,
 1128    pub diagnostics_max_severity: DiagnosticSeverity,
 1129    active_diagnostics: ActiveDiagnostic,
 1130    show_inline_diagnostics: bool,
 1131    inline_diagnostics_update: Task<()>,
 1132    inline_diagnostics_enabled: bool,
 1133    diagnostics_enabled: bool,
 1134    word_completions_enabled: bool,
 1135    inline_diagnostics: Vec<(Anchor, InlineDiagnostic)>,
 1136    soft_wrap_mode_override: Option<language_settings::SoftWrap>,
 1137    hard_wrap: Option<usize>,
 1138    project: Option<Entity<Project>>,
 1139    semantics_provider: Option<Rc<dyn SemanticsProvider>>,
 1140    completion_provider: Option<Rc<dyn CompletionProvider>>,
 1141    collaboration_hub: Option<Box<dyn CollaborationHub>>,
 1142    blink_manager: Entity<BlinkManager>,
 1143    show_cursor_names: bool,
 1144    hovered_cursors: HashMap<HoveredCursor, Task<()>>,
 1145    pub show_local_selections: bool,
 1146    mode: EditorMode,
 1147    show_breadcrumbs: bool,
 1148    show_gutter: bool,
 1149    show_scrollbars: ScrollbarAxes,
 1150    minimap_visibility: MinimapVisibility,
 1151    offset_content: bool,
 1152    disable_expand_excerpt_buttons: bool,
 1153    delegate_expand_excerpts: bool,
 1154    delegate_stage_and_restore: bool,
 1155    delegate_open_excerpts: bool,
 1156    enable_lsp_data: bool,
 1157    enable_runnables: bool,
 1158    show_line_numbers: Option<bool>,
 1159    use_relative_line_numbers: Option<bool>,
 1160    show_git_diff_gutter: Option<bool>,
 1161    show_code_actions: Option<bool>,
 1162    show_runnables: Option<bool>,
 1163    show_breakpoints: Option<bool>,
 1164    show_diff_review_button: bool,
 1165    show_wrap_guides: Option<bool>,
 1166    show_indent_guides: Option<bool>,
 1167    buffers_with_disabled_indent_guides: HashSet<BufferId>,
 1168    highlight_order: usize,
 1169    highlighted_rows: HashMap<TypeId, Vec<RowHighlight>>,
 1170    background_highlights: HashMap<HighlightKey, BackgroundHighlight>,
 1171    gutter_highlights: HashMap<TypeId, GutterHighlight>,
 1172    scrollbar_marker_state: ScrollbarMarkerState,
 1173    active_indent_guides_state: ActiveIndentGuidesState,
 1174    nav_history: Option<ItemNavHistory>,
 1175    context_menu: RefCell<Option<CodeContextMenu>>,
 1176    context_menu_options: Option<ContextMenuOptions>,
 1177    mouse_context_menu: Option<MouseContextMenu>,
 1178    completion_tasks: Vec<(CompletionId, Task<()>)>,
 1179    inline_blame_popover: Option<InlineBlamePopover>,
 1180    inline_blame_popover_show_task: Option<Task<()>>,
 1181    signature_help_state: SignatureHelpState,
 1182    auto_signature_help: Option<bool>,
 1183    find_all_references_task_sources: Vec<Anchor>,
 1184    next_completion_id: CompletionId,
 1185    available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
 1186    code_actions_task: Option<Task<Result<()>>>,
 1187    quick_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1188    debounced_selection_highlight_task: Option<(Range<Anchor>, Task<()>)>,
 1189    debounced_selection_highlight_complete: bool,
 1190    document_highlights_task: Option<Task<()>>,
 1191    linked_editing_range_task: Option<Task<Option<()>>>,
 1192    linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
 1193    pending_rename: Option<RenameState>,
 1194    searchable: bool,
 1195    cursor_shape: CursorShape,
 1196    /// Whether the cursor is offset one character to the left when something is
 1197    /// selected (needed for vim visual mode)
 1198    cursor_offset_on_selection: bool,
 1199    current_line_highlight: Option<CurrentLineHighlight>,
 1200    /// Whether to collapse search match ranges to just their start position.
 1201    /// When true, navigating to a match positions the cursor at the match
 1202    /// without selecting the matched text.
 1203    collapse_matches: bool,
 1204    autoindent_mode: Option<AutoindentMode>,
 1205    workspace: Option<(WeakEntity<Workspace>, Option<WorkspaceId>)>,
 1206    input_enabled: bool,
 1207    expects_character_input: bool,
 1208    use_modal_editing: bool,
 1209    read_only: bool,
 1210    leader_id: Option<CollaboratorId>,
 1211    remote_id: Option<ViewId>,
 1212    pub hover_state: HoverState,
 1213    pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
 1214    prev_pressure_stage: Option<PressureStage>,
 1215    gutter_hovered: bool,
 1216    hovered_link_state: Option<HoveredLinkState>,
 1217    edit_prediction_provider: Option<RegisteredEditPredictionDelegate>,
 1218    code_action_providers: Vec<Rc<dyn CodeActionProvider>>,
 1219    active_edit_prediction: Option<EditPredictionState>,
 1220    /// Used to prevent flickering as the user types while the menu is open
 1221    stale_edit_prediction_in_menu: Option<EditPredictionState>,
 1222    edit_prediction_settings: EditPredictionSettings,
 1223    edit_predictions_hidden_for_vim_mode: bool,
 1224    show_edit_predictions_override: Option<bool>,
 1225    show_completions_on_input_override: Option<bool>,
 1226    menu_edit_predictions_policy: MenuEditPredictionsPolicy,
 1227    edit_prediction_preview: EditPredictionPreview,
 1228    edit_prediction_indent_conflict: bool,
 1229    edit_prediction_requires_modifier_in_indent_conflict: bool,
 1230    next_inlay_id: usize,
 1231    next_color_inlay_id: usize,
 1232    _subscriptions: Vec<Subscription>,
 1233    pixel_position_of_newest_cursor: Option<gpui::Point<Pixels>>,
 1234    gutter_dimensions: GutterDimensions,
 1235    style: Option<EditorStyle>,
 1236    text_style_refinement: Option<TextStyleRefinement>,
 1237    next_editor_action_id: EditorActionId,
 1238    editor_actions: Rc<
 1239        RefCell<BTreeMap<EditorActionId, Box<dyn Fn(&Editor, &mut Window, &mut Context<Self>)>>>,
 1240    >,
 1241    use_autoclose: bool,
 1242    use_auto_surround: bool,
 1243    auto_replace_emoji_shortcode: bool,
 1244    jsx_tag_auto_close_enabled_in_any_buffer: bool,
 1245    show_git_blame_gutter: bool,
 1246    show_git_blame_inline: bool,
 1247    show_git_blame_inline_delay_task: Option<Task<()>>,
 1248    git_blame_inline_enabled: bool,
 1249    render_diff_hunk_controls: RenderDiffHunkControlsFn,
 1250    buffer_serialization: Option<BufferSerialization>,
 1251    show_selection_menu: Option<bool>,
 1252    blame: Option<Entity<GitBlame>>,
 1253    blame_subscription: Option<Subscription>,
 1254    custom_context_menu: Option<
 1255        Box<
 1256            dyn 'static
 1257                + Fn(
 1258                    &mut Self,
 1259                    DisplayPoint,
 1260                    &mut Window,
 1261                    &mut Context<Self>,
 1262                ) -> Option<Entity<ui::ContextMenu>>,
 1263        >,
 1264    >,
 1265    last_bounds: Option<Bounds<Pixels>>,
 1266    last_position_map: Option<Rc<PositionMap>>,
 1267    expect_bounds_change: Option<Bounds<Pixels>>,
 1268    runnables: RunnableData,
 1269    breakpoint_store: Option<Entity<BreakpointStore>>,
 1270    gutter_breakpoint_indicator: (Option<PhantomBreakpointIndicator>, Option<Task<()>>),
 1271    pub(crate) gutter_diff_review_indicator: (Option<PhantomDiffReviewIndicator>, Option<Task<()>>),
 1272    pub(crate) diff_review_drag_state: Option<DiffReviewDragState>,
 1273    /// Active diff review overlays. Multiple overlays can be open simultaneously
 1274    /// when hunks have comments stored.
 1275    pub(crate) diff_review_overlays: Vec<DiffReviewOverlay>,
 1276    /// Stored review comments grouped by hunk.
 1277    /// Uses a Vec instead of HashMap because DiffHunkKey contains an Anchor
 1278    /// which doesn't implement Hash/Eq in a way suitable for HashMap keys.
 1279    stored_review_comments: Vec<(DiffHunkKey, Vec<StoredReviewComment>)>,
 1280    /// Counter for generating unique comment IDs.
 1281    next_review_comment_id: usize,
 1282    hovered_diff_hunk_row: Option<DisplayRow>,
 1283    pull_diagnostics_task: Task<()>,
 1284    in_project_search: bool,
 1285    previous_search_ranges: Option<Arc<[Range<Anchor>]>>,
 1286    breadcrumb_header: Option<String>,
 1287    focused_block: Option<FocusedBlock>,
 1288    next_scroll_position: NextScrollCursorCenterTopBottom,
 1289    addons: HashMap<TypeId, Box<dyn Addon>>,
 1290    registered_buffers: HashMap<BufferId, OpenLspBufferHandle>,
 1291    load_diff_task: Option<Shared<Task<()>>>,
 1292    /// Whether we are temporarily displaying a diff other than git's
 1293    temporary_diff_override: bool,
 1294    selection_mark_mode: bool,
 1295    toggle_fold_multiple_buffers: Task<()>,
 1296    _scroll_cursor_center_top_bottom_task: Task<()>,
 1297    serialize_selections: Task<()>,
 1298    serialize_folds: Task<()>,
 1299    mouse_cursor_hidden: bool,
 1300    minimap: Option<Entity<Self>>,
 1301    hide_mouse_mode: HideMouseMode,
 1302    pub change_list: ChangeList,
 1303    inline_value_cache: InlineValueCache,
 1304    number_deleted_lines: bool,
 1305
 1306    selection_drag_state: SelectionDragState,
 1307    colors: Option<LspColorData>,
 1308    post_scroll_update: Task<()>,
 1309    refresh_colors_task: Task<()>,
 1310    use_document_folding_ranges: bool,
 1311    refresh_folding_ranges_task: Task<()>,
 1312    inlay_hints: Option<LspInlayHintData>,
 1313    folding_newlines: Task<()>,
 1314    select_next_is_case_sensitive: Option<bool>,
 1315    pub lookup_key: Option<Box<dyn Any + Send + Sync>>,
 1316    on_local_selections_changed:
 1317        Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
 1318    suppress_selection_callback: bool,
 1319    applicable_language_settings: HashMap<Option<LanguageName>, LanguageSettings>,
 1320    accent_data: Option<AccentData>,
 1321    bracket_fetched_tree_sitter_chunks: HashMap<ExcerptId, HashSet<Range<BufferRow>>>,
 1322    semantic_token_state: SemanticTokenState,
 1323    pub(crate) refresh_matching_bracket_highlights_task: Task<()>,
 1324    refresh_document_symbols_task: Shared<Task<()>>,
 1325    lsp_document_symbols: HashMap<BufferId, Vec<OutlineItem<text::Anchor>>>,
 1326    refresh_outline_symbols_at_cursor_at_cursor_task: Task<()>,
 1327    outline_symbols_at_cursor: Option<(BufferId, Vec<OutlineItem<Anchor>>)>,
 1328    sticky_headers_task: Task<()>,
 1329    sticky_headers: Option<Vec<OutlineItem<Anchor>>>,
 1330    pub(crate) colorize_brackets_task: Task<()>,
 1331}
 1332
 1333#[derive(Debug, PartialEq)]
 1334struct AccentData {
 1335    colors: AccentColors,
 1336    overrides: Vec<SharedString>,
 1337}
 1338
 1339fn debounce_value(debounce_ms: u64) -> Option<Duration> {
 1340    if debounce_ms > 0 {
 1341        Some(Duration::from_millis(debounce_ms))
 1342    } else {
 1343        None
 1344    }
 1345}
 1346
 1347#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
 1348enum NextScrollCursorCenterTopBottom {
 1349    #[default]
 1350    Center,
 1351    Top,
 1352    Bottom,
 1353}
 1354
 1355impl NextScrollCursorCenterTopBottom {
 1356    fn next(&self) -> Self {
 1357        match self {
 1358            Self::Center => Self::Top,
 1359            Self::Top => Self::Bottom,
 1360            Self::Bottom => Self::Center,
 1361        }
 1362    }
 1363}
 1364
 1365#[derive(Clone)]
 1366pub struct EditorSnapshot {
 1367    pub mode: EditorMode,
 1368    show_gutter: bool,
 1369    offset_content: bool,
 1370    show_line_numbers: Option<bool>,
 1371    number_deleted_lines: bool,
 1372    show_git_diff_gutter: Option<bool>,
 1373    show_code_actions: Option<bool>,
 1374    show_runnables: Option<bool>,
 1375    show_breakpoints: Option<bool>,
 1376    git_blame_gutter_max_author_length: Option<usize>,
 1377    pub display_snapshot: DisplaySnapshot,
 1378    pub placeholder_display_snapshot: Option<DisplaySnapshot>,
 1379    is_focused: bool,
 1380    scroll_anchor: SharedScrollAnchor,
 1381    ongoing_scroll: OngoingScroll,
 1382    current_line_highlight: CurrentLineHighlight,
 1383    gutter_hovered: bool,
 1384    semantic_tokens_enabled: bool,
 1385}
 1386
 1387#[derive(Default, Debug, Clone, Copy)]
 1388pub struct GutterDimensions {
 1389    pub left_padding: Pixels,
 1390    pub right_padding: Pixels,
 1391    pub width: Pixels,
 1392    pub margin: Pixels,
 1393    pub git_blame_entries_width: Option<Pixels>,
 1394}
 1395
 1396impl GutterDimensions {
 1397    fn default_with_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Self {
 1398        Self {
 1399            margin: Self::default_gutter_margin(font_id, font_size, cx),
 1400            ..Default::default()
 1401        }
 1402    }
 1403
 1404    fn default_gutter_margin(font_id: FontId, font_size: Pixels, cx: &App) -> Pixels {
 1405        -cx.text_system().descent(font_id, font_size)
 1406    }
 1407    /// The full width of the space taken up by the gutter.
 1408    pub fn full_width(&self) -> Pixels {
 1409        self.margin + self.width
 1410    }
 1411
 1412    /// The width of the space reserved for the fold indicators,
 1413    /// use alongside 'justify_end' and `gutter_width` to
 1414    /// right align content with the line numbers
 1415    pub fn fold_area_width(&self) -> Pixels {
 1416        self.margin + self.right_padding
 1417    }
 1418}
 1419
 1420struct CharacterDimensions {
 1421    em_width: Pixels,
 1422    em_advance: Pixels,
 1423    line_height: Pixels,
 1424}
 1425
 1426#[derive(Debug)]
 1427pub struct RemoteSelection {
 1428    pub replica_id: ReplicaId,
 1429    pub selection: Selection<Anchor>,
 1430    pub cursor_shape: CursorShape,
 1431    pub collaborator_id: CollaboratorId,
 1432    pub line_mode: bool,
 1433    pub user_name: Option<SharedString>,
 1434    pub color: PlayerColor,
 1435}
 1436
 1437#[derive(Clone, Debug)]
 1438struct SelectionHistoryEntry {
 1439    selections: Arc<[Selection<Anchor>]>,
 1440    select_next_state: Option<SelectNextState>,
 1441    select_prev_state: Option<SelectNextState>,
 1442    add_selections_state: Option<AddSelectionsState>,
 1443}
 1444
 1445#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
 1446enum SelectionHistoryMode {
 1447    #[default]
 1448    Normal,
 1449    Undoing,
 1450    Redoing,
 1451    Skipping,
 1452}
 1453
 1454#[derive(Clone, PartialEq, Eq, Hash)]
 1455struct HoveredCursor {
 1456    replica_id: ReplicaId,
 1457    selection_id: usize,
 1458}
 1459
 1460#[derive(Debug)]
 1461/// SelectionEffects controls the side-effects of updating the selection.
 1462///
 1463/// The default behaviour does "what you mostly want":
 1464/// - it pushes to the nav history if the cursor moved by >10 lines
 1465/// - it re-triggers completion requests
 1466/// - it scrolls to fit
 1467///
 1468/// You might want to modify these behaviours. For example when doing a "jump"
 1469/// like go to definition, we always want to add to nav history; but when scrolling
 1470/// in vim mode we never do.
 1471///
 1472/// Similarly, you might want to disable scrolling if you don't want the viewport to
 1473/// move.
 1474#[derive(Clone)]
 1475pub struct SelectionEffects {
 1476    nav_history: Option<bool>,
 1477    completions: bool,
 1478    scroll: Option<Autoscroll>,
 1479}
 1480
 1481impl Default for SelectionEffects {
 1482    fn default() -> Self {
 1483        Self {
 1484            nav_history: None,
 1485            completions: true,
 1486            scroll: Some(Autoscroll::fit()),
 1487        }
 1488    }
 1489}
 1490impl SelectionEffects {
 1491    pub fn scroll(scroll: Autoscroll) -> Self {
 1492        Self {
 1493            scroll: Some(scroll),
 1494            ..Default::default()
 1495        }
 1496    }
 1497
 1498    pub fn no_scroll() -> Self {
 1499        Self {
 1500            scroll: None,
 1501            ..Default::default()
 1502        }
 1503    }
 1504
 1505    pub fn completions(self, completions: bool) -> Self {
 1506        Self {
 1507            completions,
 1508            ..self
 1509        }
 1510    }
 1511
 1512    pub fn nav_history(self, nav_history: bool) -> Self {
 1513        Self {
 1514            nav_history: Some(nav_history),
 1515            ..self
 1516        }
 1517    }
 1518}
 1519
 1520struct DeferredSelectionEffectsState {
 1521    changed: bool,
 1522    effects: SelectionEffects,
 1523    old_cursor_position: Anchor,
 1524    history_entry: SelectionHistoryEntry,
 1525}
 1526
 1527#[derive(Default)]
 1528struct SelectionHistory {
 1529    #[allow(clippy::type_complexity)]
 1530    selections_by_transaction:
 1531        HashMap<TransactionId, (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)>,
 1532    mode: SelectionHistoryMode,
 1533    undo_stack: VecDeque<SelectionHistoryEntry>,
 1534    redo_stack: VecDeque<SelectionHistoryEntry>,
 1535}
 1536
 1537impl SelectionHistory {
 1538    #[track_caller]
 1539    fn insert_transaction(
 1540        &mut self,
 1541        transaction_id: TransactionId,
 1542        selections: Arc<[Selection<Anchor>]>,
 1543    ) {
 1544        if selections.is_empty() {
 1545            log::error!(
 1546                "SelectionHistory::insert_transaction called with empty selections. Caller: {}",
 1547                std::panic::Location::caller()
 1548            );
 1549            return;
 1550        }
 1551        self.selections_by_transaction
 1552            .insert(transaction_id, (selections, None));
 1553    }
 1554
 1555    #[allow(clippy::type_complexity)]
 1556    fn transaction(
 1557        &self,
 1558        transaction_id: TransactionId,
 1559    ) -> Option<&(Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1560        self.selections_by_transaction.get(&transaction_id)
 1561    }
 1562
 1563    #[allow(clippy::type_complexity)]
 1564    fn transaction_mut(
 1565        &mut self,
 1566        transaction_id: TransactionId,
 1567    ) -> Option<&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)> {
 1568        self.selections_by_transaction.get_mut(&transaction_id)
 1569    }
 1570
 1571    fn push(&mut self, entry: SelectionHistoryEntry) {
 1572        if !entry.selections.is_empty() {
 1573            match self.mode {
 1574                SelectionHistoryMode::Normal => {
 1575                    self.push_undo(entry);
 1576                    self.redo_stack.clear();
 1577                }
 1578                SelectionHistoryMode::Undoing => self.push_redo(entry),
 1579                SelectionHistoryMode::Redoing => self.push_undo(entry),
 1580                SelectionHistoryMode::Skipping => {}
 1581            }
 1582        }
 1583    }
 1584
 1585    fn push_undo(&mut self, entry: SelectionHistoryEntry) {
 1586        if self
 1587            .undo_stack
 1588            .back()
 1589            .is_none_or(|e| e.selections != entry.selections)
 1590        {
 1591            self.undo_stack.push_back(entry);
 1592            if self.undo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1593                self.undo_stack.pop_front();
 1594            }
 1595        }
 1596    }
 1597
 1598    fn push_redo(&mut self, entry: SelectionHistoryEntry) {
 1599        if self
 1600            .redo_stack
 1601            .back()
 1602            .is_none_or(|e| e.selections != entry.selections)
 1603        {
 1604            self.redo_stack.push_back(entry);
 1605            if self.redo_stack.len() > MAX_SELECTION_HISTORY_LEN {
 1606                self.redo_stack.pop_front();
 1607            }
 1608        }
 1609    }
 1610}
 1611
 1612#[derive(Clone, Copy)]
 1613pub struct RowHighlightOptions {
 1614    pub autoscroll: bool,
 1615    pub include_gutter: bool,
 1616}
 1617
 1618impl Default for RowHighlightOptions {
 1619    fn default() -> Self {
 1620        Self {
 1621            autoscroll: Default::default(),
 1622            include_gutter: true,
 1623        }
 1624    }
 1625}
 1626
 1627struct RowHighlight {
 1628    index: usize,
 1629    range: Range<Anchor>,
 1630    color: Hsla,
 1631    options: RowHighlightOptions,
 1632    type_id: TypeId,
 1633}
 1634
 1635#[derive(Clone, Debug)]
 1636struct AddSelectionsState {
 1637    groups: Vec<AddSelectionsGroup>,
 1638}
 1639
 1640#[derive(Clone, Debug)]
 1641struct AddSelectionsGroup {
 1642    above: bool,
 1643    stack: Vec<usize>,
 1644}
 1645
 1646#[derive(Clone)]
 1647struct SelectNextState {
 1648    query: AhoCorasick,
 1649    wordwise: bool,
 1650    done: bool,
 1651}
 1652
 1653impl std::fmt::Debug for SelectNextState {
 1654    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
 1655        f.debug_struct(std::any::type_name::<Self>())
 1656            .field("wordwise", &self.wordwise)
 1657            .field("done", &self.done)
 1658            .finish()
 1659    }
 1660}
 1661
 1662#[derive(Debug)]
 1663struct AutocloseRegion {
 1664    selection_id: usize,
 1665    range: Range<Anchor>,
 1666    pair: BracketPair,
 1667}
 1668
 1669#[derive(Debug)]
 1670struct SnippetState {
 1671    ranges: Vec<Vec<Range<Anchor>>>,
 1672    active_index: usize,
 1673    choices: Vec<Option<Vec<String>>>,
 1674}
 1675
 1676#[doc(hidden)]
 1677pub struct RenameState {
 1678    pub range: Range<Anchor>,
 1679    pub old_name: Arc<str>,
 1680    pub editor: Entity<Editor>,
 1681    block_id: CustomBlockId,
 1682}
 1683
 1684struct InvalidationStack<T>(Vec<T>);
 1685
 1686struct RegisteredEditPredictionDelegate {
 1687    provider: Arc<dyn EditPredictionDelegateHandle>,
 1688    _subscription: Subscription,
 1689}
 1690
 1691#[derive(Debug, PartialEq, Eq)]
 1692pub struct ActiveDiagnosticGroup {
 1693    pub active_range: Range<Anchor>,
 1694    pub active_message: String,
 1695    pub group_id: usize,
 1696    pub blocks: HashSet<CustomBlockId>,
 1697}
 1698
 1699#[derive(Debug, PartialEq, Eq)]
 1700
 1701pub(crate) enum ActiveDiagnostic {
 1702    None,
 1703    All,
 1704    Group(ActiveDiagnosticGroup),
 1705}
 1706
 1707#[derive(Serialize, Deserialize, Clone, Debug)]
 1708pub struct ClipboardSelection {
 1709    /// The number of bytes in this selection.
 1710    pub len: usize,
 1711    /// Whether this was a full-line selection.
 1712    pub is_entire_line: bool,
 1713    /// The indentation of the first line when this content was originally copied.
 1714    pub first_line_indent: u32,
 1715    #[serde(default)]
 1716    pub file_path: Option<PathBuf>,
 1717    #[serde(default)]
 1718    pub line_range: Option<RangeInclusive<u32>>,
 1719}
 1720
 1721impl ClipboardSelection {
 1722    pub fn for_buffer(
 1723        len: usize,
 1724        is_entire_line: bool,
 1725        range: Range<Point>,
 1726        buffer: &MultiBufferSnapshot,
 1727        project: Option<&Entity<Project>>,
 1728        cx: &App,
 1729    ) -> Self {
 1730        let first_line_indent = buffer
 1731            .indent_size_for_line(MultiBufferRow(range.start.row))
 1732            .len;
 1733
 1734        let file_path = util::maybe!({
 1735            let project = project?.read(cx);
 1736            let file = buffer.file_at(range.start)?;
 1737            let project_path = ProjectPath {
 1738                worktree_id: file.worktree_id(cx),
 1739                path: file.path().clone(),
 1740            };
 1741            project.absolute_path(&project_path, cx)
 1742        });
 1743
 1744        let line_range = file_path.as_ref().and_then(|_| {
 1745            let (_, start_point, start_excerpt_id) = buffer.point_to_buffer_point(range.start)?;
 1746            let (_, end_point, end_excerpt_id) = buffer.point_to_buffer_point(range.end)?;
 1747            if start_excerpt_id == end_excerpt_id {
 1748                Some(start_point.row..=end_point.row)
 1749            } else {
 1750                None
 1751            }
 1752        });
 1753
 1754        Self {
 1755            len,
 1756            is_entire_line,
 1757            first_line_indent,
 1758            file_path,
 1759            line_range,
 1760        }
 1761    }
 1762}
 1763
 1764// selections, scroll behavior, was newest selection reversed
 1765type SelectSyntaxNodeHistoryState = (
 1766    Box<[Selection<Anchor>]>,
 1767    SelectSyntaxNodeScrollBehavior,
 1768    bool,
 1769);
 1770
 1771#[derive(Default)]
 1772struct SelectSyntaxNodeHistory {
 1773    stack: Vec<SelectSyntaxNodeHistoryState>,
 1774    // disable temporarily to allow changing selections without losing the stack
 1775    pub disable_clearing: bool,
 1776}
 1777
 1778impl SelectSyntaxNodeHistory {
 1779    pub fn try_clear(&mut self) {
 1780        if !self.disable_clearing {
 1781            self.stack.clear();
 1782        }
 1783    }
 1784
 1785    pub fn push(&mut self, selection: SelectSyntaxNodeHistoryState) {
 1786        self.stack.push(selection);
 1787    }
 1788
 1789    pub fn pop(&mut self) -> Option<SelectSyntaxNodeHistoryState> {
 1790        self.stack.pop()
 1791    }
 1792}
 1793
 1794enum SelectSyntaxNodeScrollBehavior {
 1795    CursorTop,
 1796    FitSelection,
 1797    CursorBottom,
 1798}
 1799
 1800#[derive(Debug, Clone, Copy)]
 1801pub(crate) struct NavigationData {
 1802    cursor_anchor: Anchor,
 1803    cursor_position: Point,
 1804    scroll_anchor: ScrollAnchor,
 1805    scroll_top_row: u32,
 1806}
 1807
 1808#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 1809pub enum GotoDefinitionKind {
 1810    Symbol,
 1811    Declaration,
 1812    Type,
 1813    Implementation,
 1814}
 1815
 1816pub enum FormatTarget {
 1817    Buffers(HashSet<Entity<Buffer>>),
 1818    Ranges(Vec<Range<MultiBufferPoint>>),
 1819}
 1820
 1821pub(crate) struct FocusedBlock {
 1822    id: BlockId,
 1823    focus_handle: WeakFocusHandle,
 1824}
 1825
 1826#[derive(Clone, Debug)]
 1827pub enum JumpData {
 1828    MultiBufferRow {
 1829        row: MultiBufferRow,
 1830        line_offset_from_top: u32,
 1831    },
 1832    MultiBufferPoint {
 1833        excerpt_id: ExcerptId,
 1834        position: Point,
 1835        anchor: text::Anchor,
 1836        line_offset_from_top: u32,
 1837    },
 1838}
 1839
 1840pub enum MultibufferSelectionMode {
 1841    First,
 1842    All,
 1843}
 1844
 1845#[derive(Clone, Copy, Debug, Default)]
 1846pub struct RewrapOptions {
 1847    pub override_language_settings: bool,
 1848    pub preserve_existing_whitespace: bool,
 1849}
 1850
 1851impl Editor {
 1852    pub fn single_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1853        let buffer = cx.new(|cx| Buffer::local("", cx));
 1854        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1855        Self::new(EditorMode::SingleLine, buffer, None, window, cx)
 1856    }
 1857
 1858    pub fn multi_line(window: &mut Window, cx: &mut Context<Self>) -> Self {
 1859        let buffer = cx.new(|cx| Buffer::local("", cx));
 1860        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1861        Self::new(EditorMode::full(), buffer, None, window, cx)
 1862    }
 1863
 1864    pub fn auto_height(
 1865        min_lines: usize,
 1866        max_lines: usize,
 1867        window: &mut Window,
 1868        cx: &mut Context<Self>,
 1869    ) -> Self {
 1870        let buffer = cx.new(|cx| Buffer::local("", cx));
 1871        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1872        Self::new(
 1873            EditorMode::AutoHeight {
 1874                min_lines,
 1875                max_lines: Some(max_lines),
 1876            },
 1877            buffer,
 1878            None,
 1879            window,
 1880            cx,
 1881        )
 1882    }
 1883
 1884    /// Creates a new auto-height editor with a minimum number of lines but no maximum.
 1885    /// The editor grows as tall as needed to fit its content.
 1886    pub fn auto_height_unbounded(
 1887        min_lines: usize,
 1888        window: &mut Window,
 1889        cx: &mut Context<Self>,
 1890    ) -> Self {
 1891        let buffer = cx.new(|cx| Buffer::local("", cx));
 1892        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1893        Self::new(
 1894            EditorMode::AutoHeight {
 1895                min_lines,
 1896                max_lines: None,
 1897            },
 1898            buffer,
 1899            None,
 1900            window,
 1901            cx,
 1902        )
 1903    }
 1904
 1905    pub fn for_buffer(
 1906        buffer: Entity<Buffer>,
 1907        project: Option<Entity<Project>>,
 1908        window: &mut Window,
 1909        cx: &mut Context<Self>,
 1910    ) -> Self {
 1911        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
 1912        Self::new(EditorMode::full(), buffer, project, window, cx)
 1913    }
 1914
 1915    pub fn for_multibuffer(
 1916        buffer: Entity<MultiBuffer>,
 1917        project: Option<Entity<Project>>,
 1918        window: &mut Window,
 1919        cx: &mut Context<Self>,
 1920    ) -> Self {
 1921        Self::new(EditorMode::full(), buffer, project, window, cx)
 1922    }
 1923
 1924    pub fn clone(&self, window: &mut Window, cx: &mut Context<Self>) -> Self {
 1925        let mut clone = Self::new(
 1926            self.mode.clone(),
 1927            self.buffer.clone(),
 1928            self.project.clone(),
 1929            window,
 1930            cx,
 1931        );
 1932        let my_snapshot = self.display_map.update(cx, |display_map, cx| {
 1933            let snapshot = display_map.snapshot(cx);
 1934            clone.display_map.update(cx, |display_map, cx| {
 1935                display_map.set_state(&snapshot, cx);
 1936            });
 1937            snapshot
 1938        });
 1939        let clone_snapshot = clone.display_map.update(cx, |map, cx| map.snapshot(cx));
 1940        clone.folds_did_change(cx);
 1941        clone.selections.clone_state(&self.selections);
 1942        clone
 1943            .scroll_manager
 1944            .clone_state(&self.scroll_manager, &my_snapshot, &clone_snapshot, cx);
 1945        clone.searchable = self.searchable;
 1946        clone.read_only = self.read_only;
 1947        clone.buffers_with_disabled_indent_guides =
 1948            self.buffers_with_disabled_indent_guides.clone();
 1949        clone
 1950    }
 1951
 1952    pub fn new(
 1953        mode: EditorMode,
 1954        buffer: Entity<MultiBuffer>,
 1955        project: Option<Entity<Project>>,
 1956        window: &mut Window,
 1957        cx: &mut Context<Self>,
 1958    ) -> Self {
 1959        Editor::new_internal(mode, buffer, project, None, window, cx)
 1960    }
 1961
 1962    pub fn refresh_sticky_headers(
 1963        &mut self,
 1964        display_snapshot: &DisplaySnapshot,
 1965        cx: &mut Context<Editor>,
 1966    ) {
 1967        if !self.mode.is_full() {
 1968            return;
 1969        }
 1970        let multi_buffer = display_snapshot.buffer_snapshot();
 1971        let scroll_anchor = self
 1972            .scroll_manager
 1973            .native_anchor(display_snapshot, cx)
 1974            .anchor;
 1975        let Some((excerpt_id, _, buffer)) = multi_buffer.as_singleton() else {
 1976            return;
 1977        };
 1978        let buffer = buffer.clone();
 1979
 1980        let buffer_visible_start = scroll_anchor.text_anchor.to_point(&buffer);
 1981        let max_row = buffer.max_point().row;
 1982        let start_row = buffer_visible_start.row.min(max_row);
 1983        let end_row = (buffer_visible_start.row + 10).min(max_row);
 1984
 1985        let syntax = self.style(cx).syntax.clone();
 1986        let background_task = cx.background_spawn(async move {
 1987            buffer
 1988                .outline_items_containing(
 1989                    Point::new(start_row, 0)..Point::new(end_row, 0),
 1990                    true,
 1991                    Some(syntax.as_ref()),
 1992                )
 1993                .into_iter()
 1994                .map(|outline_item| OutlineItem {
 1995                    depth: outline_item.depth,
 1996                    range: Anchor::range_in_buffer(excerpt_id, outline_item.range),
 1997                    source_range_for_text: Anchor::range_in_buffer(
 1998                        excerpt_id,
 1999                        outline_item.source_range_for_text,
 2000                    ),
 2001                    text: outline_item.text,
 2002                    highlight_ranges: outline_item.highlight_ranges,
 2003                    name_ranges: outline_item.name_ranges,
 2004                    body_range: outline_item
 2005                        .body_range
 2006                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2007                    annotation_range: outline_item
 2008                        .annotation_range
 2009                        .map(|range| Anchor::range_in_buffer(excerpt_id, range)),
 2010                })
 2011                .collect()
 2012        });
 2013        self.sticky_headers_task = cx.spawn(async move |this, cx| {
 2014            let sticky_headers = background_task.await;
 2015            this.update(cx, |this, cx| {
 2016                this.sticky_headers = Some(sticky_headers);
 2017                cx.notify();
 2018            })
 2019            .ok();
 2020        });
 2021    }
 2022
 2023    fn new_internal(
 2024        mode: EditorMode,
 2025        multi_buffer: Entity<MultiBuffer>,
 2026        project: Option<Entity<Project>>,
 2027        display_map: Option<Entity<DisplayMap>>,
 2028        window: &mut Window,
 2029        cx: &mut Context<Self>,
 2030    ) -> Self {
 2031        debug_assert!(
 2032            display_map.is_none() || mode.is_minimap(),
 2033            "Providing a display map for a new editor is only intended for the minimap and might have unintended side effects otherwise!"
 2034        );
 2035
 2036        let full_mode = mode.is_full();
 2037        let is_minimap = mode.is_minimap();
 2038        let diagnostics_max_severity = if full_mode {
 2039            EditorSettings::get_global(cx)
 2040                .diagnostics_max_severity
 2041                .unwrap_or(DiagnosticSeverity::Hint)
 2042        } else {
 2043            DiagnosticSeverity::Off
 2044        };
 2045        let style = window.text_style();
 2046        let font_size = style.font_size.to_pixels(window.rem_size());
 2047        let editor = cx.entity().downgrade();
 2048        let fold_placeholder = FoldPlaceholder {
 2049            constrain_width: false,
 2050            render: Arc::new(move |fold_id, fold_range, cx| {
 2051                let editor = editor.clone();
 2052                FoldPlaceholder::fold_element(fold_id, cx)
 2053                    .cursor_pointer()
 2054                    .child("")
 2055                    .on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation())
 2056                    .on_click(move |_, _window, cx| {
 2057                        editor
 2058                            .update(cx, |editor, cx| {
 2059                                editor.unfold_ranges(
 2060                                    &[fold_range.start..fold_range.end],
 2061                                    true,
 2062                                    false,
 2063                                    cx,
 2064                                );
 2065                                cx.stop_propagation();
 2066                            })
 2067                            .ok();
 2068                    })
 2069                    .into_any()
 2070            }),
 2071            merge_adjacent: true,
 2072            ..FoldPlaceholder::default()
 2073        };
 2074        let display_map = display_map.unwrap_or_else(|| {
 2075            cx.new(|cx| {
 2076                DisplayMap::new(
 2077                    multi_buffer.clone(),
 2078                    style.font(),
 2079                    font_size,
 2080                    None,
 2081                    FILE_HEADER_HEIGHT,
 2082                    MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 2083                    fold_placeholder,
 2084                    diagnostics_max_severity,
 2085                    cx,
 2086                )
 2087            })
 2088        });
 2089
 2090        let selections = SelectionsCollection::new();
 2091
 2092        let blink_manager = cx.new(|cx| {
 2093            let mut blink_manager = BlinkManager::new(
 2094                CURSOR_BLINK_INTERVAL,
 2095                |cx| EditorSettings::get_global(cx).cursor_blink,
 2096                cx,
 2097            );
 2098            if is_minimap {
 2099                blink_manager.disable(cx);
 2100            }
 2101            blink_manager
 2102        });
 2103
 2104        let soft_wrap_mode_override =
 2105            matches!(mode, EditorMode::SingleLine).then(|| language_settings::SoftWrap::None);
 2106
 2107        let mut project_subscriptions = Vec::new();
 2108        if full_mode && let Some(project) = project.as_ref() {
 2109            project_subscriptions.push(cx.subscribe_in(
 2110                project,
 2111                window,
 2112                |editor, _, event, window, cx| match event {
 2113                    project::Event::RefreshCodeLens => {
 2114                        // we always query lens with actions, without storing them, always refreshing them
 2115                    }
 2116                    project::Event::RefreshInlayHints {
 2117                        server_id,
 2118                        request_id,
 2119                    } => {
 2120                        editor.refresh_inlay_hints(
 2121                            InlayHintRefreshReason::RefreshRequested {
 2122                                server_id: *server_id,
 2123                                request_id: *request_id,
 2124                            },
 2125                            cx,
 2126                        );
 2127                    }
 2128                    project::Event::RefreshSemanticTokens {
 2129                        server_id,
 2130                        request_id,
 2131                    } => {
 2132                        editor.refresh_semantic_tokens(
 2133                            None,
 2134                            Some(RefreshForServer {
 2135                                server_id: *server_id,
 2136                                request_id: *request_id,
 2137                            }),
 2138                            cx,
 2139                        );
 2140                    }
 2141                    project::Event::LanguageServerRemoved(_) => {
 2142                        editor.registered_buffers.clear();
 2143                        editor.register_visible_buffers(cx);
 2144                        editor.invalidate_semantic_tokens(None);
 2145                        editor.refresh_runnables(window, cx);
 2146                        editor.update_lsp_data(None, window, cx);
 2147                        editor.refresh_inlay_hints(InlayHintRefreshReason::ServerRemoved, cx);
 2148                    }
 2149                    project::Event::SnippetEdit(id, snippet_edits) => {
 2150                        // todo(lw): Non singletons
 2151                        if let Some(buffer) = editor.buffer.read(cx).as_singleton() {
 2152                            let snapshot = buffer.read(cx).snapshot();
 2153                            let focus_handle = editor.focus_handle(cx);
 2154                            if snapshot.remote_id() == *id && focus_handle.is_focused(window) {
 2155                                for (range, snippet) in snippet_edits {
 2156                                    let buffer_range =
 2157                                        language::range_from_lsp(*range).to_offset(&snapshot);
 2158                                    editor
 2159                                        .insert_snippet(
 2160                                            &[MultiBufferOffset(buffer_range.start)
 2161                                                ..MultiBufferOffset(buffer_range.end)],
 2162                                            snippet.clone(),
 2163                                            window,
 2164                                            cx,
 2165                                        )
 2166                                        .ok();
 2167                                }
 2168                            }
 2169                        }
 2170                    }
 2171                    project::Event::LanguageServerBufferRegistered { buffer_id, .. } => {
 2172                        let buffer_id = *buffer_id;
 2173                        if editor.buffer().read(cx).buffer(buffer_id).is_some() {
 2174                            editor.register_buffer(buffer_id, cx);
 2175                            editor.refresh_runnables(window, cx);
 2176                            editor.update_lsp_data(Some(buffer_id), window, cx);
 2177                            editor.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
 2178                            refresh_linked_ranges(editor, window, cx);
 2179                            editor.refresh_code_actions(window, cx);
 2180                            editor.refresh_document_highlights(cx);
 2181                        }
 2182                    }
 2183
 2184                    project::Event::EntryRenamed(transaction, project_path, abs_path) => {
 2185                        let Some(workspace) = editor.workspace() else {
 2186                            return;
 2187                        };
 2188                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2189                        else {
 2190                            return;
 2191                        };
 2192
 2193                        if active_editor.entity_id() == cx.entity_id() {
 2194                            let entity_id = cx.entity_id();
 2195                            workspace.update(cx, |this, cx| {
 2196                                this.panes_mut()
 2197                                    .iter_mut()
 2198                                    .filter(|pane| pane.entity_id() != entity_id)
 2199                                    .for_each(|p| {
 2200                                        p.update(cx, |pane, _| {
 2201                                            pane.nav_history_mut().rename_item(
 2202                                                entity_id,
 2203                                                project_path.clone(),
 2204                                                abs_path.clone().into(),
 2205                                            );
 2206                                        })
 2207                                    });
 2208                            });
 2209
 2210                            Self::open_transaction_for_hidden_buffers(
 2211                                workspace,
 2212                                transaction.clone(),
 2213                                "Rename".to_string(),
 2214                                window,
 2215                                cx,
 2216                            );
 2217                        }
 2218                    }
 2219
 2220                    project::Event::WorkspaceEditApplied(transaction) => {
 2221                        let Some(workspace) = editor.workspace() else {
 2222                            return;
 2223                        };
 2224                        let Some(active_editor) = workspace.read(cx).active_item_as::<Self>(cx)
 2225                        else {
 2226                            return;
 2227                        };
 2228
 2229                        if active_editor.entity_id() == cx.entity_id() {
 2230                            Self::open_transaction_for_hidden_buffers(
 2231                                workspace,
 2232                                transaction.clone(),
 2233                                "LSP Edit".to_string(),
 2234                                window,
 2235                                cx,
 2236                            );
 2237                        }
 2238                    }
 2239
 2240                    _ => {}
 2241                },
 2242            ));
 2243            if let Some(task_inventory) = project
 2244                .read(cx)
 2245                .task_store()
 2246                .read(cx)
 2247                .task_inventory()
 2248                .cloned()
 2249            {
 2250                project_subscriptions.push(cx.observe_in(
 2251                    &task_inventory,
 2252                    window,
 2253                    |editor, _, window, cx| {
 2254                        editor.refresh_runnables(window, cx);
 2255                    },
 2256                ));
 2257            };
 2258
 2259            project_subscriptions.push(cx.subscribe_in(
 2260                &project.read(cx).breakpoint_store(),
 2261                window,
 2262                |editor, _, event, window, cx| match event {
 2263                    BreakpointStoreEvent::ClearDebugLines => {
 2264                        editor.clear_row_highlights::<ActiveDebugLine>();
 2265                        editor.refresh_inline_values(cx);
 2266                    }
 2267                    BreakpointStoreEvent::SetDebugLine => {
 2268                        if editor.go_to_active_debug_line(window, cx) {
 2269                            cx.stop_propagation();
 2270                        }
 2271
 2272                        editor.refresh_inline_values(cx);
 2273                    }
 2274                    _ => {}
 2275                },
 2276            ));
 2277            let git_store = project.read(cx).git_store().clone();
 2278            let project = project.clone();
 2279            project_subscriptions.push(cx.subscribe(&git_store, move |this, _, event, cx| {
 2280                if let GitStoreEvent::RepositoryAdded = event {
 2281                    this.load_diff_task = Some(
 2282                        update_uncommitted_diff_for_buffer(
 2283                            cx.entity(),
 2284                            &project,
 2285                            this.buffer.read(cx).all_buffers(),
 2286                            this.buffer.clone(),
 2287                            cx,
 2288                        )
 2289                        .shared(),
 2290                    );
 2291                }
 2292            }));
 2293        }
 2294
 2295        let buffer_snapshot = multi_buffer.read(cx).snapshot(cx);
 2296
 2297        let inlay_hint_settings =
 2298            inlay_hint_settings(selections.newest_anchor().head(), &buffer_snapshot, cx);
 2299        let focus_handle = cx.focus_handle();
 2300        if !is_minimap {
 2301            cx.on_focus(&focus_handle, window, Self::handle_focus)
 2302                .detach();
 2303            cx.on_focus_in(&focus_handle, window, Self::handle_focus_in)
 2304                .detach();
 2305            cx.on_focus_out(&focus_handle, window, Self::handle_focus_out)
 2306                .detach();
 2307            cx.on_blur(&focus_handle, window, Self::handle_blur)
 2308                .detach();
 2309            cx.observe_pending_input(window, Self::observe_pending_input)
 2310                .detach();
 2311        }
 2312
 2313        let show_indent_guides =
 2314            if matches!(mode, EditorMode::SingleLine | EditorMode::Minimap { .. }) {
 2315                Some(false)
 2316            } else {
 2317                None
 2318            };
 2319
 2320        let breakpoint_store = match (&mode, project.as_ref()) {
 2321            (EditorMode::Full { .. }, Some(project)) => Some(project.read(cx).breakpoint_store()),
 2322            _ => None,
 2323        };
 2324
 2325        let mut code_action_providers = Vec::new();
 2326        let mut load_uncommitted_diff = None;
 2327        if let Some(project) = project.clone() {
 2328            load_uncommitted_diff = Some(
 2329                update_uncommitted_diff_for_buffer(
 2330                    cx.entity(),
 2331                    &project,
 2332                    multi_buffer.read(cx).all_buffers(),
 2333                    multi_buffer.clone(),
 2334                    cx,
 2335                )
 2336                .shared(),
 2337            );
 2338            code_action_providers.push(Rc::new(project) as Rc<_>);
 2339        }
 2340
 2341        let mut editor = Self {
 2342            focus_handle,
 2343            show_cursor_when_unfocused: false,
 2344            last_focused_descendant: None,
 2345            buffer: multi_buffer.clone(),
 2346            display_map: display_map.clone(),
 2347            placeholder_display_map: None,
 2348            selections,
 2349            scroll_manager: ScrollManager::new(cx),
 2350            columnar_selection_state: None,
 2351            add_selections_state: None,
 2352            select_next_state: None,
 2353            select_prev_state: None,
 2354            selection_history: SelectionHistory::default(),
 2355            defer_selection_effects: false,
 2356            deferred_selection_effects_state: None,
 2357            autoclose_regions: Vec::new(),
 2358            snippet_stack: InvalidationStack::default(),
 2359            select_syntax_node_history: SelectSyntaxNodeHistory::default(),
 2360            ime_transaction: None,
 2361            active_diagnostics: ActiveDiagnostic::None,
 2362            show_inline_diagnostics: ProjectSettings::get_global(cx).diagnostics.inline.enabled,
 2363            inline_diagnostics_update: Task::ready(()),
 2364            inline_diagnostics: Vec::new(),
 2365            soft_wrap_mode_override,
 2366            diagnostics_max_severity,
 2367            hard_wrap: None,
 2368            completion_provider: project.clone().map(|project| Rc::new(project) as _),
 2369            semantics_provider: project
 2370                .as_ref()
 2371                .map(|project| Rc::new(project.downgrade()) as _),
 2372            collaboration_hub: project.clone().map(|project| Box::new(project) as _),
 2373            project,
 2374            blink_manager: blink_manager.clone(),
 2375            show_local_selections: true,
 2376            show_scrollbars: ScrollbarAxes {
 2377                horizontal: full_mode,
 2378                vertical: full_mode,
 2379            },
 2380            minimap_visibility: MinimapVisibility::for_mode(&mode, cx),
 2381            offset_content: !matches!(mode, EditorMode::SingleLine),
 2382            show_breadcrumbs: EditorSettings::get_global(cx).toolbar.breadcrumbs,
 2383            show_gutter: full_mode,
 2384            show_line_numbers: (!full_mode).then_some(false),
 2385            use_relative_line_numbers: None,
 2386            disable_expand_excerpt_buttons: !full_mode,
 2387            delegate_expand_excerpts: false,
 2388            delegate_stage_and_restore: false,
 2389            delegate_open_excerpts: false,
 2390            enable_lsp_data: true,
 2391            enable_runnables: true,
 2392            show_git_diff_gutter: None,
 2393            show_code_actions: None,
 2394            show_runnables: None,
 2395            show_breakpoints: None,
 2396            show_diff_review_button: false,
 2397            show_wrap_guides: None,
 2398            show_indent_guides,
 2399            buffers_with_disabled_indent_guides: HashSet::default(),
 2400            highlight_order: 0,
 2401            highlighted_rows: HashMap::default(),
 2402            background_highlights: HashMap::default(),
 2403            gutter_highlights: HashMap::default(),
 2404            scrollbar_marker_state: ScrollbarMarkerState::default(),
 2405            active_indent_guides_state: ActiveIndentGuidesState::default(),
 2406            nav_history: None,
 2407            context_menu: RefCell::new(None),
 2408            context_menu_options: None,
 2409            mouse_context_menu: None,
 2410            completion_tasks: Vec::new(),
 2411            inline_blame_popover: None,
 2412            inline_blame_popover_show_task: None,
 2413            signature_help_state: SignatureHelpState::default(),
 2414            auto_signature_help: None,
 2415            find_all_references_task_sources: Vec::new(),
 2416            next_completion_id: 0,
 2417            next_inlay_id: 0,
 2418            code_action_providers,
 2419            available_code_actions: None,
 2420            code_actions_task: None,
 2421            quick_selection_highlight_task: None,
 2422            debounced_selection_highlight_task: None,
 2423            debounced_selection_highlight_complete: false,
 2424            document_highlights_task: None,
 2425            linked_editing_range_task: None,
 2426            pending_rename: None,
 2427            searchable: !is_minimap,
 2428            cursor_shape: EditorSettings::get_global(cx)
 2429                .cursor_shape
 2430                .unwrap_or_default(),
 2431            cursor_offset_on_selection: false,
 2432            current_line_highlight: None,
 2433            autoindent_mode: Some(AutoindentMode::EachLine),
 2434            collapse_matches: false,
 2435            workspace: None,
 2436            input_enabled: !is_minimap,
 2437            expects_character_input: !is_minimap,
 2438            use_modal_editing: full_mode,
 2439            read_only: is_minimap,
 2440            use_autoclose: true,
 2441            use_auto_surround: true,
 2442            auto_replace_emoji_shortcode: false,
 2443            jsx_tag_auto_close_enabled_in_any_buffer: false,
 2444            leader_id: None,
 2445            remote_id: None,
 2446            hover_state: HoverState::default(),
 2447            pending_mouse_down: None,
 2448            prev_pressure_stage: None,
 2449            hovered_link_state: None,
 2450            edit_prediction_provider: None,
 2451            active_edit_prediction: None,
 2452            stale_edit_prediction_in_menu: None,
 2453            edit_prediction_preview: EditPredictionPreview::Inactive {
 2454                released_too_fast: false,
 2455            },
 2456            inline_diagnostics_enabled: full_mode,
 2457            diagnostics_enabled: full_mode,
 2458            word_completions_enabled: full_mode,
 2459            inline_value_cache: InlineValueCache::new(inlay_hint_settings.show_value_hints),
 2460            gutter_hovered: false,
 2461            pixel_position_of_newest_cursor: None,
 2462            last_bounds: None,
 2463            last_position_map: None,
 2464            expect_bounds_change: None,
 2465            gutter_dimensions: GutterDimensions::default(),
 2466            style: None,
 2467            show_cursor_names: false,
 2468            hovered_cursors: HashMap::default(),
 2469            next_editor_action_id: EditorActionId::default(),
 2470            editor_actions: Rc::default(),
 2471            edit_predictions_hidden_for_vim_mode: false,
 2472            show_edit_predictions_override: None,
 2473            show_completions_on_input_override: None,
 2474            menu_edit_predictions_policy: MenuEditPredictionsPolicy::ByProvider,
 2475            edit_prediction_settings: EditPredictionSettings::Disabled,
 2476            edit_prediction_indent_conflict: false,
 2477            edit_prediction_requires_modifier_in_indent_conflict: true,
 2478            custom_context_menu: None,
 2479            show_git_blame_gutter: false,
 2480            show_git_blame_inline: false,
 2481            show_selection_menu: None,
 2482            show_git_blame_inline_delay_task: None,
 2483            git_blame_inline_enabled: full_mode
 2484                && ProjectSettings::get_global(cx).git.inline_blame.enabled,
 2485            render_diff_hunk_controls: Arc::new(render_diff_hunk_controls),
 2486            buffer_serialization: is_minimap.not().then(|| {
 2487                BufferSerialization::new(
 2488                    ProjectSettings::get_global(cx)
 2489                        .session
 2490                        .restore_unsaved_buffers,
 2491                )
 2492            }),
 2493            blame: None,
 2494            blame_subscription: None,
 2495
 2496            breakpoint_store,
 2497            gutter_breakpoint_indicator: (None, None),
 2498            gutter_diff_review_indicator: (None, None),
 2499            diff_review_drag_state: None,
 2500            diff_review_overlays: Vec::new(),
 2501            stored_review_comments: Vec::new(),
 2502            next_review_comment_id: 0,
 2503            hovered_diff_hunk_row: None,
 2504            _subscriptions: (!is_minimap)
 2505                .then(|| {
 2506                    vec![
 2507                        cx.observe(&multi_buffer, Self::on_buffer_changed),
 2508                        cx.subscribe_in(&multi_buffer, window, Self::on_buffer_event),
 2509                        cx.observe_in(&display_map, window, Self::on_display_map_changed),
 2510                        cx.observe(&blink_manager, |_, _, cx| cx.notify()),
 2511                        cx.observe_global_in::<SettingsStore>(window, Self::settings_changed),
 2512                        cx.observe_global_in::<GlobalTheme>(window, Self::theme_changed),
 2513                        observe_buffer_font_size_adjustment(cx, |_, cx| cx.notify()),
 2514                        cx.observe_window_activation(window, |editor, window, cx| {
 2515                            let active = window.is_window_active();
 2516                            editor.blink_manager.update(cx, |blink_manager, cx| {
 2517                                if active {
 2518                                    blink_manager.enable(cx);
 2519                                } else {
 2520                                    blink_manager.disable(cx);
 2521                                }
 2522                            });
 2523                            if active {
 2524                                editor.show_mouse_cursor(cx);
 2525                            }
 2526                        }),
 2527                    ]
 2528                })
 2529                .unwrap_or_default(),
 2530            runnables: RunnableData::new(),
 2531            pull_diagnostics_task: Task::ready(()),
 2532            colors: None,
 2533            refresh_colors_task: Task::ready(()),
 2534            use_document_folding_ranges: false,
 2535            refresh_folding_ranges_task: Task::ready(()),
 2536            inlay_hints: None,
 2537            next_color_inlay_id: 0,
 2538            post_scroll_update: Task::ready(()),
 2539            linked_edit_ranges: Default::default(),
 2540            in_project_search: false,
 2541            previous_search_ranges: None,
 2542            breadcrumb_header: None,
 2543            focused_block: None,
 2544            next_scroll_position: NextScrollCursorCenterTopBottom::default(),
 2545            addons: HashMap::default(),
 2546            registered_buffers: HashMap::default(),
 2547            _scroll_cursor_center_top_bottom_task: Task::ready(()),
 2548            selection_mark_mode: false,
 2549            toggle_fold_multiple_buffers: Task::ready(()),
 2550            serialize_selections: Task::ready(()),
 2551            serialize_folds: Task::ready(()),
 2552            text_style_refinement: None,
 2553            load_diff_task: load_uncommitted_diff,
 2554            temporary_diff_override: false,
 2555            mouse_cursor_hidden: false,
 2556            minimap: None,
 2557            hide_mouse_mode: EditorSettings::get_global(cx)
 2558                .hide_mouse
 2559                .unwrap_or_default(),
 2560            change_list: ChangeList::new(),
 2561            mode,
 2562            selection_drag_state: SelectionDragState::None,
 2563            folding_newlines: Task::ready(()),
 2564            lookup_key: None,
 2565            select_next_is_case_sensitive: None,
 2566            on_local_selections_changed: None,
 2567            suppress_selection_callback: false,
 2568            applicable_language_settings: HashMap::default(),
 2569            semantic_token_state: SemanticTokenState::new(cx, full_mode),
 2570            accent_data: None,
 2571            bracket_fetched_tree_sitter_chunks: HashMap::default(),
 2572            number_deleted_lines: false,
 2573            refresh_matching_bracket_highlights_task: Task::ready(()),
 2574            refresh_document_symbols_task: Task::ready(()).shared(),
 2575            lsp_document_symbols: HashMap::default(),
 2576            refresh_outline_symbols_at_cursor_at_cursor_task: Task::ready(()),
 2577            outline_symbols_at_cursor: None,
 2578            sticky_headers_task: Task::ready(()),
 2579            sticky_headers: None,
 2580            colorize_brackets_task: Task::ready(()),
 2581        };
 2582
 2583        if is_minimap {
 2584            return editor;
 2585        }
 2586
 2587        editor.applicable_language_settings = editor.fetch_applicable_language_settings(cx);
 2588        editor.accent_data = editor.fetch_accent_data(cx);
 2589
 2590        if let Some(breakpoints) = editor.breakpoint_store.as_ref() {
 2591            editor
 2592                ._subscriptions
 2593                .push(cx.observe(breakpoints, |_, _, cx| {
 2594                    cx.notify();
 2595                }));
 2596        }
 2597        editor._subscriptions.extend(project_subscriptions);
 2598
 2599        editor._subscriptions.push(cx.subscribe_in(
 2600            &cx.entity(),
 2601            window,
 2602            |editor, _, e: &EditorEvent, window, cx| match e {
 2603                EditorEvent::ScrollPositionChanged { local, .. } => {
 2604                    if *local {
 2605                        editor.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 2606                        editor.inline_blame_popover.take();
 2607                        let snapshot = editor.snapshot(window, cx);
 2608                        let new_anchor = editor
 2609                            .scroll_manager
 2610                            .native_anchor(&snapshot.display_snapshot, cx);
 2611                        editor.update_restoration_data(cx, move |data| {
 2612                            data.scroll_position = (
 2613                                new_anchor.top_row(snapshot.buffer_snapshot()),
 2614                                new_anchor.offset,
 2615                            );
 2616                        });
 2617
 2618                        editor.post_scroll_update = cx.spawn_in(window, async move |editor, cx| {
 2619                            cx.background_executor()
 2620                                .timer(Duration::from_millis(50))
 2621                                .await;
 2622                            editor
 2623                                .update_in(cx, |editor, window, cx| {
 2624                                    editor.update_data_on_scroll(window, cx)
 2625                                })
 2626                                .ok();
 2627                        });
 2628                    }
 2629                    editor.refresh_sticky_headers(&editor.snapshot(window, cx), cx);
 2630                }
 2631                EditorEvent::Edited { .. } => {
 2632                    let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
 2633                        .map(|vim_mode| vim_mode.0)
 2634                        .unwrap_or(false);
 2635                    if !vim_mode {
 2636                        let display_map = editor.display_snapshot(cx);
 2637                        let selections = editor.selections.all_adjusted_display(&display_map);
 2638                        let pop_state = editor
 2639                            .change_list
 2640                            .last()
 2641                            .map(|previous| {
 2642                                previous.len() == selections.len()
 2643                                    && previous.iter().enumerate().all(|(ix, p)| {
 2644                                        p.to_display_point(&display_map).row()
 2645                                            == selections[ix].head().row()
 2646                                    })
 2647                            })
 2648                            .unwrap_or(false);
 2649                        let new_positions = selections
 2650                            .into_iter()
 2651                            .map(|s| display_map.display_point_to_anchor(s.head(), Bias::Left))
 2652                            .collect();
 2653                        editor
 2654                            .change_list
 2655                            .push_to_change_list(pop_state, new_positions);
 2656                    }
 2657                }
 2658                _ => (),
 2659            },
 2660        ));
 2661
 2662        if let Some(dap_store) = editor
 2663            .project
 2664            .as_ref()
 2665            .map(|project| project.read(cx).dap_store())
 2666        {
 2667            let weak_editor = cx.weak_entity();
 2668
 2669            editor
 2670                ._subscriptions
 2671                .push(
 2672                    cx.observe_new::<project::debugger::session::Session>(move |_, _, cx| {
 2673                        let session_entity = cx.entity();
 2674                        weak_editor
 2675                            .update(cx, |editor, cx| {
 2676                                editor._subscriptions.push(
 2677                                    cx.subscribe(&session_entity, Self::on_debug_session_event),
 2678                                );
 2679                            })
 2680                            .ok();
 2681                    }),
 2682                );
 2683
 2684            for session in dap_store.read(cx).sessions().cloned().collect::<Vec<_>>() {
 2685                editor
 2686                    ._subscriptions
 2687                    .push(cx.subscribe(&session, Self::on_debug_session_event));
 2688            }
 2689        }
 2690
 2691        // skip adding the initial selection to selection history
 2692        editor.selection_history.mode = SelectionHistoryMode::Skipping;
 2693        editor.end_selection(window, cx);
 2694        editor.selection_history.mode = SelectionHistoryMode::Normal;
 2695
 2696        editor.scroll_manager.show_scrollbars(window, cx);
 2697        jsx_tag_auto_close::refresh_enabled_in_any_buffer(&mut editor, &multi_buffer, cx);
 2698
 2699        if full_mode {
 2700            let should_auto_hide_scrollbars = cx.should_auto_hide_scrollbars();
 2701            cx.set_global(ScrollbarAutoHide(should_auto_hide_scrollbars));
 2702
 2703            if editor.git_blame_inline_enabled {
 2704                editor.start_git_blame_inline(false, window, cx);
 2705            }
 2706
 2707            editor.go_to_active_debug_line(window, cx);
 2708
 2709            editor.minimap =
 2710                editor.create_minimap(EditorSettings::get_global(cx).minimap, window, cx);
 2711            editor.colors = Some(LspColorData::new(cx));
 2712            editor.use_document_folding_ranges = true;
 2713            editor.inlay_hints = Some(LspInlayHintData::new(inlay_hint_settings));
 2714
 2715            if let Some(buffer) = multi_buffer.read(cx).as_singleton() {
 2716                editor.register_buffer(buffer.read(cx).remote_id(), cx);
 2717            }
 2718            editor.report_editor_event(ReportEditorEvent::EditorOpened, None, cx);
 2719        }
 2720
 2721        editor
 2722    }
 2723
 2724    pub fn display_snapshot(&self, cx: &mut App) -> DisplaySnapshot {
 2725        self.display_map.update(cx, |map, cx| map.snapshot(cx))
 2726    }
 2727
 2728    pub fn deploy_mouse_context_menu(
 2729        &mut self,
 2730        position: gpui::Point<Pixels>,
 2731        context_menu: Entity<ContextMenu>,
 2732        window: &mut Window,
 2733        cx: &mut Context<Self>,
 2734    ) {
 2735        self.mouse_context_menu = Some(MouseContextMenu::new(
 2736            self,
 2737            crate::mouse_context_menu::MenuPosition::PinnedToScreen(position),
 2738            context_menu,
 2739            window,
 2740            cx,
 2741        ));
 2742    }
 2743
 2744    pub fn mouse_menu_is_focused(&self, window: &Window, cx: &App) -> bool {
 2745        self.mouse_context_menu
 2746            .as_ref()
 2747            .is_some_and(|menu| menu.context_menu.focus_handle(cx).is_focused(window))
 2748    }
 2749
 2750    pub fn is_range_selected(&mut self, range: &Range<Anchor>, cx: &mut Context<Self>) -> bool {
 2751        if self
 2752            .selections
 2753            .pending_anchor()
 2754            .is_some_and(|pending_selection| {
 2755                let snapshot = self.buffer().read(cx).snapshot(cx);
 2756                pending_selection.range().includes(range, &snapshot)
 2757            })
 2758        {
 2759            return true;
 2760        }
 2761
 2762        self.selections
 2763            .disjoint_in_range::<MultiBufferOffset>(range.clone(), &self.display_snapshot(cx))
 2764            .into_iter()
 2765            .any(|selection| {
 2766                // This is needed to cover a corner case, if we just check for an existing
 2767                // selection in the fold range, having a cursor at the start of the fold
 2768                // marks it as selected. Non-empty selections don't cause this.
 2769                let length = selection.end - selection.start;
 2770                length > 0
 2771            })
 2772    }
 2773
 2774    pub fn key_context(&self, window: &mut Window, cx: &mut App) -> KeyContext {
 2775        self.key_context_internal(self.has_active_edit_prediction(), window, cx)
 2776    }
 2777
 2778    fn key_context_internal(
 2779        &self,
 2780        has_active_edit_prediction: bool,
 2781        window: &mut Window,
 2782        cx: &mut App,
 2783    ) -> KeyContext {
 2784        let mut key_context = KeyContext::new_with_defaults();
 2785        key_context.add("Editor");
 2786        let mode = match self.mode {
 2787            EditorMode::SingleLine => "single_line",
 2788            EditorMode::AutoHeight { .. } => "auto_height",
 2789            EditorMode::Minimap { .. } => "minimap",
 2790            EditorMode::Full { .. } => "full",
 2791        };
 2792
 2793        if EditorSettings::jupyter_enabled(cx) {
 2794            key_context.add("jupyter");
 2795        }
 2796
 2797        key_context.set("mode", mode);
 2798        if self.pending_rename.is_some() {
 2799            key_context.add("renaming");
 2800        }
 2801
 2802        if let Some(snippet_stack) = self.snippet_stack.last() {
 2803            key_context.add("in_snippet");
 2804
 2805            if snippet_stack.active_index > 0 {
 2806                key_context.add("has_previous_tabstop");
 2807            }
 2808
 2809            if snippet_stack.active_index < snippet_stack.ranges.len().saturating_sub(1) {
 2810                key_context.add("has_next_tabstop");
 2811            }
 2812        }
 2813
 2814        match self.context_menu.borrow().as_ref() {
 2815            Some(CodeContextMenu::Completions(menu)) => {
 2816                if menu.visible() {
 2817                    key_context.add("menu");
 2818                    key_context.add("showing_completions");
 2819                }
 2820            }
 2821            Some(CodeContextMenu::CodeActions(menu)) => {
 2822                if menu.visible() {
 2823                    key_context.add("menu");
 2824                    key_context.add("showing_code_actions")
 2825                }
 2826            }
 2827            None => {}
 2828        }
 2829
 2830        if self.signature_help_state.has_multiple_signatures() {
 2831            key_context.add("showing_signature_help");
 2832        }
 2833
 2834        // Disable vim contexts when a sub-editor (e.g. rename/inline assistant) is focused.
 2835        if !self.focus_handle(cx).contains_focused(window, cx)
 2836            || (self.is_focused(window) || self.mouse_menu_is_focused(window, cx))
 2837        {
 2838            for addon in self.addons.values() {
 2839                addon.extend_key_context(&mut key_context, cx)
 2840            }
 2841        }
 2842
 2843        if let Some(singleton_buffer) = self.buffer.read(cx).as_singleton() {
 2844            if let Some(extension) = singleton_buffer.read(cx).file().and_then(|file| {
 2845                Some(
 2846                    file.full_path(cx)
 2847                        .extension()?
 2848                        .to_string_lossy()
 2849                        .to_lowercase(),
 2850                )
 2851            }) {
 2852                key_context.set("extension", extension);
 2853            }
 2854        } else {
 2855            key_context.add("multibuffer");
 2856        }
 2857
 2858        if has_active_edit_prediction {
 2859            if self.edit_prediction_in_conflict() {
 2860                key_context.add(EDIT_PREDICTION_CONFLICT_KEY_CONTEXT);
 2861            } else {
 2862                key_context.add(EDIT_PREDICTION_KEY_CONTEXT);
 2863                key_context.add("copilot_suggestion");
 2864            }
 2865        }
 2866
 2867        if self.selection_mark_mode {
 2868            key_context.add("selection_mode");
 2869        }
 2870
 2871        let disjoint = self.selections.disjoint_anchors();
 2872        let snapshot = self.snapshot(window, cx);
 2873        let snapshot = snapshot.buffer_snapshot();
 2874        if self.mode == EditorMode::SingleLine
 2875            && let [selection] = disjoint
 2876            && selection.start == selection.end
 2877            && selection.end.to_offset(snapshot) == snapshot.len()
 2878        {
 2879            key_context.add("end_of_input");
 2880        }
 2881
 2882        if self.has_any_expanded_diff_hunks(cx) {
 2883            key_context.add("diffs_expanded");
 2884        }
 2885
 2886        key_context
 2887    }
 2888
 2889    pub fn last_bounds(&self) -> Option<&Bounds<Pixels>> {
 2890        self.last_bounds.as_ref()
 2891    }
 2892
 2893    fn show_mouse_cursor(&mut self, cx: &mut Context<Self>) {
 2894        if self.mouse_cursor_hidden {
 2895            self.mouse_cursor_hidden = false;
 2896            cx.notify();
 2897        }
 2898    }
 2899
 2900    pub fn hide_mouse_cursor(&mut self, origin: HideMouseCursorOrigin, cx: &mut Context<Self>) {
 2901        let hide_mouse_cursor = match origin {
 2902            HideMouseCursorOrigin::TypingAction => {
 2903                matches!(
 2904                    self.hide_mouse_mode,
 2905                    HideMouseMode::OnTyping | HideMouseMode::OnTypingAndMovement
 2906                )
 2907            }
 2908            HideMouseCursorOrigin::MovementAction => {
 2909                matches!(self.hide_mouse_mode, HideMouseMode::OnTypingAndMovement)
 2910            }
 2911        };
 2912        if self.mouse_cursor_hidden != hide_mouse_cursor {
 2913            self.mouse_cursor_hidden = hide_mouse_cursor;
 2914            cx.notify();
 2915        }
 2916    }
 2917
 2918    pub fn edit_prediction_in_conflict(&self) -> bool {
 2919        if !self.show_edit_predictions_in_menu() {
 2920            return false;
 2921        }
 2922
 2923        let showing_completions = self
 2924            .context_menu
 2925            .borrow()
 2926            .as_ref()
 2927            .is_some_and(|context| matches!(context, CodeContextMenu::Completions(_)));
 2928
 2929        showing_completions
 2930            || self.edit_prediction_requires_modifier()
 2931            // Require modifier key when the cursor is on leading whitespace, to allow `tab`
 2932            // bindings to insert tab characters.
 2933            || (self.edit_prediction_requires_modifier_in_indent_conflict && self.edit_prediction_indent_conflict)
 2934    }
 2935
 2936    pub fn accept_edit_prediction_keybind(
 2937        &self,
 2938        granularity: EditPredictionGranularity,
 2939        window: &mut Window,
 2940        cx: &mut App,
 2941    ) -> AcceptEditPredictionBinding {
 2942        let key_context = self.key_context_internal(true, window, cx);
 2943        let in_conflict = self.edit_prediction_in_conflict();
 2944
 2945        let bindings =
 2946            match granularity {
 2947                EditPredictionGranularity::Word => window
 2948                    .bindings_for_action_in_context(&AcceptNextWordEditPrediction, key_context),
 2949                EditPredictionGranularity::Line => window
 2950                    .bindings_for_action_in_context(&AcceptNextLineEditPrediction, key_context),
 2951                EditPredictionGranularity::Full => {
 2952                    window.bindings_for_action_in_context(&AcceptEditPrediction, key_context)
 2953                }
 2954            };
 2955
 2956        AcceptEditPredictionBinding(bindings.into_iter().rev().find(|binding| {
 2957            !in_conflict
 2958                || binding
 2959                    .keystrokes()
 2960                    .first()
 2961                    .is_some_and(|keystroke| keystroke.modifiers().modified())
 2962        }))
 2963    }
 2964
 2965    pub fn new_file(
 2966        workspace: &mut Workspace,
 2967        _: &workspace::NewFile,
 2968        window: &mut Window,
 2969        cx: &mut Context<Workspace>,
 2970    ) {
 2971        Self::new_in_workspace(workspace, window, cx).detach_and_prompt_err(
 2972            "Failed to create buffer",
 2973            window,
 2974            cx,
 2975            |e, _, _| match e.error_code() {
 2976                ErrorCode::RemoteUpgradeRequired => Some(format!(
 2977                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 2978                e.error_tag("required").unwrap_or("the latest version")
 2979            )),
 2980                _ => None,
 2981            },
 2982        );
 2983    }
 2984
 2985    pub fn new_in_workspace(
 2986        workspace: &mut Workspace,
 2987        window: &mut Window,
 2988        cx: &mut Context<Workspace>,
 2989    ) -> Task<Result<Entity<Editor>>> {
 2990        let project = workspace.project().clone();
 2991        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 2992
 2993        cx.spawn_in(window, async move |workspace, cx| {
 2994            let buffer = create.await?;
 2995            workspace.update_in(cx, |workspace, window, cx| {
 2996                let editor =
 2997                    cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx));
 2998                workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 2999                editor
 3000            })
 3001        })
 3002    }
 3003
 3004    fn new_file_vertical(
 3005        workspace: &mut Workspace,
 3006        _: &workspace::NewFileSplitVertical,
 3007        window: &mut Window,
 3008        cx: &mut Context<Workspace>,
 3009    ) {
 3010        Self::new_file_in_direction(workspace, SplitDirection::vertical(cx), window, cx)
 3011    }
 3012
 3013    fn new_file_horizontal(
 3014        workspace: &mut Workspace,
 3015        _: &workspace::NewFileSplitHorizontal,
 3016        window: &mut Window,
 3017        cx: &mut Context<Workspace>,
 3018    ) {
 3019        Self::new_file_in_direction(workspace, SplitDirection::horizontal(cx), window, cx)
 3020    }
 3021
 3022    fn new_file_split(
 3023        workspace: &mut Workspace,
 3024        action: &workspace::NewFileSplit,
 3025        window: &mut Window,
 3026        cx: &mut Context<Workspace>,
 3027    ) {
 3028        Self::new_file_in_direction(workspace, action.0, window, cx)
 3029    }
 3030
 3031    fn new_file_in_direction(
 3032        workspace: &mut Workspace,
 3033        direction: SplitDirection,
 3034        window: &mut Window,
 3035        cx: &mut Context<Workspace>,
 3036    ) {
 3037        let project = workspace.project().clone();
 3038        let create = project.update(cx, |project, cx| project.create_buffer(None, true, cx));
 3039
 3040        cx.spawn_in(window, async move |workspace, cx| {
 3041            let buffer = create.await?;
 3042            workspace.update_in(cx, move |workspace, window, cx| {
 3043                workspace.split_item(
 3044                    direction,
 3045                    Box::new(
 3046                        cx.new(|cx| Editor::for_buffer(buffer, Some(project.clone()), window, cx)),
 3047                    ),
 3048                    window,
 3049                    cx,
 3050                )
 3051            })?;
 3052            anyhow::Ok(())
 3053        })
 3054        .detach_and_prompt_err("Failed to create buffer", window, cx, |e, _, _| {
 3055            match e.error_code() {
 3056                ErrorCode::RemoteUpgradeRequired => Some(format!(
 3057                "The remote instance of Zed does not support this yet. It must be upgraded to {}",
 3058                e.error_tag("required").unwrap_or("the latest version")
 3059            )),
 3060                _ => None,
 3061            }
 3062        });
 3063    }
 3064
 3065    pub fn leader_id(&self) -> Option<CollaboratorId> {
 3066        self.leader_id
 3067    }
 3068
 3069    pub fn buffer(&self) -> &Entity<MultiBuffer> {
 3070        &self.buffer
 3071    }
 3072
 3073    pub fn project(&self) -> Option<&Entity<Project>> {
 3074        self.project.as_ref()
 3075    }
 3076
 3077    pub fn workspace(&self) -> Option<Entity<Workspace>> {
 3078        self.workspace.as_ref()?.0.upgrade()
 3079    }
 3080
 3081    /// Detaches a task and shows an error notification in the workspace if available,
 3082    /// otherwise just logs the error.
 3083    pub fn detach_and_notify_err<R, E>(
 3084        &self,
 3085        task: Task<Result<R, E>>,
 3086        window: &mut Window,
 3087        cx: &mut App,
 3088    ) where
 3089        E: std::fmt::Debug + std::fmt::Display + 'static,
 3090        R: 'static,
 3091    {
 3092        if let Some(workspace) = self.workspace() {
 3093            task.detach_and_notify_err(workspace.downgrade(), window, cx);
 3094        } else {
 3095            task.detach_and_log_err(cx);
 3096        }
 3097    }
 3098
 3099    /// Returns the workspace serialization ID if this editor should be serialized.
 3100    fn workspace_serialization_id(&self, _cx: &App) -> Option<WorkspaceId> {
 3101        self.workspace
 3102            .as_ref()
 3103            .filter(|_| self.should_serialize_buffer())
 3104            .and_then(|workspace| workspace.1)
 3105    }
 3106
 3107    pub fn title<'a>(&self, cx: &'a App) -> Cow<'a, str> {
 3108        self.buffer().read(cx).title(cx)
 3109    }
 3110
 3111    pub fn snapshot(&self, window: &Window, cx: &mut App) -> EditorSnapshot {
 3112        let git_blame_gutter_max_author_length = self
 3113            .render_git_blame_gutter(cx)
 3114            .then(|| {
 3115                if let Some(blame) = self.blame.as_ref() {
 3116                    let max_author_length =
 3117                        blame.update(cx, |blame, cx| blame.max_author_length(cx));
 3118                    Some(max_author_length)
 3119                } else {
 3120                    None
 3121                }
 3122            })
 3123            .flatten();
 3124
 3125        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3126
 3127        EditorSnapshot {
 3128            mode: self.mode.clone(),
 3129            show_gutter: self.show_gutter,
 3130            offset_content: self.offset_content,
 3131            show_line_numbers: self.show_line_numbers,
 3132            number_deleted_lines: self.number_deleted_lines,
 3133            show_git_diff_gutter: self.show_git_diff_gutter,
 3134            semantic_tokens_enabled: self.semantic_token_state.enabled(),
 3135            show_code_actions: self.show_code_actions,
 3136            show_runnables: self.show_runnables,
 3137            show_breakpoints: self.show_breakpoints,
 3138            git_blame_gutter_max_author_length,
 3139            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 3140            display_snapshot,
 3141            placeholder_display_snapshot: self
 3142                .placeholder_display_map
 3143                .as_ref()
 3144                .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx))),
 3145            ongoing_scroll: self.scroll_manager.ongoing_scroll(),
 3146            is_focused: self.focus_handle.is_focused(window),
 3147            current_line_highlight: self
 3148                .current_line_highlight
 3149                .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight),
 3150            gutter_hovered: self.gutter_hovered,
 3151        }
 3152    }
 3153
 3154    pub fn language_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<Language>> {
 3155        self.buffer.read(cx).language_at(point, cx)
 3156    }
 3157
 3158    pub fn file_at<T: ToOffset>(&self, point: T, cx: &App) -> Option<Arc<dyn language::File>> {
 3159        self.buffer.read(cx).read(cx).file_at(point).cloned()
 3160    }
 3161
 3162    pub fn active_excerpt(
 3163        &self,
 3164        cx: &App,
 3165    ) -> Option<(ExcerptId, Entity<Buffer>, Range<text::Anchor>)> {
 3166        self.buffer
 3167            .read(cx)
 3168            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 3169    }
 3170
 3171    pub fn mode(&self) -> &EditorMode {
 3172        &self.mode
 3173    }
 3174
 3175    pub fn set_mode(&mut self, mode: EditorMode) {
 3176        self.mode = mode;
 3177    }
 3178
 3179    pub fn collaboration_hub(&self) -> Option<&dyn CollaborationHub> {
 3180        self.collaboration_hub.as_deref()
 3181    }
 3182
 3183    pub fn set_collaboration_hub(&mut self, hub: Box<dyn CollaborationHub>) {
 3184        self.collaboration_hub = Some(hub);
 3185    }
 3186
 3187    pub fn set_in_project_search(&mut self, in_project_search: bool) {
 3188        self.in_project_search = in_project_search;
 3189    }
 3190
 3191    pub fn set_custom_context_menu(
 3192        &mut self,
 3193        f: impl 'static
 3194        + Fn(
 3195            &mut Self,
 3196            DisplayPoint,
 3197            &mut Window,
 3198            &mut Context<Self>,
 3199        ) -> Option<Entity<ui::ContextMenu>>,
 3200    ) {
 3201        self.custom_context_menu = Some(Box::new(f))
 3202    }
 3203
 3204    pub fn set_completion_provider(&mut self, provider: Option<Rc<dyn CompletionProvider>>) {
 3205        self.completion_provider = provider;
 3206    }
 3207
 3208    #[cfg(any(test, feature = "test-support"))]
 3209    pub fn completion_provider(&self) -> Option<Rc<dyn CompletionProvider>> {
 3210        self.completion_provider.clone()
 3211    }
 3212
 3213    pub fn semantics_provider(&self) -> Option<Rc<dyn SemanticsProvider>> {
 3214        self.semantics_provider.clone()
 3215    }
 3216
 3217    pub fn set_semantics_provider(&mut self, provider: Option<Rc<dyn SemanticsProvider>>) {
 3218        self.semantics_provider = provider;
 3219    }
 3220
 3221    pub fn set_edit_prediction_provider<T>(
 3222        &mut self,
 3223        provider: Option<Entity<T>>,
 3224        window: &mut Window,
 3225        cx: &mut Context<Self>,
 3226    ) where
 3227        T: EditPredictionDelegate,
 3228    {
 3229        self.edit_prediction_provider = provider.map(|provider| RegisteredEditPredictionDelegate {
 3230            _subscription: cx.observe_in(&provider, window, |this, _, window, cx| {
 3231                if this.focus_handle.is_focused(window) {
 3232                    this.update_visible_edit_prediction(window, cx);
 3233                }
 3234            }),
 3235            provider: Arc::new(provider),
 3236        });
 3237        self.update_edit_prediction_settings(cx);
 3238        self.refresh_edit_prediction(false, false, window, cx);
 3239    }
 3240
 3241    pub fn placeholder_text(&self, cx: &mut App) -> Option<String> {
 3242        self.placeholder_display_map
 3243            .as_ref()
 3244            .map(|display_map| display_map.update(cx, |map, cx| map.snapshot(cx)).text())
 3245    }
 3246
 3247    pub fn set_placeholder_text(
 3248        &mut self,
 3249        placeholder_text: &str,
 3250        window: &mut Window,
 3251        cx: &mut Context<Self>,
 3252    ) {
 3253        let multibuffer = cx
 3254            .new(|cx| MultiBuffer::singleton(cx.new(|cx| Buffer::local(placeholder_text, cx)), cx));
 3255
 3256        let style = window.text_style();
 3257
 3258        self.placeholder_display_map = Some(cx.new(|cx| {
 3259            DisplayMap::new(
 3260                multibuffer,
 3261                style.font(),
 3262                style.font_size.to_pixels(window.rem_size()),
 3263                None,
 3264                FILE_HEADER_HEIGHT,
 3265                MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
 3266                Default::default(),
 3267                DiagnosticSeverity::Off,
 3268                cx,
 3269            )
 3270        }));
 3271        cx.notify();
 3272    }
 3273
 3274    pub fn set_cursor_shape(&mut self, cursor_shape: CursorShape, cx: &mut Context<Self>) {
 3275        self.cursor_shape = cursor_shape;
 3276
 3277        // Disrupt blink for immediate user feedback that the cursor shape has changed
 3278        self.blink_manager.update(cx, BlinkManager::show_cursor);
 3279
 3280        cx.notify();
 3281    }
 3282
 3283    pub fn cursor_shape(&self) -> CursorShape {
 3284        self.cursor_shape
 3285    }
 3286
 3287    pub fn set_cursor_offset_on_selection(&mut self, set_cursor_offset_on_selection: bool) {
 3288        self.cursor_offset_on_selection = set_cursor_offset_on_selection;
 3289    }
 3290
 3291    pub fn set_current_line_highlight(
 3292        &mut self,
 3293        current_line_highlight: Option<CurrentLineHighlight>,
 3294    ) {
 3295        self.current_line_highlight = current_line_highlight;
 3296    }
 3297
 3298    pub fn set_collapse_matches(&mut self, collapse_matches: bool) {
 3299        self.collapse_matches = collapse_matches;
 3300    }
 3301
 3302    pub fn range_for_match<T: std::marker::Copy>(&self, range: &Range<T>) -> Range<T> {
 3303        if self.collapse_matches {
 3304            return range.start..range.start;
 3305        }
 3306        range.clone()
 3307    }
 3308
 3309    pub fn clip_at_line_ends(&mut self, cx: &mut Context<Self>) -> bool {
 3310        self.display_map.read(cx).clip_at_line_ends
 3311    }
 3312
 3313    pub fn set_clip_at_line_ends(&mut self, clip: bool, cx: &mut Context<Self>) {
 3314        if self.display_map.read(cx).clip_at_line_ends != clip {
 3315            self.display_map
 3316                .update(cx, |map, _| map.clip_at_line_ends = clip);
 3317        }
 3318    }
 3319
 3320    pub fn set_input_enabled(&mut self, input_enabled: bool) {
 3321        self.input_enabled = input_enabled;
 3322    }
 3323
 3324    pub fn set_expects_character_input(&mut self, expects_character_input: bool) {
 3325        self.expects_character_input = expects_character_input;
 3326    }
 3327
 3328    pub fn set_edit_predictions_hidden_for_vim_mode(
 3329        &mut self,
 3330        hidden: bool,
 3331        window: &mut Window,
 3332        cx: &mut Context<Self>,
 3333    ) {
 3334        if hidden != self.edit_predictions_hidden_for_vim_mode {
 3335            self.edit_predictions_hidden_for_vim_mode = hidden;
 3336            if hidden {
 3337                self.update_visible_edit_prediction(window, cx);
 3338            } else {
 3339                self.refresh_edit_prediction(true, false, window, cx);
 3340            }
 3341        }
 3342    }
 3343
 3344    pub fn set_menu_edit_predictions_policy(&mut self, value: MenuEditPredictionsPolicy) {
 3345        self.menu_edit_predictions_policy = value;
 3346    }
 3347
 3348    pub fn set_autoindent(&mut self, autoindent: bool) {
 3349        if autoindent {
 3350            self.autoindent_mode = Some(AutoindentMode::EachLine);
 3351        } else {
 3352            self.autoindent_mode = None;
 3353        }
 3354    }
 3355
 3356    pub fn capability(&self, cx: &App) -> Capability {
 3357        if self.read_only {
 3358            Capability::ReadOnly
 3359        } else {
 3360            self.buffer.read(cx).capability()
 3361        }
 3362    }
 3363
 3364    pub fn read_only(&self, cx: &App) -> bool {
 3365        self.read_only || self.buffer.read(cx).read_only()
 3366    }
 3367
 3368    pub fn set_read_only(&mut self, read_only: bool) {
 3369        self.read_only = read_only;
 3370    }
 3371
 3372    pub fn set_use_autoclose(&mut self, autoclose: bool) {
 3373        self.use_autoclose = autoclose;
 3374    }
 3375
 3376    pub fn set_use_auto_surround(&mut self, auto_surround: bool) {
 3377        self.use_auto_surround = auto_surround;
 3378    }
 3379
 3380    pub fn set_auto_replace_emoji_shortcode(&mut self, auto_replace: bool) {
 3381        self.auto_replace_emoji_shortcode = auto_replace;
 3382    }
 3383
 3384    pub fn set_should_serialize(&mut self, should_serialize: bool, cx: &App) {
 3385        self.buffer_serialization = should_serialize.then(|| {
 3386            BufferSerialization::new(
 3387                ProjectSettings::get_global(cx)
 3388                    .session
 3389                    .restore_unsaved_buffers,
 3390            )
 3391        })
 3392    }
 3393
 3394    fn should_serialize_buffer(&self) -> bool {
 3395        self.buffer_serialization.is_some()
 3396    }
 3397
 3398    pub fn toggle_edit_predictions(
 3399        &mut self,
 3400        _: &ToggleEditPrediction,
 3401        window: &mut Window,
 3402        cx: &mut Context<Self>,
 3403    ) {
 3404        if self.show_edit_predictions_override.is_some() {
 3405            self.set_show_edit_predictions(None, window, cx);
 3406        } else {
 3407            let show_edit_predictions = !self.edit_predictions_enabled();
 3408            self.set_show_edit_predictions(Some(show_edit_predictions), window, cx);
 3409        }
 3410    }
 3411
 3412    pub fn set_show_completions_on_input(&mut self, show_completions_on_input: Option<bool>) {
 3413        self.show_completions_on_input_override = show_completions_on_input;
 3414    }
 3415
 3416    pub fn set_show_edit_predictions(
 3417        &mut self,
 3418        show_edit_predictions: Option<bool>,
 3419        window: &mut Window,
 3420        cx: &mut Context<Self>,
 3421    ) {
 3422        self.show_edit_predictions_override = show_edit_predictions;
 3423        self.update_edit_prediction_settings(cx);
 3424
 3425        if let Some(false) = show_edit_predictions {
 3426            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 3427        } else {
 3428            self.refresh_edit_prediction(false, true, window, cx);
 3429        }
 3430    }
 3431
 3432    fn edit_predictions_disabled_in_scope(
 3433        &self,
 3434        buffer: &Entity<Buffer>,
 3435        buffer_position: language::Anchor,
 3436        cx: &App,
 3437    ) -> bool {
 3438        let snapshot = buffer.read(cx).snapshot();
 3439        let settings = snapshot.settings_at(buffer_position, cx);
 3440
 3441        let Some(scope) = snapshot.language_scope_at(buffer_position) else {
 3442            return false;
 3443        };
 3444
 3445        scope.override_name().is_some_and(|scope_name| {
 3446            settings
 3447                .edit_predictions_disabled_in
 3448                .iter()
 3449                .any(|s| s == scope_name)
 3450        })
 3451    }
 3452
 3453    pub fn set_use_modal_editing(&mut self, to: bool) {
 3454        self.use_modal_editing = to;
 3455    }
 3456
 3457    pub fn use_modal_editing(&self) -> bool {
 3458        self.use_modal_editing
 3459    }
 3460
 3461    fn selections_did_change(
 3462        &mut self,
 3463        local: bool,
 3464        old_cursor_position: &Anchor,
 3465        effects: SelectionEffects,
 3466        window: &mut Window,
 3467        cx: &mut Context<Self>,
 3468    ) {
 3469        window.invalidate_character_coordinates();
 3470
 3471        // Copy selections to primary selection buffer
 3472        #[cfg(any(target_os = "linux", target_os = "freebsd"))]
 3473        if local {
 3474            let selections = self
 3475                .selections
 3476                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 3477            let buffer_handle = self.buffer.read(cx).read(cx);
 3478
 3479            let mut text = String::new();
 3480            for (index, selection) in selections.iter().enumerate() {
 3481                let text_for_selection = buffer_handle
 3482                    .text_for_range(selection.start..selection.end)
 3483                    .collect::<String>();
 3484
 3485                text.push_str(&text_for_selection);
 3486                if index != selections.len() - 1 {
 3487                    text.push('\n');
 3488                }
 3489            }
 3490
 3491            if !text.is_empty() {
 3492                cx.write_to_primary(ClipboardItem::new_string(text));
 3493            }
 3494        }
 3495
 3496        let selection_anchors = self.selections.disjoint_anchors_arc();
 3497
 3498        if self.focus_handle.is_focused(window) && self.leader_id.is_none() {
 3499            self.buffer.update(cx, |buffer, cx| {
 3500                buffer.set_active_selections(
 3501                    &selection_anchors,
 3502                    self.selections.line_mode(),
 3503                    self.cursor_shape,
 3504                    cx,
 3505                )
 3506            });
 3507        }
 3508        let display_map = self
 3509            .display_map
 3510            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3511        let buffer = display_map.buffer_snapshot();
 3512        if self.selections.count() == 1 {
 3513            self.add_selections_state = None;
 3514        }
 3515        self.select_next_state = None;
 3516        self.select_prev_state = None;
 3517        self.select_syntax_node_history.try_clear();
 3518        self.invalidate_autoclose_regions(&selection_anchors, buffer);
 3519        self.snippet_stack.invalidate(&selection_anchors, buffer);
 3520        self.take_rename(false, window, cx);
 3521
 3522        let newest_selection = self.selections.newest_anchor();
 3523        let new_cursor_position = newest_selection.head();
 3524        let selection_start = newest_selection.start;
 3525
 3526        if effects.nav_history.is_none() || effects.nav_history == Some(true) {
 3527            self.push_to_nav_history(
 3528                *old_cursor_position,
 3529                Some(new_cursor_position.to_point(buffer)),
 3530                false,
 3531                effects.nav_history == Some(true),
 3532                cx,
 3533            );
 3534        }
 3535
 3536        if local {
 3537            if let Some(buffer_id) = new_cursor_position.text_anchor.buffer_id {
 3538                self.register_buffer(buffer_id, cx);
 3539            }
 3540
 3541            let mut context_menu = self.context_menu.borrow_mut();
 3542            let completion_menu = match context_menu.as_ref() {
 3543                Some(CodeContextMenu::Completions(menu)) => Some(menu),
 3544                Some(CodeContextMenu::CodeActions(_)) => {
 3545                    *context_menu = None;
 3546                    None
 3547                }
 3548                None => None,
 3549            };
 3550            let completion_position = completion_menu.map(|menu| menu.initial_position);
 3551            drop(context_menu);
 3552
 3553            if effects.completions
 3554                && let Some(completion_position) = completion_position
 3555            {
 3556                let start_offset = selection_start.to_offset(buffer);
 3557                let position_matches = start_offset == completion_position.to_offset(buffer);
 3558                let continue_showing = if let Some((snap, ..)) =
 3559                    buffer.point_to_buffer_offset(completion_position)
 3560                    && !snap.capability.editable()
 3561                {
 3562                    false
 3563                } else if position_matches {
 3564                    if self.snippet_stack.is_empty() {
 3565                        buffer.char_kind_before(start_offset, Some(CharScopeContext::Completion))
 3566                            == Some(CharKind::Word)
 3567                    } else {
 3568                        // Snippet choices can be shown even when the cursor is in whitespace.
 3569                        // Dismissing the menu with actions like backspace is handled by
 3570                        // invalidation regions.
 3571                        true
 3572                    }
 3573                } else {
 3574                    false
 3575                };
 3576
 3577                if continue_showing {
 3578                    self.open_or_update_completions_menu(None, None, false, window, cx);
 3579                } else {
 3580                    self.hide_context_menu(window, cx);
 3581                }
 3582            }
 3583
 3584            hide_hover(self, cx);
 3585
 3586            if old_cursor_position.to_display_point(&display_map).row()
 3587                != new_cursor_position.to_display_point(&display_map).row()
 3588            {
 3589                self.available_code_actions.take();
 3590            }
 3591            self.refresh_code_actions(window, cx);
 3592            self.refresh_document_highlights(cx);
 3593            refresh_linked_ranges(self, window, cx);
 3594
 3595            self.refresh_selected_text_highlights(&display_map, false, window, cx);
 3596            self.refresh_matching_bracket_highlights(&display_map, cx);
 3597            self.refresh_outline_symbols_at_cursor(cx);
 3598            self.update_visible_edit_prediction(window, cx);
 3599            self.edit_prediction_requires_modifier_in_indent_conflict = true;
 3600            self.inline_blame_popover.take();
 3601            if self.git_blame_inline_enabled {
 3602                self.start_inline_blame_timer(window, cx);
 3603            }
 3604        }
 3605
 3606        self.blink_manager.update(cx, BlinkManager::pause_blinking);
 3607
 3608        if local && !self.suppress_selection_callback {
 3609            if let Some(callback) = self.on_local_selections_changed.as_ref() {
 3610                let cursor_position = self.selections.newest::<Point>(&display_map).head();
 3611                callback(cursor_position, window, cx);
 3612            }
 3613        }
 3614
 3615        cx.emit(EditorEvent::SelectionsChanged { local });
 3616
 3617        let selections = &self.selections.disjoint_anchors_arc();
 3618        if selections.len() == 1 {
 3619            cx.emit(SearchEvent::ActiveMatchChanged)
 3620        }
 3621        if local && let Some((_, _, buffer_snapshot)) = buffer.as_singleton() {
 3622            let inmemory_selections = selections
 3623                .iter()
 3624                .map(|s| {
 3625                    text::ToPoint::to_point(&s.range().start.text_anchor, buffer_snapshot)
 3626                        ..text::ToPoint::to_point(&s.range().end.text_anchor, buffer_snapshot)
 3627                })
 3628                .collect();
 3629            self.update_restoration_data(cx, |data| {
 3630                data.selections = inmemory_selections;
 3631            });
 3632
 3633            if WorkspaceSettings::get(None, cx).restore_on_startup
 3634                != RestoreOnStartupBehavior::EmptyTab
 3635                && let Some(workspace_id) = self.workspace_serialization_id(cx)
 3636            {
 3637                let snapshot = self.buffer().read(cx).snapshot(cx);
 3638                let selections = selections.clone();
 3639                let background_executor = cx.background_executor().clone();
 3640                let editor_id = cx.entity().entity_id().as_u64() as ItemId;
 3641                self.serialize_selections = cx.background_spawn(async move {
 3642                    background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3643                    let db_selections = selections
 3644                        .iter()
 3645                        .map(|selection| {
 3646                            (
 3647                                selection.start.to_offset(&snapshot).0,
 3648                                selection.end.to_offset(&snapshot).0,
 3649                            )
 3650                        })
 3651                        .collect();
 3652
 3653                    DB.save_editor_selections(editor_id, workspace_id, db_selections)
 3654                        .await
 3655                        .with_context(|| {
 3656                            format!(
 3657                                "persisting editor selections for editor {editor_id}, \
 3658                                workspace {workspace_id:?}"
 3659                            )
 3660                        })
 3661                        .log_err();
 3662                });
 3663            }
 3664        }
 3665
 3666        cx.notify();
 3667    }
 3668
 3669    fn folds_did_change(&mut self, cx: &mut Context<Self>) {
 3670        use text::ToOffset as _;
 3671        use text::ToPoint as _;
 3672
 3673        if self.mode.is_minimap()
 3674            || WorkspaceSettings::get(None, cx).restore_on_startup
 3675                == RestoreOnStartupBehavior::EmptyTab
 3676        {
 3677            return;
 3678        }
 3679
 3680        if !self.buffer().read(cx).is_singleton() {
 3681            return;
 3682        }
 3683
 3684        let display_snapshot = self
 3685            .display_map
 3686            .update(cx, |display_map, cx| display_map.snapshot(cx));
 3687        let Some((.., snapshot)) = display_snapshot.buffer_snapshot().as_singleton() else {
 3688            return;
 3689        };
 3690        let inmemory_folds = display_snapshot
 3691            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3692            .map(|fold| {
 3693                fold.range.start.text_anchor.to_point(&snapshot)
 3694                    ..fold.range.end.text_anchor.to_point(&snapshot)
 3695            })
 3696            .collect();
 3697        self.update_restoration_data(cx, |data| {
 3698            data.folds = inmemory_folds;
 3699        });
 3700
 3701        let Some(workspace_id) = self.workspace_serialization_id(cx) else {
 3702            return;
 3703        };
 3704
 3705        // Get file path for path-based fold storage (survives tab close)
 3706        let Some(file_path) = self.buffer().read(cx).as_singleton().and_then(|buffer| {
 3707            project::File::from_dyn(buffer.read(cx).file())
 3708                .map(|file| Arc::<Path>::from(file.abs_path(cx)))
 3709        }) else {
 3710            return;
 3711        };
 3712
 3713        let background_executor = cx.background_executor().clone();
 3714        const FINGERPRINT_LEN: usize = 32;
 3715        let db_folds = display_snapshot
 3716            .folds_in_range(MultiBufferOffset(0)..display_snapshot.buffer_snapshot().len())
 3717            .map(|fold| {
 3718                let start = fold.range.start.text_anchor.to_offset(&snapshot);
 3719                let end = fold.range.end.text_anchor.to_offset(&snapshot);
 3720
 3721                // Extract fingerprints - content at fold boundaries for validation on restore
 3722                // Both fingerprints must be INSIDE the fold to avoid capturing surrounding
 3723                // content that might change independently.
 3724                // start_fp: first min(32, fold_len) bytes of fold content
 3725                // end_fp: last min(32, fold_len) bytes of fold content
 3726                // Clip to character boundaries to handle multibyte UTF-8 characters.
 3727                let fold_len = end - start;
 3728                let start_fp_end = snapshot
 3729                    .clip_offset(start + std::cmp::min(FINGERPRINT_LEN, fold_len), Bias::Left);
 3730                let start_fp: String = snapshot.text_for_range(start..start_fp_end).collect();
 3731                let end_fp_start = snapshot
 3732                    .clip_offset(end.saturating_sub(FINGERPRINT_LEN).max(start), Bias::Right);
 3733                let end_fp: String = snapshot.text_for_range(end_fp_start..end).collect();
 3734
 3735                (start, end, start_fp, end_fp)
 3736            })
 3737            .collect::<Vec<_>>();
 3738        self.serialize_folds = cx.background_spawn(async move {
 3739            background_executor.timer(SERIALIZATION_THROTTLE_TIME).await;
 3740            if db_folds.is_empty() {
 3741                // No folds - delete any persisted folds for this file
 3742                DB.delete_file_folds(workspace_id, file_path)
 3743                    .await
 3744                    .with_context(|| format!("deleting file folds for workspace {workspace_id:?}"))
 3745                    .log_err();
 3746            } else {
 3747                DB.save_file_folds(workspace_id, file_path, db_folds)
 3748                    .await
 3749                    .with_context(|| {
 3750                        format!("persisting file folds for workspace {workspace_id:?}")
 3751                    })
 3752                    .log_err();
 3753            }
 3754        });
 3755    }
 3756
 3757    pub fn sync_selections(
 3758        &mut self,
 3759        other: Entity<Editor>,
 3760        cx: &mut Context<Self>,
 3761    ) -> gpui::Subscription {
 3762        let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3763        if !other_selections.is_empty() {
 3764            self.selections
 3765                .change_with(&self.display_snapshot(cx), |selections| {
 3766                    selections.select_anchors(other_selections);
 3767                });
 3768        }
 3769
 3770        let other_subscription = cx.subscribe(&other, |this, other, other_evt, cx| {
 3771            if let EditorEvent::SelectionsChanged { local: true } = other_evt {
 3772                let other_selections = other.read(cx).selections.disjoint_anchors().to_vec();
 3773                if other_selections.is_empty() {
 3774                    return;
 3775                }
 3776                let snapshot = this.display_snapshot(cx);
 3777                this.selections.change_with(&snapshot, |selections| {
 3778                    selections.select_anchors(other_selections);
 3779                });
 3780            }
 3781        });
 3782
 3783        let this_subscription = cx.subscribe_self::<EditorEvent>(move |this, this_evt, cx| {
 3784            if let EditorEvent::SelectionsChanged { local: true } = this_evt {
 3785                let these_selections = this.selections.disjoint_anchors().to_vec();
 3786                if these_selections.is_empty() {
 3787                    return;
 3788                }
 3789                other.update(cx, |other_editor, cx| {
 3790                    let snapshot = other_editor.display_snapshot(cx);
 3791                    other_editor
 3792                        .selections
 3793                        .change_with(&snapshot, |selections| {
 3794                            selections.select_anchors(these_selections);
 3795                        })
 3796                });
 3797            }
 3798        });
 3799
 3800        Subscription::join(other_subscription, this_subscription)
 3801    }
 3802
 3803    fn unfold_buffers_with_selections(&mut self, cx: &mut Context<Self>) {
 3804        if self.buffer().read(cx).is_singleton() {
 3805            return;
 3806        }
 3807        let snapshot = self.buffer.read(cx).snapshot(cx);
 3808        let buffer_ids: HashSet<BufferId> = self
 3809            .selections
 3810            .disjoint_anchor_ranges()
 3811            .flat_map(|range| snapshot.buffer_ids_for_range(range))
 3812            .collect();
 3813        for buffer_id in buffer_ids {
 3814            self.unfold_buffer(buffer_id, cx);
 3815        }
 3816    }
 3817
 3818    /// Changes selections using the provided mutation function. Changes to `self.selections` occur
 3819    /// immediately, but when run within `transact` or `with_selection_effects_deferred` other
 3820    /// effects of selection change occur at the end of the transaction.
 3821    pub fn change_selections<R>(
 3822        &mut self,
 3823        effects: SelectionEffects,
 3824        window: &mut Window,
 3825        cx: &mut Context<Self>,
 3826        change: impl FnOnce(&mut MutableSelectionsCollection<'_, '_>) -> R,
 3827    ) -> R {
 3828        let snapshot = self.display_snapshot(cx);
 3829        if let Some(state) = &mut self.deferred_selection_effects_state {
 3830            state.effects.scroll = effects.scroll.or(state.effects.scroll);
 3831            state.effects.completions = effects.completions;
 3832            state.effects.nav_history = effects.nav_history.or(state.effects.nav_history);
 3833            let (changed, result) = self.selections.change_with(&snapshot, change);
 3834            state.changed |= changed;
 3835            return result;
 3836        }
 3837        let mut state = DeferredSelectionEffectsState {
 3838            changed: false,
 3839            effects,
 3840            old_cursor_position: self.selections.newest_anchor().head(),
 3841            history_entry: SelectionHistoryEntry {
 3842                selections: self.selections.disjoint_anchors_arc(),
 3843                select_next_state: self.select_next_state.clone(),
 3844                select_prev_state: self.select_prev_state.clone(),
 3845                add_selections_state: self.add_selections_state.clone(),
 3846            },
 3847        };
 3848        let (changed, result) = self.selections.change_with(&snapshot, change);
 3849        state.changed = state.changed || changed;
 3850        if self.defer_selection_effects {
 3851            self.deferred_selection_effects_state = Some(state);
 3852        } else {
 3853            self.apply_selection_effects(state, window, cx);
 3854        }
 3855        result
 3856    }
 3857
 3858    /// Defers the effects of selection change, so that the effects of multiple calls to
 3859    /// `change_selections` are applied at the end. This way these intermediate states aren't added
 3860    /// to selection history and the state of popovers based on selection position aren't
 3861    /// erroneously updated.
 3862    pub fn with_selection_effects_deferred<R>(
 3863        &mut self,
 3864        window: &mut Window,
 3865        cx: &mut Context<Self>,
 3866        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>) -> R,
 3867    ) -> R {
 3868        let already_deferred = self.defer_selection_effects;
 3869        self.defer_selection_effects = true;
 3870        let result = update(self, window, cx);
 3871        if !already_deferred {
 3872            self.defer_selection_effects = false;
 3873            if let Some(state) = self.deferred_selection_effects_state.take() {
 3874                self.apply_selection_effects(state, window, cx);
 3875            }
 3876        }
 3877        result
 3878    }
 3879
 3880    fn apply_selection_effects(
 3881        &mut self,
 3882        state: DeferredSelectionEffectsState,
 3883        window: &mut Window,
 3884        cx: &mut Context<Self>,
 3885    ) {
 3886        if state.changed {
 3887            self.selection_history.push(state.history_entry);
 3888
 3889            if let Some(autoscroll) = state.effects.scroll {
 3890                self.request_autoscroll(autoscroll, cx);
 3891            }
 3892
 3893            let old_cursor_position = &state.old_cursor_position;
 3894
 3895            self.selections_did_change(true, old_cursor_position, state.effects, window, cx);
 3896
 3897            if self.should_open_signature_help_automatically(old_cursor_position, cx) {
 3898                self.show_signature_help_auto(window, cx);
 3899            }
 3900        }
 3901    }
 3902
 3903    pub fn edit<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3904    where
 3905        I: IntoIterator<Item = (Range<S>, T)>,
 3906        S: ToOffset,
 3907        T: Into<Arc<str>>,
 3908    {
 3909        if self.read_only(cx) {
 3910            return;
 3911        }
 3912
 3913        self.buffer
 3914            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
 3915    }
 3916
 3917    pub fn edit_with_autoindent<I, S, T>(&mut self, edits: I, cx: &mut Context<Self>)
 3918    where
 3919        I: IntoIterator<Item = (Range<S>, T)>,
 3920        S: ToOffset,
 3921        T: Into<Arc<str>>,
 3922    {
 3923        if self.read_only(cx) {
 3924            return;
 3925        }
 3926
 3927        self.buffer.update(cx, |buffer, cx| {
 3928            buffer.edit(edits, self.autoindent_mode.clone(), cx)
 3929        });
 3930    }
 3931
 3932    pub fn edit_with_block_indent<I, S, T>(
 3933        &mut self,
 3934        edits: I,
 3935        original_indent_columns: Vec<Option<u32>>,
 3936        cx: &mut Context<Self>,
 3937    ) where
 3938        I: IntoIterator<Item = (Range<S>, T)>,
 3939        S: ToOffset,
 3940        T: Into<Arc<str>>,
 3941    {
 3942        if self.read_only(cx) {
 3943            return;
 3944        }
 3945
 3946        self.buffer.update(cx, |buffer, cx| {
 3947            buffer.edit(
 3948                edits,
 3949                Some(AutoindentMode::Block {
 3950                    original_indent_columns,
 3951                }),
 3952                cx,
 3953            )
 3954        });
 3955    }
 3956
 3957    fn select(&mut self, phase: SelectPhase, window: &mut Window, cx: &mut Context<Self>) {
 3958        self.hide_context_menu(window, cx);
 3959
 3960        match phase {
 3961            SelectPhase::Begin {
 3962                position,
 3963                add,
 3964                click_count,
 3965            } => self.begin_selection(position, add, click_count, window, cx),
 3966            SelectPhase::BeginColumnar {
 3967                position,
 3968                goal_column,
 3969                reset,
 3970                mode,
 3971            } => self.begin_columnar_selection(position, goal_column, reset, mode, window, cx),
 3972            SelectPhase::Extend {
 3973                position,
 3974                click_count,
 3975            } => self.extend_selection(position, click_count, window, cx),
 3976            SelectPhase::Update {
 3977                position,
 3978                goal_column,
 3979                scroll_delta,
 3980            } => self.update_selection(position, goal_column, scroll_delta, window, cx),
 3981            SelectPhase::End => self.end_selection(window, cx),
 3982        }
 3983    }
 3984
 3985    fn extend_selection(
 3986        &mut self,
 3987        position: DisplayPoint,
 3988        click_count: usize,
 3989        window: &mut Window,
 3990        cx: &mut Context<Self>,
 3991    ) {
 3992        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 3993        let tail = self
 3994            .selections
 3995            .newest::<MultiBufferOffset>(&display_map)
 3996            .tail();
 3997        let click_count = click_count.max(match self.selections.select_mode() {
 3998            SelectMode::Character => 1,
 3999            SelectMode::Word(_) => 2,
 4000            SelectMode::Line(_) => 3,
 4001            SelectMode::All => 4,
 4002        });
 4003        self.begin_selection(position, false, click_count, window, cx);
 4004
 4005        let tail_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4006
 4007        let current_selection = match self.selections.select_mode() {
 4008            SelectMode::Character | SelectMode::All => tail_anchor..tail_anchor,
 4009            SelectMode::Word(range) | SelectMode::Line(range) => range.clone(),
 4010        };
 4011
 4012        let mut pending_selection = self
 4013            .selections
 4014            .pending_anchor()
 4015            .cloned()
 4016            .expect("extend_selection not called with pending selection");
 4017
 4018        if pending_selection
 4019            .start
 4020            .cmp(&current_selection.start, display_map.buffer_snapshot())
 4021            == Ordering::Greater
 4022        {
 4023            pending_selection.start = current_selection.start;
 4024        }
 4025        if pending_selection
 4026            .end
 4027            .cmp(&current_selection.end, display_map.buffer_snapshot())
 4028            == Ordering::Less
 4029        {
 4030            pending_selection.end = current_selection.end;
 4031            pending_selection.reversed = true;
 4032        }
 4033
 4034        let mut pending_mode = self.selections.pending_mode().unwrap();
 4035        match &mut pending_mode {
 4036            SelectMode::Word(range) | SelectMode::Line(range) => *range = current_selection,
 4037            _ => {}
 4038        }
 4039
 4040        let effects = if EditorSettings::get_global(cx).autoscroll_on_clicks {
 4041            SelectionEffects::scroll(Autoscroll::fit())
 4042        } else {
 4043            SelectionEffects::no_scroll()
 4044        };
 4045
 4046        self.change_selections(effects, window, cx, |s| {
 4047            s.set_pending(pending_selection.clone(), pending_mode);
 4048            s.set_is_extending(true);
 4049        });
 4050    }
 4051
 4052    fn begin_selection(
 4053        &mut self,
 4054        position: DisplayPoint,
 4055        add: bool,
 4056        click_count: usize,
 4057        window: &mut Window,
 4058        cx: &mut Context<Self>,
 4059    ) {
 4060        if !self.focus_handle.is_focused(window) {
 4061            self.last_focused_descendant = None;
 4062            window.focus(&self.focus_handle, cx);
 4063        }
 4064
 4065        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4066        let buffer = display_map.buffer_snapshot();
 4067        let position = display_map.clip_point(position, Bias::Left);
 4068
 4069        let start;
 4070        let end;
 4071        let mode;
 4072        let mut auto_scroll;
 4073        match click_count {
 4074            1 => {
 4075                start = buffer.anchor_before(position.to_point(&display_map));
 4076                end = start;
 4077                mode = SelectMode::Character;
 4078                auto_scroll = true;
 4079            }
 4080            2 => {
 4081                let position = display_map
 4082                    .clip_point(position, Bias::Left)
 4083                    .to_offset(&display_map, Bias::Left);
 4084                let (range, _) = buffer.surrounding_word(position, None);
 4085                start = buffer.anchor_before(range.start);
 4086                end = buffer.anchor_before(range.end);
 4087                mode = SelectMode::Word(start..end);
 4088                auto_scroll = true;
 4089            }
 4090            3 => {
 4091                let position = display_map
 4092                    .clip_point(position, Bias::Left)
 4093                    .to_point(&display_map);
 4094                let line_start = display_map.prev_line_boundary(position).0;
 4095                let next_line_start = buffer.clip_point(
 4096                    display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4097                    Bias::Left,
 4098                );
 4099                start = buffer.anchor_before(line_start);
 4100                end = buffer.anchor_before(next_line_start);
 4101                mode = SelectMode::Line(start..end);
 4102                auto_scroll = true;
 4103            }
 4104            _ => {
 4105                start = buffer.anchor_before(MultiBufferOffset(0));
 4106                end = buffer.anchor_before(buffer.len());
 4107                mode = SelectMode::All;
 4108                auto_scroll = false;
 4109            }
 4110        }
 4111        auto_scroll &= EditorSettings::get_global(cx).autoscroll_on_clicks;
 4112
 4113        let point_to_delete: Option<usize> = {
 4114            let selected_points: Vec<Selection<Point>> =
 4115                self.selections.disjoint_in_range(start..end, &display_map);
 4116
 4117            if !add || click_count > 1 {
 4118                None
 4119            } else if !selected_points.is_empty() {
 4120                Some(selected_points[0].id)
 4121            } else {
 4122                let clicked_point_already_selected =
 4123                    self.selections.disjoint_anchors().iter().find(|selection| {
 4124                        selection.start.to_point(buffer) == start.to_point(buffer)
 4125                            || selection.end.to_point(buffer) == end.to_point(buffer)
 4126                    });
 4127
 4128                clicked_point_already_selected.map(|selection| selection.id)
 4129            }
 4130        };
 4131
 4132        let selections_count = self.selections.count();
 4133        let effects = if auto_scroll {
 4134            SelectionEffects::default()
 4135        } else {
 4136            SelectionEffects::no_scroll()
 4137        };
 4138
 4139        self.change_selections(effects, window, cx, |s| {
 4140            if let Some(point_to_delete) = point_to_delete {
 4141                s.delete(point_to_delete);
 4142
 4143                if selections_count == 1 {
 4144                    s.set_pending_anchor_range(start..end, mode);
 4145                }
 4146            } else {
 4147                if !add {
 4148                    s.clear_disjoint();
 4149                }
 4150
 4151                s.set_pending_anchor_range(start..end, mode);
 4152            }
 4153        });
 4154    }
 4155
 4156    fn begin_columnar_selection(
 4157        &mut self,
 4158        position: DisplayPoint,
 4159        goal_column: u32,
 4160        reset: bool,
 4161        mode: ColumnarMode,
 4162        window: &mut Window,
 4163        cx: &mut Context<Self>,
 4164    ) {
 4165        if !self.focus_handle.is_focused(window) {
 4166            self.last_focused_descendant = None;
 4167            window.focus(&self.focus_handle, cx);
 4168        }
 4169
 4170        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4171
 4172        if reset {
 4173            let pointer_position = display_map
 4174                .buffer_snapshot()
 4175                .anchor_before(position.to_point(&display_map));
 4176
 4177            self.change_selections(
 4178                SelectionEffects::scroll(Autoscroll::newest()),
 4179                window,
 4180                cx,
 4181                |s| {
 4182                    s.clear_disjoint();
 4183                    s.set_pending_anchor_range(
 4184                        pointer_position..pointer_position,
 4185                        SelectMode::Character,
 4186                    );
 4187                },
 4188            );
 4189        };
 4190
 4191        let tail = self.selections.newest::<Point>(&display_map).tail();
 4192        let selection_anchor = display_map.buffer_snapshot().anchor_before(tail);
 4193        self.columnar_selection_state = match mode {
 4194            ColumnarMode::FromMouse => Some(ColumnarSelectionState::FromMouse {
 4195                selection_tail: selection_anchor,
 4196                display_point: if reset {
 4197                    if position.column() != goal_column {
 4198                        Some(DisplayPoint::new(position.row(), goal_column))
 4199                    } else {
 4200                        None
 4201                    }
 4202                } else {
 4203                    None
 4204                },
 4205            }),
 4206            ColumnarMode::FromSelection => Some(ColumnarSelectionState::FromSelection {
 4207                selection_tail: selection_anchor,
 4208            }),
 4209        };
 4210
 4211        if !reset {
 4212            self.select_columns(position, goal_column, &display_map, window, cx);
 4213        }
 4214    }
 4215
 4216    fn update_selection(
 4217        &mut self,
 4218        position: DisplayPoint,
 4219        goal_column: u32,
 4220        scroll_delta: gpui::Point<f32>,
 4221        window: &mut Window,
 4222        cx: &mut Context<Self>,
 4223    ) {
 4224        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 4225
 4226        if self.columnar_selection_state.is_some() {
 4227            self.select_columns(position, goal_column, &display_map, window, cx);
 4228        } else if let Some(mut pending) = self.selections.pending_anchor().cloned() {
 4229            let buffer = display_map.buffer_snapshot();
 4230            let head;
 4231            let tail;
 4232            let mode = self.selections.pending_mode().unwrap();
 4233            match &mode {
 4234                SelectMode::Character => {
 4235                    head = position.to_point(&display_map);
 4236                    tail = pending.tail().to_point(buffer);
 4237                }
 4238                SelectMode::Word(original_range) => {
 4239                    let offset = display_map
 4240                        .clip_point(position, Bias::Left)
 4241                        .to_offset(&display_map, Bias::Left);
 4242                    let original_range = original_range.to_offset(buffer);
 4243
 4244                    let head_offset = if buffer.is_inside_word(offset, None)
 4245                        || original_range.contains(&offset)
 4246                    {
 4247                        let (word_range, _) = buffer.surrounding_word(offset, None);
 4248                        if word_range.start < original_range.start {
 4249                            word_range.start
 4250                        } else {
 4251                            word_range.end
 4252                        }
 4253                    } else {
 4254                        offset
 4255                    };
 4256
 4257                    head = head_offset.to_point(buffer);
 4258                    if head_offset <= original_range.start {
 4259                        tail = original_range.end.to_point(buffer);
 4260                    } else {
 4261                        tail = original_range.start.to_point(buffer);
 4262                    }
 4263                }
 4264                SelectMode::Line(original_range) => {
 4265                    let original_range = original_range.to_point(display_map.buffer_snapshot());
 4266
 4267                    let position = display_map
 4268                        .clip_point(position, Bias::Left)
 4269                        .to_point(&display_map);
 4270                    let line_start = display_map.prev_line_boundary(position).0;
 4271                    let next_line_start = buffer.clip_point(
 4272                        display_map.next_line_boundary(position).0 + Point::new(1, 0),
 4273                        Bias::Left,
 4274                    );
 4275
 4276                    if line_start < original_range.start {
 4277                        head = line_start
 4278                    } else {
 4279                        head = next_line_start
 4280                    }
 4281
 4282                    if head <= original_range.start {
 4283                        tail = original_range.end;
 4284                    } else {
 4285                        tail = original_range.start;
 4286                    }
 4287                }
 4288                SelectMode::All => {
 4289                    return;
 4290                }
 4291            };
 4292
 4293            if head < tail {
 4294                pending.start = buffer.anchor_before(head);
 4295                pending.end = buffer.anchor_before(tail);
 4296                pending.reversed = true;
 4297            } else {
 4298                pending.start = buffer.anchor_before(tail);
 4299                pending.end = buffer.anchor_before(head);
 4300                pending.reversed = false;
 4301            }
 4302
 4303            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4304                s.set_pending(pending.clone(), mode);
 4305            });
 4306        } else {
 4307            log::error!("update_selection dispatched with no pending selection");
 4308            return;
 4309        }
 4310
 4311        self.apply_scroll_delta(scroll_delta, window, cx);
 4312        cx.notify();
 4313    }
 4314
 4315    fn end_selection(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 4316        self.columnar_selection_state.take();
 4317        if let Some(pending_mode) = self.selections.pending_mode() {
 4318            let selections = self
 4319                .selections
 4320                .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 4321            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4322                s.select(selections);
 4323                s.clear_pending();
 4324                if s.is_extending() {
 4325                    s.set_is_extending(false);
 4326                } else {
 4327                    s.set_select_mode(pending_mode);
 4328                }
 4329            });
 4330        }
 4331    }
 4332
 4333    fn select_columns(
 4334        &mut self,
 4335        head: DisplayPoint,
 4336        goal_column: u32,
 4337        display_map: &DisplaySnapshot,
 4338        window: &mut Window,
 4339        cx: &mut Context<Self>,
 4340    ) {
 4341        let Some(columnar_state) = self.columnar_selection_state.as_ref() else {
 4342            return;
 4343        };
 4344
 4345        let tail = match columnar_state {
 4346            ColumnarSelectionState::FromMouse {
 4347                selection_tail,
 4348                display_point,
 4349            } => display_point.unwrap_or_else(|| selection_tail.to_display_point(display_map)),
 4350            ColumnarSelectionState::FromSelection { selection_tail } => {
 4351                selection_tail.to_display_point(display_map)
 4352            }
 4353        };
 4354
 4355        let start_row = cmp::min(tail.row(), head.row());
 4356        let end_row = cmp::max(tail.row(), head.row());
 4357        let start_column = cmp::min(tail.column(), goal_column);
 4358        let end_column = cmp::max(tail.column(), goal_column);
 4359        let reversed = start_column < tail.column();
 4360
 4361        let selection_ranges = (start_row.0..=end_row.0)
 4362            .map(DisplayRow)
 4363            .filter_map(|row| {
 4364                if (matches!(columnar_state, ColumnarSelectionState::FromMouse { .. })
 4365                    || start_column <= display_map.line_len(row))
 4366                    && !display_map.is_block_line(row)
 4367                {
 4368                    let start = display_map
 4369                        .clip_point(DisplayPoint::new(row, start_column), Bias::Left)
 4370                        .to_point(display_map);
 4371                    let end = display_map
 4372                        .clip_point(DisplayPoint::new(row, end_column), Bias::Right)
 4373                        .to_point(display_map);
 4374                    if reversed {
 4375                        Some(end..start)
 4376                    } else {
 4377                        Some(start..end)
 4378                    }
 4379                } else {
 4380                    None
 4381                }
 4382            })
 4383            .collect::<Vec<_>>();
 4384        if selection_ranges.is_empty() {
 4385            return;
 4386        }
 4387
 4388        let ranges = match columnar_state {
 4389            ColumnarSelectionState::FromMouse { .. } => {
 4390                let mut non_empty_ranges = selection_ranges
 4391                    .iter()
 4392                    .filter(|selection_range| selection_range.start != selection_range.end)
 4393                    .peekable();
 4394                if non_empty_ranges.peek().is_some() {
 4395                    non_empty_ranges.cloned().collect()
 4396                } else {
 4397                    selection_ranges
 4398                }
 4399            }
 4400            _ => selection_ranges,
 4401        };
 4402
 4403        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 4404            s.select_ranges(ranges);
 4405        });
 4406        cx.notify();
 4407    }
 4408
 4409    pub fn has_non_empty_selection(&self, snapshot: &DisplaySnapshot) -> bool {
 4410        self.selections
 4411            .all_adjusted(snapshot)
 4412            .iter()
 4413            .any(|selection| !selection.is_empty())
 4414    }
 4415
 4416    pub fn has_pending_nonempty_selection(&self) -> bool {
 4417        let pending_nonempty_selection = match self.selections.pending_anchor() {
 4418            Some(Selection { start, end, .. }) => start != end,
 4419            None => false,
 4420        };
 4421
 4422        pending_nonempty_selection
 4423            || (self.columnar_selection_state.is_some()
 4424                && self.selections.disjoint_anchors().len() > 1)
 4425    }
 4426
 4427    pub fn has_pending_selection(&self) -> bool {
 4428        self.selections.pending_anchor().is_some() || self.columnar_selection_state.is_some()
 4429    }
 4430
 4431    pub fn cancel(&mut self, _: &Cancel, window: &mut Window, cx: &mut Context<Self>) {
 4432        self.selection_mark_mode = false;
 4433        self.selection_drag_state = SelectionDragState::None;
 4434
 4435        if self.dismiss_menus_and_popups(true, window, cx) {
 4436            cx.notify();
 4437            return;
 4438        }
 4439        if self.clear_expanded_diff_hunks(cx) {
 4440            cx.notify();
 4441            return;
 4442        }
 4443        if self.show_git_blame_gutter {
 4444            self.show_git_blame_gutter = false;
 4445            cx.notify();
 4446            return;
 4447        }
 4448
 4449        if self.mode.is_full()
 4450            && self.change_selections(Default::default(), window, cx, |s| s.try_cancel())
 4451        {
 4452            cx.notify();
 4453            return;
 4454        }
 4455
 4456        cx.propagate();
 4457    }
 4458
 4459    pub fn dismiss_menus_and_popups(
 4460        &mut self,
 4461        is_user_requested: bool,
 4462        window: &mut Window,
 4463        cx: &mut Context<Self>,
 4464    ) -> bool {
 4465        let mut dismissed = false;
 4466
 4467        dismissed |= self.take_rename(false, window, cx).is_some();
 4468        dismissed |= self.hide_blame_popover(true, cx);
 4469        dismissed |= hide_hover(self, cx);
 4470        dismissed |= self.hide_signature_help(cx, SignatureHelpHiddenBy::Escape);
 4471        dismissed |= self.hide_context_menu(window, cx).is_some();
 4472        dismissed |= self.mouse_context_menu.take().is_some();
 4473        dismissed |= is_user_requested
 4474            && self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 4475        dismissed |= self.snippet_stack.pop().is_some();
 4476        if self.diff_review_drag_state.is_some() {
 4477            self.cancel_diff_review_drag(cx);
 4478            dismissed = true;
 4479        }
 4480        if !self.diff_review_overlays.is_empty() {
 4481            self.dismiss_all_diff_review_overlays(cx);
 4482            dismissed = true;
 4483        }
 4484
 4485        if self.mode.is_full() && matches!(self.active_diagnostics, ActiveDiagnostic::Group(_)) {
 4486            self.dismiss_diagnostics(cx);
 4487            dismissed = true;
 4488        }
 4489
 4490        dismissed
 4491    }
 4492
 4493    fn linked_editing_ranges_for(
 4494        &self,
 4495        selection: Range<text::Anchor>,
 4496        cx: &App,
 4497    ) -> Option<HashMap<Entity<Buffer>, Vec<Range<text::Anchor>>>> {
 4498        if self.linked_edit_ranges.is_empty() {
 4499            return None;
 4500        }
 4501        let ((base_range, linked_ranges), buffer_snapshot, buffer) =
 4502            selection.end.buffer_id.and_then(|end_buffer_id| {
 4503                if selection.start.buffer_id != Some(end_buffer_id) {
 4504                    return None;
 4505                }
 4506                let buffer = self.buffer.read(cx).buffer(end_buffer_id)?;
 4507                let snapshot = buffer.read(cx).snapshot();
 4508                self.linked_edit_ranges
 4509                    .get(end_buffer_id, selection.start..selection.end, &snapshot)
 4510                    .map(|ranges| (ranges, snapshot, buffer))
 4511            })?;
 4512        use text::ToOffset as TO;
 4513        // find offset from the start of current range to current cursor position
 4514        let start_byte_offset = TO::to_offset(&base_range.start, &buffer_snapshot);
 4515
 4516        let start_offset = TO::to_offset(&selection.start, &buffer_snapshot);
 4517        let start_difference = start_offset - start_byte_offset;
 4518        let end_offset = TO::to_offset(&selection.end, &buffer_snapshot);
 4519        let end_difference = end_offset - start_byte_offset;
 4520
 4521        // Current range has associated linked ranges.
 4522        let mut linked_edits = HashMap::<_, Vec<_>>::default();
 4523        for range in linked_ranges.iter() {
 4524            let start_offset = TO::to_offset(&range.start, &buffer_snapshot);
 4525            let end_offset = start_offset + end_difference;
 4526            let start_offset = start_offset + start_difference;
 4527            if start_offset > buffer_snapshot.len() || end_offset > buffer_snapshot.len() {
 4528                continue;
 4529            }
 4530            if self.selections.disjoint_anchor_ranges().any(|s| {
 4531                if s.start.text_anchor.buffer_id != selection.start.buffer_id
 4532                    || s.end.text_anchor.buffer_id != selection.end.buffer_id
 4533                {
 4534                    return false;
 4535                }
 4536                TO::to_offset(&s.start.text_anchor, &buffer_snapshot) <= end_offset
 4537                    && TO::to_offset(&s.end.text_anchor, &buffer_snapshot) >= start_offset
 4538            }) {
 4539                continue;
 4540            }
 4541            let start = buffer_snapshot.anchor_after(start_offset);
 4542            let end = buffer_snapshot.anchor_after(end_offset);
 4543            linked_edits
 4544                .entry(buffer.clone())
 4545                .or_default()
 4546                .push(start..end);
 4547        }
 4548        Some(linked_edits)
 4549    }
 4550
 4551    pub fn handle_input(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 4552        let text: Arc<str> = text.into();
 4553
 4554        if self.read_only(cx) {
 4555            return;
 4556        }
 4557
 4558        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 4559
 4560        self.unfold_buffers_with_selections(cx);
 4561
 4562        let selections = self.selections.all_adjusted(&self.display_snapshot(cx));
 4563        let mut bracket_inserted = false;
 4564        let mut edits = Vec::new();
 4565        let mut linked_edits = LinkedEdits::new();
 4566        let mut new_selections = Vec::with_capacity(selections.len());
 4567        let mut new_autoclose_regions = Vec::new();
 4568        let snapshot = self.buffer.read(cx).read(cx);
 4569        let mut clear_linked_edit_ranges = false;
 4570        let mut all_selections_read_only = true;
 4571        let mut has_adjacent_edits = false;
 4572        let mut in_adjacent_group = false;
 4573
 4574        let mut regions = self
 4575            .selections_with_autoclose_regions(selections, &snapshot)
 4576            .peekable();
 4577
 4578        while let Some((selection, autoclose_region)) = regions.next() {
 4579            if snapshot
 4580                .point_to_buffer_point(selection.head())
 4581                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4582            {
 4583                continue;
 4584            }
 4585            if snapshot
 4586                .point_to_buffer_point(selection.tail())
 4587                .is_none_or(|(snapshot, ..)| !snapshot.capability.editable())
 4588            {
 4589                // note, ideally we'd clip the tail to the closest writeable region towards the head
 4590                continue;
 4591            }
 4592            all_selections_read_only = false;
 4593
 4594            if let Some(scope) = snapshot.language_scope_at(selection.head()) {
 4595                // Determine if the inserted text matches the opening or closing
 4596                // bracket of any of this language's bracket pairs.
 4597                let mut bracket_pair = None;
 4598                let mut is_bracket_pair_start = false;
 4599                let mut is_bracket_pair_end = false;
 4600                if !text.is_empty() {
 4601                    let mut bracket_pair_matching_end = None;
 4602                    // `text` can be empty when a user is using IME (e.g. Chinese Wubi Simplified)
 4603                    //  and they are removing the character that triggered IME popup.
 4604                    for (pair, enabled) in scope.brackets() {
 4605                        if !pair.close && !pair.surround {
 4606                            continue;
 4607                        }
 4608
 4609                        if enabled && pair.start.ends_with(text.as_ref()) {
 4610                            let prefix_len = pair.start.len() - text.len();
 4611                            let preceding_text_matches_prefix = prefix_len == 0
 4612                                || (selection.start.column >= (prefix_len as u32)
 4613                                    && snapshot.contains_str_at(
 4614                                        Point::new(
 4615                                            selection.start.row,
 4616                                            selection.start.column - (prefix_len as u32),
 4617                                        ),
 4618                                        &pair.start[..prefix_len],
 4619                                    ));
 4620                            if preceding_text_matches_prefix {
 4621                                bracket_pair = Some(pair.clone());
 4622                                is_bracket_pair_start = true;
 4623                                break;
 4624                            }
 4625                        }
 4626                        if pair.end.as_str() == text.as_ref() && bracket_pair_matching_end.is_none()
 4627                        {
 4628                            // take first bracket pair matching end, but don't break in case a later bracket
 4629                            // pair matches start
 4630                            bracket_pair_matching_end = Some(pair.clone());
 4631                        }
 4632                    }
 4633                    if let Some(end) = bracket_pair_matching_end
 4634                        && bracket_pair.is_none()
 4635                    {
 4636                        bracket_pair = Some(end);
 4637                        is_bracket_pair_end = true;
 4638                    }
 4639                }
 4640
 4641                if let Some(bracket_pair) = bracket_pair {
 4642                    let snapshot_settings = snapshot.language_settings_at(selection.start, cx);
 4643                    let autoclose = self.use_autoclose && snapshot_settings.use_autoclose;
 4644                    let auto_surround =
 4645                        self.use_auto_surround && snapshot_settings.use_auto_surround;
 4646                    if selection.is_empty() {
 4647                        if is_bracket_pair_start {
 4648                            // If the inserted text is a suffix of an opening bracket and the
 4649                            // selection is preceded by the rest of the opening bracket, then
 4650                            // insert the closing bracket.
 4651                            let following_text_allows_autoclose = snapshot
 4652                                .chars_at(selection.start)
 4653                                .next()
 4654                                .is_none_or(|c| scope.should_autoclose_before(c));
 4655
 4656                            let preceding_text_allows_autoclose = selection.start.column == 0
 4657                                || snapshot
 4658                                    .reversed_chars_at(selection.start)
 4659                                    .next()
 4660                                    .is_none_or(|c| {
 4661                                        bracket_pair.start != bracket_pair.end
 4662                                            || !snapshot
 4663                                                .char_classifier_at(selection.start)
 4664                                                .is_word(c)
 4665                                    });
 4666
 4667                            let is_closing_quote = if bracket_pair.end == bracket_pair.start
 4668                                && bracket_pair.start.len() == 1
 4669                            {
 4670                                let target = bracket_pair.start.chars().next().unwrap();
 4671                                let mut byte_offset = 0u32;
 4672                                let current_line_count = snapshot
 4673                                    .reversed_chars_at(selection.start)
 4674                                    .take_while(|&c| c != '\n')
 4675                                    .filter(|c| {
 4676                                        byte_offset += c.len_utf8() as u32;
 4677                                        if *c != target {
 4678                                            return false;
 4679                                        }
 4680
 4681                                        let point = Point::new(
 4682                                            selection.start.row,
 4683                                            selection.start.column.saturating_sub(byte_offset),
 4684                                        );
 4685
 4686                                        let is_enabled = snapshot
 4687                                            .language_scope_at(point)
 4688                                            .and_then(|scope| {
 4689                                                scope
 4690                                                    .brackets()
 4691                                                    .find(|(pair, _)| {
 4692                                                        pair.start == bracket_pair.start
 4693                                                    })
 4694                                                    .map(|(_, enabled)| enabled)
 4695                                            })
 4696                                            .unwrap_or(true);
 4697
 4698                                        let is_delimiter = snapshot
 4699                                            .language_scope_at(Point::new(
 4700                                                point.row,
 4701                                                point.column + 1,
 4702                                            ))
 4703                                            .and_then(|scope| {
 4704                                                scope
 4705                                                    .brackets()
 4706                                                    .find(|(pair, _)| {
 4707                                                        pair.start == bracket_pair.start
 4708                                                    })
 4709                                                    .map(|(_, enabled)| !enabled)
 4710                                            })
 4711                                            .unwrap_or(false);
 4712
 4713                                        is_enabled && !is_delimiter
 4714                                    })
 4715                                    .count();
 4716                                current_line_count % 2 == 1
 4717                            } else {
 4718                                false
 4719                            };
 4720
 4721                            if autoclose
 4722                                && bracket_pair.close
 4723                                && following_text_allows_autoclose
 4724                                && preceding_text_allows_autoclose
 4725                                && !is_closing_quote
 4726                            {
 4727                                let anchor = snapshot.anchor_before(selection.end);
 4728                                new_selections.push((selection.map(|_| anchor), text.len()));
 4729                                new_autoclose_regions.push((
 4730                                    anchor,
 4731                                    text.len(),
 4732                                    selection.id,
 4733                                    bracket_pair.clone(),
 4734                                ));
 4735                                edits.push((
 4736                                    selection.range(),
 4737                                    format!("{}{}", text, bracket_pair.end).into(),
 4738                                ));
 4739                                bracket_inserted = true;
 4740                                continue;
 4741                            }
 4742                        }
 4743
 4744                        if let Some(region) = autoclose_region {
 4745                            // If the selection is followed by an auto-inserted closing bracket,
 4746                            // then don't insert that closing bracket again; just move the selection
 4747                            // past the closing bracket.
 4748                            let should_skip = selection.end == region.range.end.to_point(&snapshot)
 4749                                && text.as_ref() == region.pair.end.as_str()
 4750                                && snapshot.contains_str_at(region.range.end, text.as_ref());
 4751                            if should_skip {
 4752                                let anchor = snapshot.anchor_after(selection.end);
 4753                                new_selections
 4754                                    .push((selection.map(|_| anchor), region.pair.end.len()));
 4755                                continue;
 4756                            }
 4757                        }
 4758
 4759                        let always_treat_brackets_as_autoclosed = snapshot
 4760                            .language_settings_at(selection.start, cx)
 4761                            .always_treat_brackets_as_autoclosed;
 4762                        if always_treat_brackets_as_autoclosed
 4763                            && is_bracket_pair_end
 4764                            && snapshot.contains_str_at(selection.end, text.as_ref())
 4765                        {
 4766                            // Otherwise, when `always_treat_brackets_as_autoclosed` is set to `true
 4767                            // and the inserted text is a closing bracket and the selection is followed
 4768                            // by the closing bracket then move the selection past the closing bracket.
 4769                            let anchor = snapshot.anchor_after(selection.end);
 4770                            new_selections.push((selection.map(|_| anchor), text.len()));
 4771                            continue;
 4772                        }
 4773                    }
 4774                    // If an opening bracket is 1 character long and is typed while
 4775                    // text is selected, then surround that text with the bracket pair.
 4776                    else if auto_surround
 4777                        && bracket_pair.surround
 4778                        && is_bracket_pair_start
 4779                        && bracket_pair.start.chars().count() == 1
 4780                    {
 4781                        edits.push((selection.start..selection.start, text.clone()));
 4782                        edits.push((
 4783                            selection.end..selection.end,
 4784                            bracket_pair.end.as_str().into(),
 4785                        ));
 4786                        bracket_inserted = true;
 4787                        new_selections.push((
 4788                            Selection {
 4789                                id: selection.id,
 4790                                start: snapshot.anchor_after(selection.start),
 4791                                end: snapshot.anchor_before(selection.end),
 4792                                reversed: selection.reversed,
 4793                                goal: selection.goal,
 4794                            },
 4795                            0,
 4796                        ));
 4797                        continue;
 4798                    }
 4799                }
 4800            }
 4801
 4802            if self.auto_replace_emoji_shortcode
 4803                && selection.is_empty()
 4804                && text.as_ref().ends_with(':')
 4805                && let Some(possible_emoji_short_code) =
 4806                    Self::find_possible_emoji_shortcode_at_position(&snapshot, selection.start)
 4807                && !possible_emoji_short_code.is_empty()
 4808                && let Some(emoji) = emojis::get_by_shortcode(&possible_emoji_short_code)
 4809            {
 4810                let emoji_shortcode_start = Point::new(
 4811                    selection.start.row,
 4812                    selection.start.column - possible_emoji_short_code.len() as u32 - 1,
 4813                );
 4814
 4815                // Remove shortcode from buffer
 4816                edits.push((
 4817                    emoji_shortcode_start..selection.start,
 4818                    "".to_string().into(),
 4819                ));
 4820                new_selections.push((
 4821                    Selection {
 4822                        id: selection.id,
 4823                        start: snapshot.anchor_after(emoji_shortcode_start),
 4824                        end: snapshot.anchor_before(selection.start),
 4825                        reversed: selection.reversed,
 4826                        goal: selection.goal,
 4827                    },
 4828                    0,
 4829                ));
 4830
 4831                // Insert emoji
 4832                let selection_start_anchor = snapshot.anchor_after(selection.start);
 4833                new_selections.push((selection.map(|_| selection_start_anchor), 0));
 4834                edits.push((selection.start..selection.end, emoji.to_string().into()));
 4835
 4836                continue;
 4837            }
 4838
 4839            let next_is_adjacent = regions
 4840                .peek()
 4841                .is_some_and(|(next, _)| selection.end == next.start);
 4842
 4843            // If not handling any auto-close operation, then just replace the selected
 4844            // text with the given input and move the selection to the end of the
 4845            // newly inserted text.
 4846            let anchor = if in_adjacent_group || next_is_adjacent {
 4847                // After edits the right bias would shift those anchor to the next visible fragment
 4848                // but we want to resolve to the previous one
 4849                snapshot.anchor_before(selection.end)
 4850            } else {
 4851                snapshot.anchor_after(selection.end)
 4852            };
 4853
 4854            if !self.linked_edit_ranges.is_empty() {
 4855                let start_anchor = snapshot.anchor_before(selection.start);
 4856
 4857                let is_word_char = text.chars().next().is_none_or(|char| {
 4858                    let classifier = snapshot
 4859                        .char_classifier_at(start_anchor.to_offset(&snapshot))
 4860                        .scope_context(Some(CharScopeContext::LinkedEdit));
 4861                    classifier.is_word(char)
 4862                });
 4863                let is_dot = text.as_ref() == ".";
 4864                let should_apply_linked_edit = is_word_char || is_dot;
 4865
 4866                if should_apply_linked_edit {
 4867                    let anchor_range = start_anchor.text_anchor..anchor.text_anchor;
 4868                    linked_edits.push(&self, anchor_range, text.clone(), cx);
 4869                } else {
 4870                    clear_linked_edit_ranges = true;
 4871                }
 4872            }
 4873
 4874            new_selections.push((selection.map(|_| anchor), 0));
 4875            edits.push((selection.start..selection.end, text.clone()));
 4876
 4877            has_adjacent_edits |= next_is_adjacent;
 4878            in_adjacent_group = next_is_adjacent;
 4879        }
 4880
 4881        if all_selections_read_only {
 4882            return;
 4883        }
 4884
 4885        drop(regions);
 4886        drop(snapshot);
 4887
 4888        self.transact(window, cx, |this, window, cx| {
 4889            if clear_linked_edit_ranges {
 4890                this.linked_edit_ranges.clear();
 4891            }
 4892            let initial_buffer_versions =
 4893                jsx_tag_auto_close::construct_initial_buffer_versions_map(this, &edits, cx);
 4894
 4895            this.buffer.update(cx, |buffer, cx| {
 4896                if has_adjacent_edits {
 4897                    buffer.edit_non_coalesce(edits, this.autoindent_mode.clone(), cx);
 4898                } else {
 4899                    buffer.edit(edits, this.autoindent_mode.clone(), cx);
 4900                }
 4901            });
 4902            linked_edits.apply(cx);
 4903            let new_anchor_selections = new_selections.iter().map(|e| &e.0);
 4904            let new_selection_deltas = new_selections.iter().map(|e| e.1);
 4905            let map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
 4906            let new_selections = resolve_selections_wrapping_blocks::<MultiBufferOffset, _>(
 4907                new_anchor_selections,
 4908                &map,
 4909            )
 4910            .zip(new_selection_deltas)
 4911            .map(|(selection, delta)| Selection {
 4912                id: selection.id,
 4913                start: selection.start + delta,
 4914                end: selection.end + delta,
 4915                reversed: selection.reversed,
 4916                goal: SelectionGoal::None,
 4917            })
 4918            .collect::<Vec<_>>();
 4919
 4920            let mut i = 0;
 4921            for (position, delta, selection_id, pair) in new_autoclose_regions {
 4922                let position = position.to_offset(map.buffer_snapshot()) + delta;
 4923                let start = map.buffer_snapshot().anchor_before(position);
 4924                let end = map.buffer_snapshot().anchor_after(position);
 4925                while let Some(existing_state) = this.autoclose_regions.get(i) {
 4926                    match existing_state
 4927                        .range
 4928                        .start
 4929                        .cmp(&start, map.buffer_snapshot())
 4930                    {
 4931                        Ordering::Less => i += 1,
 4932                        Ordering::Greater => break,
 4933                        Ordering::Equal => {
 4934                            match end.cmp(&existing_state.range.end, map.buffer_snapshot()) {
 4935                                Ordering::Less => i += 1,
 4936                                Ordering::Equal => break,
 4937                                Ordering::Greater => break,
 4938                            }
 4939                        }
 4940                    }
 4941                }
 4942                this.autoclose_regions.insert(
 4943                    i,
 4944                    AutocloseRegion {
 4945                        selection_id,
 4946                        range: start..end,
 4947                        pair,
 4948                    },
 4949                );
 4950            }
 4951
 4952            let had_active_edit_prediction = this.has_active_edit_prediction();
 4953            this.change_selections(
 4954                SelectionEffects::scroll(Autoscroll::fit()).completions(false),
 4955                window,
 4956                cx,
 4957                |s| s.select(new_selections),
 4958            );
 4959
 4960            if !bracket_inserted
 4961                && let Some(on_type_format_task) =
 4962                    this.trigger_on_type_formatting(text.to_string(), window, cx)
 4963            {
 4964                on_type_format_task.detach_and_log_err(cx);
 4965            }
 4966
 4967            let editor_settings = EditorSettings::get_global(cx);
 4968            if bracket_inserted
 4969                && (editor_settings.auto_signature_help
 4970                    || editor_settings.show_signature_help_after_edits)
 4971            {
 4972                this.show_signature_help(&ShowSignatureHelp, window, cx);
 4973            }
 4974
 4975            let trigger_in_words =
 4976                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
 4977            if this.hard_wrap.is_some() {
 4978                let latest: Range<Point> = this.selections.newest(&map).range();
 4979                if latest.is_empty()
 4980                    && this
 4981                        .buffer()
 4982                        .read(cx)
 4983                        .snapshot(cx)
 4984                        .line_len(MultiBufferRow(latest.start.row))
 4985                        == latest.start.column
 4986                {
 4987                    this.rewrap_impl(
 4988                        RewrapOptions {
 4989                            override_language_settings: true,
 4990                            preserve_existing_whitespace: true,
 4991                        },
 4992                        cx,
 4993                    )
 4994                }
 4995            }
 4996            this.trigger_completion_on_input(&text, trigger_in_words, window, cx);
 4997            refresh_linked_ranges(this, window, cx);
 4998            this.refresh_edit_prediction(true, false, window, cx);
 4999            jsx_tag_auto_close::handle_from(this, initial_buffer_versions, window, cx);
 5000        });
 5001    }
 5002
 5003    fn find_possible_emoji_shortcode_at_position(
 5004        snapshot: &MultiBufferSnapshot,
 5005        position: Point,
 5006    ) -> Option<String> {
 5007        let mut chars = Vec::new();
 5008        let mut found_colon = false;
 5009        for char in snapshot.reversed_chars_at(position).take(100) {
 5010            // Found a possible emoji shortcode in the middle of the buffer
 5011            if found_colon {
 5012                if char.is_whitespace() {
 5013                    chars.reverse();
 5014                    return Some(chars.iter().collect());
 5015                }
 5016                // If the previous character is not a whitespace, we are in the middle of a word
 5017                // and we only want to complete the shortcode if the word is made up of other emojis
 5018                let mut containing_word = String::new();
 5019                for ch in snapshot
 5020                    .reversed_chars_at(position)
 5021                    .skip(chars.len() + 1)
 5022                    .take(100)
 5023                {
 5024                    if ch.is_whitespace() {
 5025                        break;
 5026                    }
 5027                    containing_word.push(ch);
 5028                }
 5029                let containing_word = containing_word.chars().rev().collect::<String>();
 5030                if util::word_consists_of_emojis(containing_word.as_str()) {
 5031                    chars.reverse();
 5032                    return Some(chars.iter().collect());
 5033                }
 5034            }
 5035
 5036            if char.is_whitespace() || !char.is_ascii() {
 5037                return None;
 5038            }
 5039            if char == ':' {
 5040                found_colon = true;
 5041            } else {
 5042                chars.push(char);
 5043            }
 5044        }
 5045        // Found a possible emoji shortcode at the beginning of the buffer
 5046        chars.reverse();
 5047        Some(chars.iter().collect())
 5048    }
 5049
 5050    pub fn newline(&mut self, _: &Newline, window: &mut Window, cx: &mut Context<Self>) {
 5051        if self.read_only(cx) {
 5052            return;
 5053        }
 5054
 5055        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5056        self.transact(window, cx, |this, window, cx| {
 5057            let (edits_with_flags, selection_info): (Vec<_>, Vec<_>) = {
 5058                let selections = this
 5059                    .selections
 5060                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
 5061                let multi_buffer = this.buffer.read(cx);
 5062                let buffer = multi_buffer.snapshot(cx);
 5063                selections
 5064                    .iter()
 5065                    .map(|selection| {
 5066                        let start_point = selection.start.to_point(&buffer);
 5067                        let mut existing_indent =
 5068                            buffer.indent_size_for_line(MultiBufferRow(start_point.row));
 5069                        existing_indent.len = cmp::min(existing_indent.len, start_point.column);
 5070                        let start = selection.start;
 5071                        let end = selection.end;
 5072                        let selection_is_empty = start == end;
 5073                        let language_scope = buffer.language_scope_at(start);
 5074                        let (delimiter, newline_config) = if let Some(language) = &language_scope {
 5075                            let needs_extra_newline = NewlineConfig::insert_extra_newline_brackets(
 5076                                &buffer,
 5077                                start..end,
 5078                                language,
 5079                            )
 5080                                || NewlineConfig::insert_extra_newline_tree_sitter(
 5081                                    &buffer,
 5082                                    start..end,
 5083                                );
 5084
 5085                            let mut newline_config = NewlineConfig::Newline {
 5086                                additional_indent: IndentSize::spaces(0),
 5087                                extra_line_additional_indent: if needs_extra_newline {
 5088                                    Some(IndentSize::spaces(0))
 5089                                } else {
 5090                                    None
 5091                                },
 5092                                prevent_auto_indent: false,
 5093                            };
 5094
 5095                            let comment_delimiter = maybe!({
 5096                                if !selection_is_empty {
 5097                                    return None;
 5098                                }
 5099
 5100                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5101                                    return None;
 5102                                }
 5103
 5104                                return comment_delimiter_for_newline(
 5105                                    &start_point,
 5106                                    &buffer,
 5107                                    language,
 5108                                );
 5109                            });
 5110
 5111                            let doc_delimiter = maybe!({
 5112                                if !selection_is_empty {
 5113                                    return None;
 5114                                }
 5115
 5116                                if !multi_buffer.language_settings(cx).extend_comment_on_newline {
 5117                                    return None;
 5118                                }
 5119
 5120                                return documentation_delimiter_for_newline(
 5121                                    &start_point,
 5122                                    &buffer,
 5123                                    language,
 5124                                    &mut newline_config,
 5125                                );
 5126                            });
 5127
 5128                            let list_delimiter = maybe!({
 5129                                if !selection_is_empty {
 5130                                    return None;
 5131                                }
 5132
 5133                                if !multi_buffer.language_settings(cx).extend_list_on_newline {
 5134                                    return None;
 5135                                }
 5136
 5137                                return list_delimiter_for_newline(
 5138                                    &start_point,
 5139                                    &buffer,
 5140                                    language,
 5141                                    &mut newline_config,
 5142                                );
 5143                            });
 5144
 5145                            (
 5146                                comment_delimiter.or(doc_delimiter).or(list_delimiter),
 5147                                newline_config,
 5148                            )
 5149                        } else {
 5150                            (
 5151                                None,
 5152                                NewlineConfig::Newline {
 5153                                    additional_indent: IndentSize::spaces(0),
 5154                                    extra_line_additional_indent: None,
 5155                                    prevent_auto_indent: false,
 5156                                },
 5157                            )
 5158                        };
 5159
 5160                        let (edit_start, new_text, prevent_auto_indent) = match &newline_config {
 5161                            NewlineConfig::ClearCurrentLine => {
 5162                                let row_start =
 5163                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5164                                (row_start, String::new(), false)
 5165                            }
 5166                            NewlineConfig::UnindentCurrentLine { continuation } => {
 5167                                let row_start =
 5168                                    buffer.point_to_offset(Point::new(start_point.row, 0));
 5169                                let tab_size = buffer.language_settings_at(start, cx).tab_size;
 5170                                let tab_size_indent = IndentSize::spaces(tab_size.get());
 5171                                let reduced_indent =
 5172                                    existing_indent.with_delta(Ordering::Less, tab_size_indent);
 5173                                let mut new_text = String::new();
 5174                                new_text.extend(reduced_indent.chars());
 5175                                new_text.push_str(continuation);
 5176                                (row_start, new_text, true)
 5177                            }
 5178                            NewlineConfig::Newline {
 5179                                additional_indent,
 5180                                extra_line_additional_indent,
 5181                                prevent_auto_indent,
 5182                            } => {
 5183                                let auto_indent_mode =
 5184                                    buffer.language_settings_at(start, cx).auto_indent;
 5185                                let preserve_indent =
 5186                                    auto_indent_mode != language::AutoIndentMode::None;
 5187                                let apply_syntax_indent =
 5188                                    auto_indent_mode == language::AutoIndentMode::SyntaxAware;
 5189                                let capacity_for_delimiter =
 5190                                    delimiter.as_deref().map(str::len).unwrap_or_default();
 5191                                let existing_indent_len = if preserve_indent {
 5192                                    existing_indent.len as usize
 5193                                } else {
 5194                                    0
 5195                                };
 5196                                let extra_line_len = extra_line_additional_indent
 5197                                    .map(|i| 1 + existing_indent_len + i.len as usize)
 5198                                    .unwrap_or(0);
 5199                                let mut new_text = String::with_capacity(
 5200                                    1 + capacity_for_delimiter
 5201                                        + existing_indent_len
 5202                                        + additional_indent.len as usize
 5203                                        + extra_line_len,
 5204                                );
 5205                                new_text.push('\n');
 5206                                if preserve_indent {
 5207                                    new_text.extend(existing_indent.chars());
 5208                                }
 5209                                new_text.extend(additional_indent.chars());
 5210                                if let Some(delimiter) = &delimiter {
 5211                                    new_text.push_str(delimiter);
 5212                                }
 5213                                if let Some(extra_indent) = extra_line_additional_indent {
 5214                                    new_text.push('\n');
 5215                                    if preserve_indent {
 5216                                        new_text.extend(existing_indent.chars());
 5217                                    }
 5218                                    new_text.extend(extra_indent.chars());
 5219                                }
 5220                                (
 5221                                    start,
 5222                                    new_text,
 5223                                    *prevent_auto_indent || !apply_syntax_indent,
 5224                                )
 5225                            }
 5226                        };
 5227
 5228                        let anchor = buffer.anchor_after(end);
 5229                        let new_selection = selection.map(|_| anchor);
 5230                        (
 5231                            ((edit_start..end, new_text), prevent_auto_indent),
 5232                            (newline_config.has_extra_line(), new_selection),
 5233                        )
 5234                    })
 5235                    .unzip()
 5236            };
 5237
 5238            let mut auto_indent_edits = Vec::new();
 5239            let mut edits = Vec::new();
 5240            for (edit, prevent_auto_indent) in edits_with_flags {
 5241                if prevent_auto_indent {
 5242                    edits.push(edit);
 5243                } else {
 5244                    auto_indent_edits.push(edit);
 5245                }
 5246            }
 5247            if !edits.is_empty() {
 5248                this.edit(edits, cx);
 5249            }
 5250            if !auto_indent_edits.is_empty() {
 5251                this.edit_with_autoindent(auto_indent_edits, cx);
 5252            }
 5253
 5254            let buffer = this.buffer.read(cx).snapshot(cx);
 5255            let new_selections = selection_info
 5256                .into_iter()
 5257                .map(|(extra_newline_inserted, new_selection)| {
 5258                    let mut cursor = new_selection.end.to_point(&buffer);
 5259                    if extra_newline_inserted {
 5260                        cursor.row -= 1;
 5261                        cursor.column = buffer.line_len(MultiBufferRow(cursor.row));
 5262                    }
 5263                    new_selection.map(|_| cursor)
 5264                })
 5265                .collect();
 5266
 5267            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
 5268            this.refresh_edit_prediction(true, false, window, cx);
 5269            if let Some(task) = this.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5270                task.detach_and_log_err(cx);
 5271            }
 5272        });
 5273    }
 5274
 5275    pub fn newline_above(&mut self, _: &NewlineAbove, window: &mut Window, cx: &mut Context<Self>) {
 5276        if self.read_only(cx) {
 5277            return;
 5278        }
 5279
 5280        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5281
 5282        let buffer = self.buffer.read(cx);
 5283        let snapshot = buffer.snapshot(cx);
 5284
 5285        let mut edits = Vec::new();
 5286        let mut rows = Vec::new();
 5287
 5288        for (rows_inserted, selection) in self
 5289            .selections
 5290            .all_adjusted(&self.display_snapshot(cx))
 5291            .into_iter()
 5292            .enumerate()
 5293        {
 5294            let cursor = selection.head();
 5295            let row = cursor.row;
 5296
 5297            let start_of_line = snapshot.clip_point(Point::new(row, 0), Bias::Left);
 5298
 5299            let newline = "\n".to_string();
 5300            edits.push((start_of_line..start_of_line, newline));
 5301
 5302            rows.push(row + rows_inserted as u32);
 5303        }
 5304
 5305        self.transact(window, cx, |editor, window, cx| {
 5306            editor.edit(edits, cx);
 5307
 5308            editor.change_selections(Default::default(), window, cx, |s| {
 5309                let mut index = 0;
 5310                s.move_cursors_with(&mut |map, _, _| {
 5311                    let row = rows[index];
 5312                    index += 1;
 5313
 5314                    let point = Point::new(row, 0);
 5315                    let boundary = map.next_line_boundary(point).1;
 5316                    let clipped = map.clip_point(boundary, Bias::Left);
 5317
 5318                    (clipped, SelectionGoal::None)
 5319                });
 5320            });
 5321
 5322            let mut indent_edits = Vec::new();
 5323            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5324            for row in rows {
 5325                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5326                for (row, indent) in indents {
 5327                    if indent.len == 0 {
 5328                        continue;
 5329                    }
 5330
 5331                    let text = match indent.kind {
 5332                        IndentKind::Space => " ".repeat(indent.len as usize),
 5333                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5334                    };
 5335                    let point = Point::new(row.0, 0);
 5336                    indent_edits.push((point..point, text));
 5337                }
 5338            }
 5339            editor.edit(indent_edits, cx);
 5340            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5341                format.detach_and_log_err(cx);
 5342            }
 5343        });
 5344    }
 5345
 5346    pub fn newline_below(&mut self, _: &NewlineBelow, window: &mut Window, cx: &mut Context<Self>) {
 5347        if self.read_only(cx) {
 5348            return;
 5349        }
 5350
 5351        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 5352
 5353        let mut buffer_edits: HashMap<EntityId, (Entity<Buffer>, Vec<Point>)> = HashMap::default();
 5354        let mut rows = Vec::new();
 5355        let mut rows_inserted = 0;
 5356
 5357        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
 5358            let cursor = selection.head();
 5359            let row = cursor.row;
 5360
 5361            let point = Point::new(row, 0);
 5362            let Some((buffer_handle, buffer_point, _)) =
 5363                self.buffer.read(cx).point_to_buffer_point(point, cx)
 5364            else {
 5365                continue;
 5366            };
 5367
 5368            buffer_edits
 5369                .entry(buffer_handle.entity_id())
 5370                .or_insert_with(|| (buffer_handle, Vec::new()))
 5371                .1
 5372                .push(buffer_point);
 5373
 5374            rows_inserted += 1;
 5375            rows.push(row + rows_inserted);
 5376        }
 5377
 5378        self.transact(window, cx, |editor, window, cx| {
 5379            for (_, (buffer_handle, points)) in &buffer_edits {
 5380                buffer_handle.update(cx, |buffer, cx| {
 5381                    let edits: Vec<_> = points
 5382                        .iter()
 5383                        .map(|point| {
 5384                            let target = Point::new(point.row + 1, 0);
 5385                            let start_of_line = buffer.point_to_offset(target).min(buffer.len());
 5386                            (start_of_line..start_of_line, "\n")
 5387                        })
 5388                        .collect();
 5389                    buffer.edit(edits, None, cx);
 5390                });
 5391            }
 5392
 5393            editor.change_selections(Default::default(), window, cx, |s| {
 5394                let mut index = 0;
 5395                s.move_cursors_with(&mut |map, _, _| {
 5396                    let row = rows[index];
 5397                    index += 1;
 5398
 5399                    let point = Point::new(row, 0);
 5400                    let boundary = map.next_line_boundary(point).1;
 5401                    let clipped = map.clip_point(boundary, Bias::Left);
 5402
 5403                    (clipped, SelectionGoal::None)
 5404                });
 5405            });
 5406
 5407            let mut indent_edits = Vec::new();
 5408            let multibuffer_snapshot = editor.buffer.read(cx).snapshot(cx);
 5409            for row in rows {
 5410                let indents = multibuffer_snapshot.suggested_indents(row..row + 1, cx);
 5411                for (row, indent) in indents {
 5412                    if indent.len == 0 {
 5413                        continue;
 5414                    }
 5415
 5416                    let text = match indent.kind {
 5417                        IndentKind::Space => " ".repeat(indent.len as usize),
 5418                        IndentKind::Tab => "\t".repeat(indent.len as usize),
 5419                    };
 5420                    let point = Point::new(row.0, 0);
 5421                    indent_edits.push((point..point, text));
 5422                }
 5423            }
 5424            editor.edit(indent_edits, cx);
 5425            if let Some(format) = editor.trigger_on_type_formatting("\n".to_owned(), window, cx) {
 5426                format.detach_and_log_err(cx);
 5427            }
 5428        });
 5429    }
 5430
 5431    pub fn insert(&mut self, text: &str, window: &mut Window, cx: &mut Context<Self>) {
 5432        let autoindent = text.is_empty().not().then(|| AutoindentMode::Block {
 5433            original_indent_columns: Vec::new(),
 5434        });
 5435        self.replace_selections(text, autoindent, window, cx, false);
 5436    }
 5437
 5438    /// Replaces the editor's selections with the provided `text`, applying the
 5439    /// given `autoindent_mode` (`None` will skip autoindentation).
 5440    ///
 5441    /// Early returns if the editor is in read-only mode, without applying any
 5442    /// edits.
 5443    fn replace_selections(
 5444        &mut self,
 5445        text: &str,
 5446        autoindent_mode: Option<AutoindentMode>,
 5447        window: &mut Window,
 5448        cx: &mut Context<Self>,
 5449        apply_linked_edits: bool,
 5450    ) {
 5451        if self.read_only(cx) {
 5452            return;
 5453        }
 5454
 5455        let text: Arc<str> = text.into();
 5456        self.transact(window, cx, |this, window, cx| {
 5457            let old_selections = this.selections.all_adjusted(&this.display_snapshot(cx));
 5458            let linked_edits = if apply_linked_edits {
 5459                this.linked_edits_for_selections(text.clone(), cx)
 5460            } else {
 5461                LinkedEdits::new()
 5462            };
 5463
 5464            let selection_anchors = this.buffer.update(cx, |buffer, cx| {
 5465                let anchors = {
 5466                    let snapshot = buffer.read(cx);
 5467                    old_selections
 5468                        .iter()
 5469                        .map(|s| {
 5470                            let anchor = snapshot.anchor_after(s.head());
 5471                            s.map(|_| anchor)
 5472                        })
 5473                        .collect::<Vec<_>>()
 5474                };
 5475                buffer.edit(
 5476                    old_selections
 5477                        .iter()
 5478                        .map(|s| (s.start..s.end, text.clone())),
 5479                    autoindent_mode,
 5480                    cx,
 5481                );
 5482                anchors
 5483            });
 5484
 5485            linked_edits.apply(cx);
 5486
 5487            this.change_selections(Default::default(), window, cx, |s| {
 5488                s.select_anchors(selection_anchors);
 5489            });
 5490
 5491            if apply_linked_edits {
 5492                refresh_linked_ranges(this, window, cx);
 5493            }
 5494
 5495            cx.notify();
 5496        });
 5497    }
 5498
 5499    /// Collects linked edits for the current selections, pairing each linked
 5500    /// range with `text`.
 5501    pub fn linked_edits_for_selections(&self, text: Arc<str>, cx: &App) -> LinkedEdits {
 5502        let mut linked_edits = LinkedEdits::new();
 5503        if !self.linked_edit_ranges.is_empty() {
 5504            for selection in self.selections.disjoint_anchors() {
 5505                let start = selection.start.text_anchor;
 5506                let end = selection.end.text_anchor;
 5507                linked_edits.push(self, start..end, text.clone(), cx);
 5508            }
 5509        }
 5510        linked_edits
 5511    }
 5512
 5513    /// Deletes the content covered by the current selections and applies
 5514    /// linked edits.
 5515    pub fn delete_selections_with_linked_edits(
 5516        &mut self,
 5517        window: &mut Window,
 5518        cx: &mut Context<Self>,
 5519    ) {
 5520        self.replace_selections("", None, window, cx, true);
 5521    }
 5522
 5523    #[cfg(any(test, feature = "test-support"))]
 5524    pub fn set_linked_edit_ranges_for_testing(
 5525        &mut self,
 5526        ranges: Vec<(Range<Point>, Vec<Range<Point>>)>,
 5527        cx: &mut Context<Self>,
 5528    ) -> Option<()> {
 5529        let Some((buffer, _)) = self
 5530            .buffer
 5531            .read(cx)
 5532            .text_anchor_for_position(self.selections.newest_anchor().start, cx)
 5533        else {
 5534            return None;
 5535        };
 5536        let buffer = buffer.read(cx);
 5537        let buffer_id = buffer.remote_id();
 5538        let mut linked_ranges = Vec::with_capacity(ranges.len());
 5539        for (base_range, linked_ranges_points) in ranges {
 5540            let base_anchor =
 5541                buffer.anchor_before(base_range.start)..buffer.anchor_after(base_range.end);
 5542            let linked_anchors = linked_ranges_points
 5543                .into_iter()
 5544                .map(|range| buffer.anchor_before(range.start)..buffer.anchor_after(range.end))
 5545                .collect();
 5546            linked_ranges.push((base_anchor, linked_anchors));
 5547        }
 5548        let mut map = HashMap::default();
 5549        map.insert(buffer_id, linked_ranges);
 5550        self.linked_edit_ranges = linked_editing_ranges::LinkedEditingRanges(map);
 5551        Some(())
 5552    }
 5553
 5554    fn trigger_completion_on_input(
 5555        &mut self,
 5556        text: &str,
 5557        trigger_in_words: bool,
 5558        window: &mut Window,
 5559        cx: &mut Context<Self>,
 5560    ) {
 5561        let completions_source = self
 5562            .context_menu
 5563            .borrow()
 5564            .as_ref()
 5565            .and_then(|menu| match menu {
 5566                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5567                CodeContextMenu::CodeActions(_) => None,
 5568            });
 5569
 5570        match completions_source {
 5571            Some(CompletionsMenuSource::Words { .. }) => {
 5572                self.open_or_update_completions_menu(
 5573                    Some(CompletionsMenuSource::Words {
 5574                        ignore_threshold: false,
 5575                    }),
 5576                    None,
 5577                    trigger_in_words,
 5578                    window,
 5579                    cx,
 5580                );
 5581            }
 5582            _ => self.open_or_update_completions_menu(
 5583                None,
 5584                Some(text.to_owned()).filter(|x| !x.is_empty()),
 5585                true,
 5586                window,
 5587                cx,
 5588            ),
 5589        }
 5590    }
 5591
 5592    /// If any empty selections is touching the start of its innermost containing autoclose
 5593    /// region, expand it to select the brackets.
 5594    fn select_autoclose_pair(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 5595        let selections = self
 5596            .selections
 5597            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 5598        let buffer = self.buffer.read(cx).read(cx);
 5599        let new_selections = self
 5600            .selections_with_autoclose_regions(selections, &buffer)
 5601            .map(|(mut selection, region)| {
 5602                if !selection.is_empty() {
 5603                    return selection;
 5604                }
 5605
 5606                if let Some(region) = region {
 5607                    let mut range = region.range.to_offset(&buffer);
 5608                    if selection.start == range.start && range.start.0 >= region.pair.start.len() {
 5609                        range.start -= region.pair.start.len();
 5610                        if buffer.contains_str_at(range.start, &region.pair.start)
 5611                            && buffer.contains_str_at(range.end, &region.pair.end)
 5612                        {
 5613                            range.end += region.pair.end.len();
 5614                            selection.start = range.start;
 5615                            selection.end = range.end;
 5616
 5617                            return selection;
 5618                        }
 5619                    }
 5620                }
 5621
 5622                let always_treat_brackets_as_autoclosed = buffer
 5623                    .language_settings_at(selection.start, cx)
 5624                    .always_treat_brackets_as_autoclosed;
 5625
 5626                if !always_treat_brackets_as_autoclosed {
 5627                    return selection;
 5628                }
 5629
 5630                if let Some(scope) = buffer.language_scope_at(selection.start) {
 5631                    for (pair, enabled) in scope.brackets() {
 5632                        if !enabled || !pair.close {
 5633                            continue;
 5634                        }
 5635
 5636                        if buffer.contains_str_at(selection.start, &pair.end) {
 5637                            let pair_start_len = pair.start.len();
 5638                            if buffer.contains_str_at(
 5639                                selection.start.saturating_sub_usize(pair_start_len),
 5640                                &pair.start,
 5641                            ) {
 5642                                selection.start -= pair_start_len;
 5643                                selection.end += pair.end.len();
 5644
 5645                                return selection;
 5646                            }
 5647                        }
 5648                    }
 5649                }
 5650
 5651                selection
 5652            })
 5653            .collect();
 5654
 5655        drop(buffer);
 5656        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
 5657            selections.select(new_selections)
 5658        });
 5659    }
 5660
 5661    /// Iterate the given selections, and for each one, find the smallest surrounding
 5662    /// autoclose region. This uses the ordering of the selections and the autoclose
 5663    /// regions to avoid repeated comparisons.
 5664    fn selections_with_autoclose_regions<'a, D: ToOffset + Clone>(
 5665        &'a self,
 5666        selections: impl IntoIterator<Item = Selection<D>>,
 5667        buffer: &'a MultiBufferSnapshot,
 5668    ) -> impl Iterator<Item = (Selection<D>, Option<&'a AutocloseRegion>)> {
 5669        let mut i = 0;
 5670        let mut regions = self.autoclose_regions.as_slice();
 5671        selections.into_iter().map(move |selection| {
 5672            let range = selection.start.to_offset(buffer)..selection.end.to_offset(buffer);
 5673
 5674            let mut enclosing = None;
 5675            while let Some(pair_state) = regions.get(i) {
 5676                if pair_state.range.end.to_offset(buffer) < range.start {
 5677                    regions = &regions[i + 1..];
 5678                    i = 0;
 5679                } else if pair_state.range.start.to_offset(buffer) > range.end {
 5680                    break;
 5681                } else {
 5682                    if pair_state.selection_id == selection.id {
 5683                        enclosing = Some(pair_state);
 5684                    }
 5685                    i += 1;
 5686                }
 5687            }
 5688
 5689            (selection, enclosing)
 5690        })
 5691    }
 5692
 5693    /// Remove any autoclose regions that no longer contain their selection or have invalid anchors in ranges.
 5694    fn invalidate_autoclose_regions(
 5695        &mut self,
 5696        mut selections: &[Selection<Anchor>],
 5697        buffer: &MultiBufferSnapshot,
 5698    ) {
 5699        self.autoclose_regions.retain(|state| {
 5700            if !state.range.start.is_valid(buffer) || !state.range.end.is_valid(buffer) {
 5701                return false;
 5702            }
 5703
 5704            let mut i = 0;
 5705            while let Some(selection) = selections.get(i) {
 5706                if selection.end.cmp(&state.range.start, buffer).is_lt() {
 5707                    selections = &selections[1..];
 5708                    continue;
 5709                }
 5710                if selection.start.cmp(&state.range.end, buffer).is_gt() {
 5711                    break;
 5712                }
 5713                if selection.id == state.selection_id {
 5714                    return true;
 5715                } else {
 5716                    i += 1;
 5717                }
 5718            }
 5719            false
 5720        });
 5721    }
 5722
 5723    fn completion_query(buffer: &MultiBufferSnapshot, position: impl ToOffset) -> Option<String> {
 5724        let offset = position.to_offset(buffer);
 5725        let (word_range, kind) =
 5726            buffer.surrounding_word(offset, Some(CharScopeContext::Completion));
 5727        if offset > word_range.start && kind == Some(CharKind::Word) {
 5728            Some(
 5729                buffer
 5730                    .text_for_range(word_range.start..offset)
 5731                    .collect::<String>(),
 5732            )
 5733        } else {
 5734            None
 5735        }
 5736    }
 5737
 5738    pub fn visible_excerpts(
 5739        &self,
 5740        lsp_related_only: bool,
 5741        cx: &mut Context<Editor>,
 5742    ) -> HashMap<ExcerptId, (Entity<Buffer>, clock::Global, Range<usize>)> {
 5743        let project = self.project().cloned();
 5744        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 5745        let multi_buffer = self.buffer().read(cx);
 5746        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
 5747        multi_buffer_snapshot
 5748            .range_to_buffer_ranges(
 5749                self.multi_buffer_visible_range(&display_snapshot, cx)
 5750                    .to_inclusive(),
 5751            )
 5752            .into_iter()
 5753            .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty())
 5754            .filter_map(|(buffer, excerpt_visible_range, excerpt_id)| {
 5755                if !lsp_related_only {
 5756                    return Some((
 5757                        excerpt_id,
 5758                        (
 5759                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5760                            buffer.version().clone(),
 5761                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5762                        ),
 5763                    ));
 5764                }
 5765
 5766                let project = project.as_ref()?.read(cx);
 5767                let buffer_file = project::File::from_dyn(buffer.file())?;
 5768                let buffer_worktree = project.worktree_for_id(buffer_file.worktree_id(cx), cx)?;
 5769                let worktree_entry = buffer_worktree
 5770                    .read(cx)
 5771                    .entry_for_id(buffer_file.project_entry_id()?)?;
 5772                if worktree_entry.is_ignored {
 5773                    None
 5774                } else {
 5775                    Some((
 5776                        excerpt_id,
 5777                        (
 5778                            multi_buffer.buffer(buffer.remote_id()).unwrap(),
 5779                            buffer.version().clone(),
 5780                            excerpt_visible_range.start.0..excerpt_visible_range.end.0,
 5781                        ),
 5782                    ))
 5783                }
 5784            })
 5785            .collect()
 5786    }
 5787
 5788    pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
 5789        TextLayoutDetails {
 5790            text_system: window.text_system().clone(),
 5791            editor_style: self.style.clone().unwrap(),
 5792            rem_size: window.rem_size(),
 5793            scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
 5794            visible_rows: self.visible_line_count(),
 5795            vertical_scroll_margin: self.scroll_manager.vertical_scroll_margin,
 5796        }
 5797    }
 5798
 5799    fn trigger_on_type_formatting(
 5800        &self,
 5801        input: String,
 5802        window: &mut Window,
 5803        cx: &mut Context<Self>,
 5804    ) -> Option<Task<Result<()>>> {
 5805        if input.chars().count() != 1 {
 5806            return None;
 5807        }
 5808
 5809        let project = self.project()?;
 5810        let position = self.selections.newest_anchor().head();
 5811        let (buffer, buffer_position) = self
 5812            .buffer
 5813            .read(cx)
 5814            .text_anchor_for_position(position, cx)?;
 5815
 5816        let settings = language_settings::language_settings(
 5817            buffer
 5818                .read(cx)
 5819                .language_at(buffer_position)
 5820                .map(|l| l.name()),
 5821            buffer.read(cx).file(),
 5822            cx,
 5823        );
 5824        if !settings.use_on_type_format {
 5825            return None;
 5826        }
 5827
 5828        // OnTypeFormatting returns a list of edits, no need to pass them between Zed instances,
 5829        // hence we do LSP request & edit on host side only — add formats to host's history.
 5830        let push_to_lsp_host_history = true;
 5831        // If this is not the host, append its history with new edits.
 5832        let push_to_client_history = project.read(cx).is_via_collab();
 5833
 5834        let on_type_formatting = project.update(cx, |project, cx| {
 5835            project.on_type_format(
 5836                buffer.clone(),
 5837                buffer_position,
 5838                input,
 5839                push_to_lsp_host_history,
 5840                cx,
 5841            )
 5842        });
 5843        Some(cx.spawn_in(window, async move |editor, cx| {
 5844            if let Some(transaction) = on_type_formatting.await? {
 5845                if push_to_client_history {
 5846                    buffer.update(cx, |buffer, _| {
 5847                        buffer.push_transaction(transaction, Instant::now());
 5848                        buffer.finalize_last_transaction();
 5849                    });
 5850                }
 5851                editor.update(cx, |editor, cx| {
 5852                    editor.refresh_document_highlights(cx);
 5853                })?;
 5854            }
 5855            Ok(())
 5856        }))
 5857    }
 5858
 5859    pub fn show_word_completions(
 5860        &mut self,
 5861        _: &ShowWordCompletions,
 5862        window: &mut Window,
 5863        cx: &mut Context<Self>,
 5864    ) {
 5865        self.open_or_update_completions_menu(
 5866            Some(CompletionsMenuSource::Words {
 5867                ignore_threshold: true,
 5868            }),
 5869            None,
 5870            false,
 5871            window,
 5872            cx,
 5873        );
 5874    }
 5875
 5876    pub fn show_completions(
 5877        &mut self,
 5878        _: &ShowCompletions,
 5879        window: &mut Window,
 5880        cx: &mut Context<Self>,
 5881    ) {
 5882        self.open_or_update_completions_menu(None, None, false, window, cx);
 5883    }
 5884
 5885    fn open_or_update_completions_menu(
 5886        &mut self,
 5887        requested_source: Option<CompletionsMenuSource>,
 5888        trigger: Option<String>,
 5889        trigger_in_words: bool,
 5890        window: &mut Window,
 5891        cx: &mut Context<Self>,
 5892    ) {
 5893        if self.pending_rename.is_some() {
 5894            return;
 5895        }
 5896
 5897        let completions_source = self
 5898            .context_menu
 5899            .borrow()
 5900            .as_ref()
 5901            .and_then(|menu| match menu {
 5902                CodeContextMenu::Completions(completions_menu) => Some(completions_menu.source),
 5903                CodeContextMenu::CodeActions(_) => None,
 5904            });
 5905
 5906        let multibuffer_snapshot = self.buffer.read(cx).read(cx);
 5907
 5908        // Typically `start` == `end`, but with snippet tabstop choices the default choice is
 5909        // inserted and selected. To handle that case, the start of the selection is used so that
 5910        // the menu starts with all choices.
 5911        let position = self
 5912            .selections
 5913            .newest_anchor()
 5914            .start
 5915            .bias_right(&multibuffer_snapshot);
 5916        if position.diff_base_anchor.is_some() {
 5917            return;
 5918        }
 5919        let buffer_position = multibuffer_snapshot.anchor_before(position);
 5920        let Some(buffer) = buffer_position
 5921            .text_anchor
 5922            .buffer_id
 5923            .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
 5924        else {
 5925            return;
 5926        };
 5927        let buffer_snapshot = buffer.read(cx).snapshot();
 5928
 5929        let menu_is_open = matches!(
 5930            self.context_menu.borrow().as_ref(),
 5931            Some(CodeContextMenu::Completions(_))
 5932        );
 5933
 5934        let language = buffer_snapshot
 5935            .language_at(buffer_position.text_anchor)
 5936            .map(|language| language.name());
 5937
 5938        let language_settings = language_settings(language.clone(), buffer_snapshot.file(), cx);
 5939        let completion_settings = language_settings.completions.clone();
 5940
 5941        let show_completions_on_input = self
 5942            .show_completions_on_input_override
 5943            .unwrap_or(language_settings.show_completions_on_input);
 5944        if !menu_is_open && trigger.is_some() && !show_completions_on_input {
 5945            return;
 5946        }
 5947
 5948        let query: Option<Arc<String>> =
 5949            Self::completion_query(&multibuffer_snapshot, buffer_position)
 5950                .map(|query| query.into());
 5951
 5952        drop(multibuffer_snapshot);
 5953
 5954        // Hide the current completions menu when query is empty. Without this, cached
 5955        // completions from before the trigger char may be reused (#32774).
 5956        if query.is_none() && menu_is_open {
 5957            self.hide_context_menu(window, cx);
 5958        }
 5959
 5960        let mut ignore_word_threshold = false;
 5961        let provider = match requested_source {
 5962            Some(CompletionsMenuSource::Normal) | None => self.completion_provider.clone(),
 5963            Some(CompletionsMenuSource::Words { ignore_threshold }) => {
 5964                ignore_word_threshold = ignore_threshold;
 5965                None
 5966            }
 5967            Some(CompletionsMenuSource::SnippetChoices)
 5968            | Some(CompletionsMenuSource::SnippetsOnly) => {
 5969                log::error!("bug: SnippetChoices requested_source is not handled");
 5970                None
 5971            }
 5972        };
 5973
 5974        let sort_completions = provider
 5975            .as_ref()
 5976            .is_some_and(|provider| provider.sort_completions());
 5977
 5978        let filter_completions = provider
 5979            .as_ref()
 5980            .is_none_or(|provider| provider.filter_completions());
 5981
 5982        let was_snippets_only = matches!(
 5983            completions_source,
 5984            Some(CompletionsMenuSource::SnippetsOnly)
 5985        );
 5986
 5987        if let Some(CodeContextMenu::Completions(menu)) = self.context_menu.borrow_mut().as_mut() {
 5988            if filter_completions {
 5989                menu.filter(
 5990                    query.clone().unwrap_or_default(),
 5991                    buffer_position.text_anchor,
 5992                    &buffer,
 5993                    provider.clone(),
 5994                    window,
 5995                    cx,
 5996                );
 5997            }
 5998            // When `is_incomplete` is false, no need to re-query completions when the current query
 5999            // is a suffix of the initial query.
 6000            let was_complete = !menu.is_incomplete;
 6001            if was_complete && !was_snippets_only {
 6002                // If the new query is a suffix of the old query (typing more characters) and
 6003                // the previous result was complete, the existing completions can be filtered.
 6004                //
 6005                // Note that snippet completions are always complete.
 6006                let query_matches = match (&menu.initial_query, &query) {
 6007                    (Some(initial_query), Some(query)) => query.starts_with(initial_query.as_ref()),
 6008                    (None, _) => true,
 6009                    _ => false,
 6010                };
 6011                if query_matches {
 6012                    let position_matches = if menu.initial_position == position {
 6013                        true
 6014                    } else {
 6015                        let snapshot = self.buffer.read(cx).read(cx);
 6016                        menu.initial_position.to_offset(&snapshot) == position.to_offset(&snapshot)
 6017                    };
 6018                    if position_matches {
 6019                        return;
 6020                    }
 6021                }
 6022            }
 6023        };
 6024
 6025        let Anchor {
 6026            excerpt_id: buffer_excerpt_id,
 6027            text_anchor: buffer_position,
 6028            ..
 6029        } = buffer_position;
 6030
 6031        let (word_replace_range, word_to_exclude) = if let (word_range, Some(CharKind::Word)) =
 6032            buffer_snapshot.surrounding_word(buffer_position, None)
 6033        {
 6034            let word_to_exclude = buffer_snapshot
 6035                .text_for_range(word_range.clone())
 6036                .collect::<String>();
 6037            (
 6038                buffer_snapshot.anchor_before(word_range.start)
 6039                    ..buffer_snapshot.anchor_after(buffer_position),
 6040                Some(word_to_exclude),
 6041            )
 6042        } else {
 6043            (buffer_position..buffer_position, None)
 6044        };
 6045
 6046        let show_completion_documentation = buffer_snapshot
 6047            .settings_at(buffer_position, cx)
 6048            .show_completion_documentation;
 6049
 6050        // The document can be large, so stay in reasonable bounds when searching for words,
 6051        // otherwise completion pop-up might be slow to appear.
 6052        const WORD_LOOKUP_ROWS: u32 = 5_000;
 6053        let buffer_row = text::ToPoint::to_point(&buffer_position, &buffer_snapshot).row;
 6054        let min_word_search = buffer_snapshot.clip_point(
 6055            Point::new(buffer_row.saturating_sub(WORD_LOOKUP_ROWS), 0),
 6056            Bias::Left,
 6057        );
 6058        let max_word_search = buffer_snapshot.clip_point(
 6059            Point::new(buffer_row + WORD_LOOKUP_ROWS, 0).min(buffer_snapshot.max_point()),
 6060            Bias::Right,
 6061        );
 6062        let word_search_range = buffer_snapshot.point_to_offset(min_word_search)
 6063            ..buffer_snapshot.point_to_offset(max_word_search);
 6064
 6065        let skip_digits = query
 6066            .as_ref()
 6067            .is_none_or(|query| !query.chars().any(|c| c.is_digit(10)));
 6068
 6069        let load_provider_completions = provider.as_ref().is_some_and(|provider| {
 6070            trigger.as_ref().is_none_or(|trigger| {
 6071                provider.is_completion_trigger(
 6072                    &buffer,
 6073                    position.text_anchor,
 6074                    trigger,
 6075                    trigger_in_words,
 6076                    cx,
 6077                )
 6078            })
 6079        });
 6080
 6081        let provider_responses = if let Some(provider) = &provider
 6082            && load_provider_completions
 6083        {
 6084            let trigger_character =
 6085                trigger.filter(|trigger| buffer.read(cx).completion_triggers().contains(trigger));
 6086            let completion_context = CompletionContext {
 6087                trigger_kind: match &trigger_character {
 6088                    Some(_) => CompletionTriggerKind::TRIGGER_CHARACTER,
 6089                    None => CompletionTriggerKind::INVOKED,
 6090                },
 6091                trigger_character,
 6092            };
 6093
 6094            provider.completions(
 6095                buffer_excerpt_id,
 6096                &buffer,
 6097                buffer_position,
 6098                completion_context,
 6099                window,
 6100                cx,
 6101            )
 6102        } else {
 6103            Task::ready(Ok(Vec::new()))
 6104        };
 6105
 6106        let load_word_completions = if !self.word_completions_enabled {
 6107            false
 6108        } else if requested_source
 6109            == Some(CompletionsMenuSource::Words {
 6110                ignore_threshold: true,
 6111            })
 6112        {
 6113            true
 6114        } else {
 6115            load_provider_completions
 6116                && completion_settings.words != WordsCompletionMode::Disabled
 6117                && (ignore_word_threshold || {
 6118                    let words_min_length = completion_settings.words_min_length;
 6119                    // check whether word has at least `words_min_length` characters
 6120                    let query_chars = query.iter().flat_map(|q| q.chars());
 6121                    query_chars.take(words_min_length).count() == words_min_length
 6122                })
 6123        };
 6124
 6125        let mut words = if load_word_completions {
 6126            cx.background_spawn({
 6127                let buffer_snapshot = buffer_snapshot.clone();
 6128                async move {
 6129                    buffer_snapshot.words_in_range(WordsQuery {
 6130                        fuzzy_contents: None,
 6131                        range: word_search_range,
 6132                        skip_digits,
 6133                    })
 6134                }
 6135            })
 6136        } else {
 6137            Task::ready(BTreeMap::default())
 6138        };
 6139
 6140        let snippets = if let Some(provider) = &provider
 6141            && provider.show_snippets()
 6142            && let Some(project) = self.project()
 6143        {
 6144            let char_classifier = buffer_snapshot
 6145                .char_classifier_at(buffer_position)
 6146                .scope_context(Some(CharScopeContext::Completion));
 6147            project.update(cx, |project, cx| {
 6148                snippet_completions(project, &buffer, buffer_position, char_classifier, cx)
 6149            })
 6150        } else {
 6151            Task::ready(Ok(CompletionResponse {
 6152                completions: Vec::new(),
 6153                display_options: Default::default(),
 6154                is_incomplete: false,
 6155            }))
 6156        };
 6157
 6158        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
 6159
 6160        let id = post_inc(&mut self.next_completion_id);
 6161        let task = cx.spawn_in(window, async move |editor, cx| {
 6162            let Ok(()) = editor.update(cx, |this, _| {
 6163                this.completion_tasks.retain(|(task_id, _)| *task_id >= id);
 6164            }) else {
 6165                return;
 6166            };
 6167
 6168            // TODO: Ideally completions from different sources would be selectively re-queried, so
 6169            // that having one source with `is_incomplete: true` doesn't cause all to be re-queried.
 6170            let mut completions = Vec::new();
 6171            let mut is_incomplete = false;
 6172            let mut display_options: Option<CompletionDisplayOptions> = None;
 6173            if let Some(provider_responses) = provider_responses.await.log_err()
 6174                && !provider_responses.is_empty()
 6175            {
 6176                for response in provider_responses {
 6177                    completions.extend(response.completions);
 6178                    is_incomplete = is_incomplete || response.is_incomplete;
 6179                    match display_options.as_mut() {
 6180                        None => {
 6181                            display_options = Some(response.display_options);
 6182                        }
 6183                        Some(options) => options.merge(&response.display_options),
 6184                    }
 6185                }
 6186                if completion_settings.words == WordsCompletionMode::Fallback {
 6187                    words = Task::ready(BTreeMap::default());
 6188                }
 6189            }
 6190            let display_options = display_options.unwrap_or_default();
 6191
 6192            let mut words = words.await;
 6193            if let Some(word_to_exclude) = &word_to_exclude {
 6194                words.remove(word_to_exclude);
 6195            }
 6196            for lsp_completion in &completions {
 6197                words.remove(&lsp_completion.new_text);
 6198            }
 6199            completions.extend(words.into_iter().map(|(word, word_range)| Completion {
 6200                replace_range: word_replace_range.clone(),
 6201                new_text: word.clone(),
 6202                label: CodeLabel::plain(word, None),
 6203                match_start: None,
 6204                snippet_deduplication_key: None,
 6205                icon_path: None,
 6206                documentation: None,
 6207                source: CompletionSource::BufferWord {
 6208                    word_range,
 6209                    resolved: false,
 6210                },
 6211                insert_text_mode: Some(InsertTextMode::AS_IS),
 6212                confirm: None,
 6213            }));
 6214
 6215            completions.extend(
 6216                snippets
 6217                    .await
 6218                    .into_iter()
 6219                    .flat_map(|response| response.completions),
 6220            );
 6221
 6222            let menu = if completions.is_empty() {
 6223                None
 6224            } else {
 6225                let Ok((mut menu, matches_task)) = editor.update(cx, |editor, cx| {
 6226                    let languages = editor
 6227                        .workspace
 6228                        .as_ref()
 6229                        .and_then(|(workspace, _)| workspace.upgrade())
 6230                        .map(|workspace| workspace.read(cx).app_state().languages.clone());
 6231                    let menu = CompletionsMenu::new(
 6232                        id,
 6233                        requested_source.unwrap_or(if load_provider_completions {
 6234                            CompletionsMenuSource::Normal
 6235                        } else {
 6236                            CompletionsMenuSource::SnippetsOnly
 6237                        }),
 6238                        sort_completions,
 6239                        show_completion_documentation,
 6240                        position,
 6241                        query.clone(),
 6242                        is_incomplete,
 6243                        buffer.clone(),
 6244                        completions.into(),
 6245                        editor
 6246                            .context_menu()
 6247                            .borrow_mut()
 6248                            .as_ref()
 6249                            .map(|menu| menu.primary_scroll_handle()),
 6250                        display_options,
 6251                        snippet_sort_order,
 6252                        languages,
 6253                        language,
 6254                        cx,
 6255                    );
 6256
 6257                    let query = if filter_completions { query } else { None };
 6258                    let matches_task = menu.do_async_filtering(
 6259                        query.unwrap_or_default(),
 6260                        buffer_position,
 6261                        &buffer,
 6262                        cx,
 6263                    );
 6264                    (menu, matches_task)
 6265                }) else {
 6266                    return;
 6267                };
 6268
 6269                let matches = matches_task.await;
 6270
 6271                let Ok(()) = editor.update_in(cx, |editor, window, cx| {
 6272                    // Newer menu already set, so exit.
 6273                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6274                        editor.context_menu.borrow().as_ref()
 6275                        && prev_menu.id > id
 6276                    {
 6277                        return;
 6278                    };
 6279
 6280                    // Only valid to take prev_menu because either the new menu is immediately set
 6281                    // below, or the menu is hidden.
 6282                    if let Some(CodeContextMenu::Completions(prev_menu)) =
 6283                        editor.context_menu.borrow_mut().take()
 6284                    {
 6285                        let position_matches =
 6286                            if prev_menu.initial_position == menu.initial_position {
 6287                                true
 6288                            } else {
 6289                                let snapshot = editor.buffer.read(cx).read(cx);
 6290                                prev_menu.initial_position.to_offset(&snapshot)
 6291                                    == menu.initial_position.to_offset(&snapshot)
 6292                            };
 6293                        if position_matches {
 6294                            // Preserve markdown cache before `set_filter_results` because it will
 6295                            // try to populate the documentation cache.
 6296                            menu.preserve_markdown_cache(prev_menu);
 6297                        }
 6298                    };
 6299
 6300                    menu.set_filter_results(matches, provider, window, cx);
 6301                }) else {
 6302                    return;
 6303                };
 6304
 6305                menu.visible().then_some(menu)
 6306            };
 6307
 6308            editor
 6309                .update_in(cx, |editor, window, cx| {
 6310                    if editor.focus_handle.is_focused(window)
 6311                        && let Some(menu) = menu
 6312                    {
 6313                        *editor.context_menu.borrow_mut() =
 6314                            Some(CodeContextMenu::Completions(menu));
 6315
 6316                        crate::hover_popover::hide_hover(editor, cx);
 6317                        if editor.show_edit_predictions_in_menu() {
 6318                            editor.update_visible_edit_prediction(window, cx);
 6319                        } else {
 6320                            editor
 6321                                .discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6322                        }
 6323
 6324                        cx.notify();
 6325                        return;
 6326                    }
 6327
 6328                    if editor.completion_tasks.len() <= 1 {
 6329                        // If there are no more completion tasks and the last menu was empty, we should hide it.
 6330                        let was_hidden = editor.hide_context_menu(window, cx).is_none();
 6331                        // If it was already hidden and we don't show edit predictions in the menu,
 6332                        // we should also show the edit prediction when available.
 6333                        if was_hidden && editor.show_edit_predictions_in_menu() {
 6334                            editor.update_visible_edit_prediction(window, cx);
 6335                        }
 6336                    }
 6337                })
 6338                .ok();
 6339        });
 6340
 6341        self.completion_tasks.push((id, task));
 6342    }
 6343
 6344    #[cfg(any(test, feature = "test-support"))]
 6345    pub fn current_completions(&self) -> Option<Vec<project::Completion>> {
 6346        let menu = self.context_menu.borrow();
 6347        if let CodeContextMenu::Completions(menu) = menu.as_ref()? {
 6348            let completions = menu.completions.borrow();
 6349            Some(completions.to_vec())
 6350        } else {
 6351            None
 6352        }
 6353    }
 6354
 6355    pub fn with_completions_menu_matching_id<R>(
 6356        &self,
 6357        id: CompletionId,
 6358        f: impl FnOnce(Option<&mut CompletionsMenu>) -> R,
 6359    ) -> R {
 6360        let mut context_menu = self.context_menu.borrow_mut();
 6361        let Some(CodeContextMenu::Completions(completions_menu)) = &mut *context_menu else {
 6362            return f(None);
 6363        };
 6364        if completions_menu.id != id {
 6365            return f(None);
 6366        }
 6367        f(Some(completions_menu))
 6368    }
 6369
 6370    pub fn confirm_completion(
 6371        &mut self,
 6372        action: &ConfirmCompletion,
 6373        window: &mut Window,
 6374        cx: &mut Context<Self>,
 6375    ) -> Option<Task<Result<()>>> {
 6376        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6377        self.do_completion(action.item_ix, CompletionIntent::Complete, window, cx)
 6378    }
 6379
 6380    pub fn confirm_completion_insert(
 6381        &mut self,
 6382        _: &ConfirmCompletionInsert,
 6383        window: &mut Window,
 6384        cx: &mut Context<Self>,
 6385    ) -> Option<Task<Result<()>>> {
 6386        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6387        self.do_completion(None, CompletionIntent::CompleteWithInsert, window, cx)
 6388    }
 6389
 6390    pub fn confirm_completion_replace(
 6391        &mut self,
 6392        _: &ConfirmCompletionReplace,
 6393        window: &mut Window,
 6394        cx: &mut Context<Self>,
 6395    ) -> Option<Task<Result<()>>> {
 6396        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6397        self.do_completion(None, CompletionIntent::CompleteWithReplace, window, cx)
 6398    }
 6399
 6400    pub fn compose_completion(
 6401        &mut self,
 6402        action: &ComposeCompletion,
 6403        window: &mut Window,
 6404        cx: &mut Context<Self>,
 6405    ) -> Option<Task<Result<()>>> {
 6406        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6407        self.do_completion(action.item_ix, CompletionIntent::Compose, window, cx)
 6408    }
 6409
 6410    fn do_completion(
 6411        &mut self,
 6412        item_ix: Option<usize>,
 6413        intent: CompletionIntent,
 6414        window: &mut Window,
 6415        cx: &mut Context<Editor>,
 6416    ) -> Option<Task<Result<()>>> {
 6417        use language::ToOffset as _;
 6418
 6419        let CodeContextMenu::Completions(completions_menu) = self.hide_context_menu(window, cx)?
 6420        else {
 6421            return None;
 6422        };
 6423
 6424        let candidate_id = {
 6425            let entries = completions_menu.entries.borrow();
 6426            let mat = entries.get(item_ix.unwrap_or(completions_menu.selected_item))?;
 6427            if self.show_edit_predictions_in_menu() {
 6428                self.discard_edit_prediction(EditPredictionDiscardReason::Rejected, cx);
 6429            }
 6430            mat.candidate_id
 6431        };
 6432
 6433        let completion = completions_menu
 6434            .completions
 6435            .borrow()
 6436            .get(candidate_id)?
 6437            .clone();
 6438        cx.stop_propagation();
 6439
 6440        let buffer_handle = completions_menu.buffer.clone();
 6441
 6442        let CompletionEdit {
 6443            new_text,
 6444            snippet,
 6445            replace_range,
 6446        } = process_completion_for_edit(
 6447            &completion,
 6448            intent,
 6449            &buffer_handle,
 6450            &completions_menu.initial_position.text_anchor,
 6451            cx,
 6452        );
 6453
 6454        let buffer = buffer_handle.read(cx);
 6455        let snapshot = self.buffer.read(cx).snapshot(cx);
 6456        let newest_anchor = self.selections.newest_anchor();
 6457        let replace_range_multibuffer = {
 6458            let mut excerpt = snapshot.excerpt_containing(newest_anchor.range()).unwrap();
 6459            excerpt.map_range_from_buffer(replace_range.clone())
 6460        };
 6461        if snapshot.buffer_id_for_anchor(newest_anchor.head()) != Some(buffer.remote_id()) {
 6462            return None;
 6463        }
 6464
 6465        let old_text = buffer
 6466            .text_for_range(replace_range.clone())
 6467            .collect::<String>();
 6468        let lookbehind = newest_anchor
 6469            .start
 6470            .text_anchor
 6471            .to_offset(buffer)
 6472            .saturating_sub(replace_range.start.0);
 6473        let lookahead = replace_range
 6474            .end
 6475            .0
 6476            .saturating_sub(newest_anchor.end.text_anchor.to_offset(buffer));
 6477        let prefix = &old_text[..old_text.len().saturating_sub(lookahead)];
 6478        let suffix = &old_text[lookbehind.min(old_text.len())..];
 6479
 6480        let selections = self
 6481            .selections
 6482            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
 6483        let mut ranges = Vec::new();
 6484        let mut linked_edits = LinkedEdits::new();
 6485
 6486        let text: Arc<str> = new_text.clone().into();
 6487        for selection in &selections {
 6488            let range = if selection.id == newest_anchor.id {
 6489                replace_range_multibuffer.clone()
 6490            } else {
 6491                let mut range = selection.range();
 6492
 6493                // if prefix is present, don't duplicate it
 6494                if snapshot.contains_str_at(range.start.saturating_sub_usize(lookbehind), prefix) {
 6495                    range.start = range.start.saturating_sub_usize(lookbehind);
 6496
 6497                    // if suffix is also present, mimic the newest cursor and replace it
 6498                    if selection.id != newest_anchor.id
 6499                        && snapshot.contains_str_at(range.end, suffix)
 6500                    {
 6501                        range.end += lookahead;
 6502                    }
 6503                }
 6504                range
 6505            };
 6506
 6507            ranges.push(range.clone());
 6508
 6509            if !self.linked_edit_ranges.is_empty() {
 6510                let start_anchor = snapshot.anchor_before(range.start);
 6511                let end_anchor = snapshot.anchor_after(range.end);
 6512                let anchor_range = start_anchor.text_anchor..end_anchor.text_anchor;
 6513                linked_edits.push(&self, anchor_range, text.clone(), cx);
 6514            }
 6515        }
 6516
 6517        let common_prefix_len = old_text
 6518            .chars()
 6519            .zip(new_text.chars())
 6520            .take_while(|(a, b)| a == b)
 6521            .map(|(a, _)| a.len_utf8())
 6522            .sum::<usize>();
 6523
 6524        cx.emit(EditorEvent::InputHandled {
 6525            utf16_range_to_replace: None,
 6526            text: new_text[common_prefix_len..].into(),
 6527        });
 6528
 6529        self.transact(window, cx, |editor, window, cx| {
 6530            if let Some(mut snippet) = snippet {
 6531                snippet.text = new_text.to_string();
 6532                editor
 6533                    .insert_snippet(&ranges, snippet, window, cx)
 6534                    .log_err();
 6535            } else {
 6536                editor.buffer.update(cx, |multi_buffer, cx| {
 6537                    let auto_indent = match completion.insert_text_mode {
 6538                        Some(InsertTextMode::AS_IS) => None,
 6539                        _ => editor.autoindent_mode.clone(),
 6540                    };
 6541                    let edits = ranges.into_iter().map(|range| (range, new_text.as_str()));
 6542                    multi_buffer.edit(edits, auto_indent, cx);
 6543                });
 6544            }
 6545            linked_edits.apply(cx);
 6546            editor.refresh_edit_prediction(true, false, window, cx);
 6547        });
 6548        self.invalidate_autoclose_regions(&self.selections.disjoint_anchors_arc(), &snapshot);
 6549
 6550        let show_new_completions_on_confirm = completion
 6551            .confirm
 6552            .as_ref()
 6553            .is_some_and(|confirm| confirm(intent, window, cx));
 6554        if show_new_completions_on_confirm {
 6555            self.open_or_update_completions_menu(None, None, false, window, cx);
 6556        }
 6557
 6558        let provider = self.completion_provider.as_ref()?;
 6559
 6560        let lsp_store = self.project().map(|project| project.read(cx).lsp_store());
 6561        let command = lsp_store.as_ref().and_then(|lsp_store| {
 6562            let CompletionSource::Lsp {
 6563                lsp_completion,
 6564                server_id,
 6565                ..
 6566            } = &completion.source
 6567            else {
 6568                return None;
 6569            };
 6570            let lsp_command = lsp_completion.command.as_ref()?;
 6571            let available_commands = lsp_store
 6572                .read(cx)
 6573                .lsp_server_capabilities
 6574                .get(server_id)
 6575                .and_then(|server_capabilities| {
 6576                    server_capabilities
 6577                        .execute_command_provider
 6578                        .as_ref()
 6579                        .map(|options| options.commands.as_slice())
 6580                })?;
 6581            if available_commands.contains(&lsp_command.command) {
 6582                Some(CodeAction {
 6583                    server_id: *server_id,
 6584                    range: language::Anchor::MIN..language::Anchor::MIN,
 6585                    lsp_action: LspAction::Command(lsp_command.clone()),
 6586                    resolved: false,
 6587                })
 6588            } else {
 6589                None
 6590            }
 6591        });
 6592
 6593        drop(completion);
 6594        let apply_edits = provider.apply_additional_edits_for_completion(
 6595            buffer_handle.clone(),
 6596            completions_menu.completions.clone(),
 6597            candidate_id,
 6598            true,
 6599            cx,
 6600        );
 6601
 6602        let editor_settings = EditorSettings::get_global(cx);
 6603        if editor_settings.show_signature_help_after_edits || editor_settings.auto_signature_help {
 6604            // After the code completion is finished, users often want to know what signatures are needed.
 6605            // so we should automatically call signature_help
 6606            self.show_signature_help(&ShowSignatureHelp, window, cx);
 6607        }
 6608
 6609        Some(cx.spawn_in(window, async move |editor, cx| {
 6610            apply_edits.await?;
 6611
 6612            if let Some((lsp_store, command)) = lsp_store.zip(command) {
 6613                let title = command.lsp_action.title().to_owned();
 6614                let project_transaction = lsp_store
 6615                    .update(cx, |lsp_store, cx| {
 6616                        lsp_store.apply_code_action(buffer_handle, command, false, cx)
 6617                    })
 6618                    .await
 6619                    .context("applying post-completion command")?;
 6620                if let Some(workspace) = editor.read_with(cx, |editor, _| editor.workspace())? {
 6621                    Self::open_project_transaction(
 6622                        &editor,
 6623                        workspace.downgrade(),
 6624                        project_transaction,
 6625                        title,
 6626                        cx,
 6627                    )
 6628                    .await?;
 6629                }
 6630            }
 6631
 6632            Ok(())
 6633        }))
 6634    }
 6635
 6636    pub fn toggle_code_actions(
 6637        &mut self,
 6638        action: &ToggleCodeActions,
 6639        window: &mut Window,
 6640        cx: &mut Context<Self>,
 6641    ) {
 6642        let quick_launch = action.quick_launch;
 6643        let mut context_menu = self.context_menu.borrow_mut();
 6644        if let Some(CodeContextMenu::CodeActions(code_actions)) = context_menu.as_ref() {
 6645            if code_actions.deployed_from == action.deployed_from {
 6646                // Toggle if we're selecting the same one
 6647                *context_menu = None;
 6648                cx.notify();
 6649                return;
 6650            } else {
 6651                // Otherwise, clear it and start a new one
 6652                *context_menu = None;
 6653                cx.notify();
 6654            }
 6655        }
 6656        drop(context_menu);
 6657        let snapshot = self.snapshot(window, cx);
 6658        let deployed_from = action.deployed_from.clone();
 6659        let action = action.clone();
 6660        self.completion_tasks.clear();
 6661        self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 6662
 6663        let multibuffer_point = match &action.deployed_from {
 6664            Some(CodeActionSource::Indicator(row)) | Some(CodeActionSource::RunMenu(row)) => {
 6665                DisplayPoint::new(*row, 0).to_point(&snapshot)
 6666            }
 6667            _ => self
 6668                .selections
 6669                .newest::<Point>(&snapshot.display_snapshot)
 6670                .head(),
 6671        };
 6672        let Some((buffer, buffer_row)) = snapshot
 6673            .buffer_snapshot()
 6674            .buffer_line_for_row(MultiBufferRow(multibuffer_point.row))
 6675            .and_then(|(buffer_snapshot, range)| {
 6676                self.buffer()
 6677                    .read(cx)
 6678                    .buffer(buffer_snapshot.remote_id())
 6679                    .map(|buffer| (buffer, range.start.row))
 6680            })
 6681        else {
 6682            return;
 6683        };
 6684        let buffer_id = buffer.read(cx).remote_id();
 6685        let tasks = self
 6686            .runnables
 6687            .runnables((buffer_id, buffer_row))
 6688            .map(|t| Arc::new(t.to_owned()));
 6689
 6690        if !self.focus_handle.is_focused(window) {
 6691            return;
 6692        }
 6693        let project = self.project.clone();
 6694
 6695        let code_actions_task = match deployed_from {
 6696            Some(CodeActionSource::RunMenu(_)) => Task::ready(None),
 6697            _ => self.code_actions(buffer_row, window, cx),
 6698        };
 6699
 6700        let runnable_task = match deployed_from {
 6701            Some(CodeActionSource::Indicator(_)) => Task::ready(Ok(Default::default())),
 6702            _ => {
 6703                let mut task_context_task = Task::ready(None);
 6704                if let Some(tasks) = &tasks
 6705                    && let Some(project) = project
 6706                {
 6707                    task_context_task =
 6708                        Self::build_tasks_context(&project, &buffer, buffer_row, tasks, cx);
 6709                }
 6710
 6711                cx.spawn_in(window, {
 6712                    let buffer = buffer.clone();
 6713                    async move |editor, cx| {
 6714                        let task_context = task_context_task.await;
 6715
 6716                        let resolved_tasks =
 6717                            tasks
 6718                                .zip(task_context.clone())
 6719                                .map(|(tasks, task_context)| ResolvedTasks {
 6720                                    templates: tasks.resolve(&task_context).collect(),
 6721                                    position: snapshot.buffer_snapshot().anchor_before(Point::new(
 6722                                        multibuffer_point.row,
 6723                                        tasks.column,
 6724                                    )),
 6725                                });
 6726                        let debug_scenarios = editor
 6727                            .update(cx, |editor, cx| {
 6728                                editor.debug_scenarios(&resolved_tasks, &buffer, cx)
 6729                            })?
 6730                            .await;
 6731                        anyhow::Ok((resolved_tasks, debug_scenarios, task_context))
 6732                    }
 6733                })
 6734            }
 6735        };
 6736
 6737        cx.spawn_in(window, async move |editor, cx| {
 6738            let (resolved_tasks, debug_scenarios, task_context) = runnable_task.await?;
 6739            let code_actions = code_actions_task.await;
 6740            let spawn_straight_away = quick_launch
 6741                && resolved_tasks
 6742                    .as_ref()
 6743                    .is_some_and(|tasks| tasks.templates.len() == 1)
 6744                && code_actions
 6745                    .as_ref()
 6746                    .is_none_or(|actions| actions.is_empty())
 6747                && debug_scenarios.is_empty();
 6748
 6749            editor.update_in(cx, |editor, window, cx| {
 6750                crate::hover_popover::hide_hover(editor, cx);
 6751                let actions = CodeActionContents::new(
 6752                    resolved_tasks,
 6753                    code_actions,
 6754                    debug_scenarios,
 6755                    task_context.unwrap_or_default(),
 6756                );
 6757
 6758                // Don't show the menu if there are no actions available
 6759                if actions.is_empty() {
 6760                    cx.notify();
 6761                    return Task::ready(Ok(()));
 6762                }
 6763
 6764                *editor.context_menu.borrow_mut() =
 6765                    Some(CodeContextMenu::CodeActions(CodeActionsMenu {
 6766                        buffer,
 6767                        actions,
 6768                        selected_item: Default::default(),
 6769                        scroll_handle: UniformListScrollHandle::default(),
 6770                        deployed_from,
 6771                    }));
 6772                cx.notify();
 6773                if spawn_straight_away
 6774                    && let Some(task) = editor.confirm_code_action(
 6775                        &ConfirmCodeAction { item_ix: Some(0) },
 6776                        window,
 6777                        cx,
 6778                    )
 6779                {
 6780                    return task;
 6781                }
 6782
 6783                Task::ready(Ok(()))
 6784            })
 6785        })
 6786        .detach_and_log_err(cx);
 6787    }
 6788
 6789    fn debug_scenarios(
 6790        &mut self,
 6791        resolved_tasks: &Option<ResolvedTasks>,
 6792        buffer: &Entity<Buffer>,
 6793        cx: &mut App,
 6794    ) -> Task<Vec<task::DebugScenario>> {
 6795        maybe!({
 6796            let project = self.project()?;
 6797            let dap_store = project.read(cx).dap_store();
 6798            let mut scenarios = vec![];
 6799            let resolved_tasks = resolved_tasks.as_ref()?;
 6800            let buffer = buffer.read(cx);
 6801            let language = buffer.language()?;
 6802            let file = buffer.file();
 6803            let debug_adapter = language_settings(language.name().into(), file, cx)
 6804                .debuggers
 6805                .first()
 6806                .map(SharedString::from)
 6807                .or_else(|| language.config().debuggers.first().map(SharedString::from))?;
 6808
 6809            dap_store.update(cx, |dap_store, cx| {
 6810                for (_, task) in &resolved_tasks.templates {
 6811                    let maybe_scenario = dap_store.debug_scenario_for_build_task(
 6812                        task.original_task().clone(),
 6813                        debug_adapter.clone().into(),
 6814                        task.display_label().to_owned().into(),
 6815                        cx,
 6816                    );
 6817                    scenarios.push(maybe_scenario);
 6818                }
 6819            });
 6820            Some(cx.background_spawn(async move {
 6821                futures::future::join_all(scenarios)
 6822                    .await
 6823                    .into_iter()
 6824                    .flatten()
 6825                    .collect::<Vec<_>>()
 6826            }))
 6827        })
 6828        .unwrap_or_else(|| Task::ready(vec![]))
 6829    }
 6830
 6831    fn code_actions(
 6832        &mut self,
 6833        buffer_row: u32,
 6834        window: &mut Window,
 6835        cx: &mut Context<Self>,
 6836    ) -> Task<Option<Rc<[AvailableCodeAction]>>> {
 6837        let mut task = self.code_actions_task.take();
 6838        cx.spawn_in(window, async move |editor, cx| {
 6839            while let Some(prev_task) = task {
 6840                prev_task.await.log_err();
 6841                task = editor
 6842                    .update(cx, |this, _| this.code_actions_task.take())
 6843                    .ok()?;
 6844            }
 6845
 6846            editor
 6847                .update(cx, |editor, cx| {
 6848                    editor
 6849                        .available_code_actions
 6850                        .clone()
 6851                        .and_then(|(location, code_actions)| {
 6852                            let snapshot = location.buffer.read(cx).snapshot();
 6853                            let point_range = location.range.to_point(&snapshot);
 6854                            let point_range = point_range.start.row..=point_range.end.row;
 6855                            if point_range.contains(&buffer_row) {
 6856                                Some(code_actions)
 6857                            } else {
 6858                                None
 6859                            }
 6860                        })
 6861                })
 6862                .ok()
 6863                .flatten()
 6864        })
 6865    }
 6866
 6867    pub fn confirm_code_action(
 6868        &mut self,
 6869        action: &ConfirmCodeAction,
 6870        window: &mut Window,
 6871        cx: &mut Context<Self>,
 6872    ) -> Option<Task<Result<()>>> {
 6873        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
 6874
 6875        let actions_menu =
 6876            if let CodeContextMenu::CodeActions(menu) = self.hide_context_menu(window, cx)? {
 6877                menu
 6878            } else {
 6879                return None;
 6880            };
 6881
 6882        let action_ix = action.item_ix.unwrap_or(actions_menu.selected_item);
 6883        let action = actions_menu.actions.get(action_ix)?;
 6884        let title = action.label();
 6885        let buffer = actions_menu.buffer;
 6886        let workspace = self.workspace()?;
 6887
 6888        match action {
 6889            CodeActionsItem::Task(task_source_kind, resolved_task) => {
 6890                workspace.update(cx, |workspace, cx| {
 6891                    workspace.schedule_resolved_task(
 6892                        task_source_kind,
 6893                        resolved_task,
 6894                        false,
 6895                        window,
 6896                        cx,
 6897                    );
 6898
 6899                    Some(Task::ready(Ok(())))
 6900                })
 6901            }
 6902            CodeActionsItem::CodeAction {
 6903                excerpt_id,
 6904                action,
 6905                provider,
 6906            } => {
 6907                let apply_code_action =
 6908                    provider.apply_code_action(buffer, action, excerpt_id, true, window, cx);
 6909                let workspace = workspace.downgrade();
 6910                Some(cx.spawn_in(window, async move |editor, cx| {
 6911                    let project_transaction = apply_code_action.await?;
 6912                    Self::open_project_transaction(
 6913                        &editor,
 6914                        workspace,
 6915                        project_transaction,
 6916                        title,
 6917                        cx,
 6918                    )
 6919                    .await
 6920                }))
 6921            }
 6922            CodeActionsItem::DebugScenario(scenario) => {
 6923                let context = actions_menu.actions.context.into();
 6924
 6925                workspace.update(cx, |workspace, cx| {
 6926                    dap::send_telemetry(&scenario, TelemetrySpawnLocation::Gutter, cx);
 6927                    workspace.start_debug_session(
 6928                        scenario,
 6929                        context,
 6930                        Some(buffer),
 6931                        None,
 6932                        window,
 6933                        cx,
 6934                    );
 6935                });
 6936                Some(Task::ready(Ok(())))
 6937            }
 6938        }
 6939    }
 6940
 6941    fn open_transaction_for_hidden_buffers(
 6942        workspace: Entity<Workspace>,
 6943        transaction: ProjectTransaction,
 6944        title: String,
 6945        window: &mut Window,
 6946        cx: &mut Context<Self>,
 6947    ) {
 6948        if transaction.0.is_empty() {
 6949            return;
 6950        }
 6951
 6952        let edited_buffers_already_open = {
 6953            let other_editors: Vec<Entity<Editor>> = workspace
 6954                .read(cx)
 6955                .panes()
 6956                .iter()
 6957                .flat_map(|pane| pane.read(cx).items_of_type::<Editor>())
 6958                .filter(|editor| editor.entity_id() != cx.entity_id())
 6959                .collect();
 6960
 6961            transaction.0.keys().all(|buffer| {
 6962                other_editors.iter().any(|editor| {
 6963                    let multi_buffer = editor.read(cx).buffer();
 6964                    multi_buffer.read(cx).is_singleton()
 6965                        && multi_buffer
 6966                            .read(cx)
 6967                            .as_singleton()
 6968                            .map_or(false, |singleton| {
 6969                                singleton.entity_id() == buffer.entity_id()
 6970                            })
 6971                })
 6972            })
 6973        };
 6974        if !edited_buffers_already_open {
 6975            let workspace = workspace.downgrade();
 6976            cx.defer_in(window, move |_, window, cx| {
 6977                cx.spawn_in(window, async move |editor, cx| {
 6978                    Self::open_project_transaction(&editor, workspace, transaction, title, cx)
 6979                        .await
 6980                        .ok()
 6981                })
 6982                .detach();
 6983            });
 6984        }
 6985    }
 6986
 6987    pub async fn open_project_transaction(
 6988        editor: &WeakEntity<Editor>,
 6989        workspace: WeakEntity<Workspace>,
 6990        transaction: ProjectTransaction,
 6991        title: String,
 6992        cx: &mut AsyncWindowContext,
 6993    ) -> Result<()> {
 6994        let mut entries = transaction.0.into_iter().collect::<Vec<_>>();
 6995        cx.update(|_, cx| {
 6996            entries.sort_unstable_by_key(|(buffer, _)| {
 6997                buffer.read(cx).file().map(|f| f.path().clone())
 6998            });
 6999        })?;
 7000        if entries.is_empty() {
 7001            return Ok(());
 7002        }
 7003
 7004        // If the project transaction's edits are all contained within this editor, then
 7005        // avoid opening a new editor to display them.
 7006
 7007        if let [(buffer, transaction)] = &*entries {
 7008            let excerpt = editor.update(cx, |editor, cx| {
 7009                editor
 7010                    .buffer()
 7011                    .read(cx)
 7012                    .excerpt_containing(editor.selections.newest_anchor().head(), cx)
 7013            })?;
 7014            if let Some((_, excerpted_buffer, excerpt_range)) = excerpt
 7015                && excerpted_buffer == *buffer
 7016            {
 7017                let all_edits_within_excerpt = buffer.read_with(cx, |buffer, _| {
 7018                    let excerpt_range = excerpt_range.to_offset(buffer);
 7019                    buffer
 7020                        .edited_ranges_for_transaction::<usize>(transaction)
 7021                        .all(|range| {
 7022                            excerpt_range.start <= range.start && excerpt_range.end >= range.end
 7023                        })
 7024                });
 7025
 7026                if all_edits_within_excerpt {
 7027                    return Ok(());
 7028                }
 7029            }
 7030        }
 7031
 7032        let mut ranges_to_highlight = Vec::new();
 7033        let excerpt_buffer = cx.new(|cx| {
 7034            let mut multibuffer = MultiBuffer::new(Capability::ReadWrite).with_title(title);
 7035            for (buffer_handle, transaction) in &entries {
 7036                let edited_ranges = buffer_handle
 7037                    .read(cx)
 7038                    .edited_ranges_for_transaction::<Point>(transaction)
 7039                    .collect::<Vec<_>>();
 7040                let (ranges, _) = multibuffer.set_excerpts_for_path(
 7041                    PathKey::for_buffer(buffer_handle, cx),
 7042                    buffer_handle.clone(),
 7043                    edited_ranges,
 7044                    multibuffer_context_lines(cx),
 7045                    cx,
 7046                );
 7047
 7048                ranges_to_highlight.extend(ranges);
 7049            }
 7050            multibuffer.push_transaction(entries.iter().map(|(b, t)| (b, t)), cx);
 7051            multibuffer
 7052        });
 7053
 7054        workspace.update_in(cx, |workspace, window, cx| {
 7055            let project = workspace.project().clone();
 7056            let editor =
 7057                cx.new(|cx| Editor::for_multibuffer(excerpt_buffer, Some(project), window, cx));
 7058            workspace.add_item_to_active_pane(Box::new(editor.clone()), None, true, window, cx);
 7059            editor.update(cx, |editor, cx| {
 7060                editor.highlight_background(
 7061                    HighlightKey::Editor,
 7062                    &ranges_to_highlight,
 7063                    |_, theme| theme.colors().editor_highlighted_line_background,
 7064                    cx,
 7065                );
 7066            });
 7067        })?;
 7068
 7069        Ok(())
 7070    }
 7071
 7072    pub fn clear_code_action_providers(&mut self) {
 7073        self.code_action_providers.clear();
 7074        self.available_code_actions.take();
 7075    }
 7076
 7077    pub fn add_code_action_provider(
 7078        &mut self,
 7079        provider: Rc<dyn CodeActionProvider>,
 7080        window: &mut Window,
 7081        cx: &mut Context<Self>,
 7082    ) {
 7083        if self
 7084            .code_action_providers
 7085            .iter()
 7086            .any(|existing_provider| existing_provider.id() == provider.id())
 7087        {
 7088            return;
 7089        }
 7090
 7091        self.code_action_providers.push(provider);
 7092        self.refresh_code_actions(window, cx);
 7093    }
 7094
 7095    pub fn remove_code_action_provider(
 7096        &mut self,
 7097        id: Arc<str>,
 7098        window: &mut Window,
 7099        cx: &mut Context<Self>,
 7100    ) {
 7101        self.code_action_providers
 7102            .retain(|provider| provider.id() != id);
 7103        self.refresh_code_actions(window, cx);
 7104    }
 7105
 7106    pub fn code_actions_enabled_for_toolbar(&self, cx: &App) -> bool {
 7107        !self.code_action_providers.is_empty()
 7108            && EditorSettings::get_global(cx).toolbar.code_actions
 7109    }
 7110
 7111    pub fn has_available_code_actions(&self) -> bool {
 7112        self.available_code_actions
 7113            .as_ref()
 7114            .is_some_and(|(_, actions)| !actions.is_empty())
 7115    }
 7116
 7117    fn render_inline_code_actions(
 7118        &self,
 7119        icon_size: ui::IconSize,
 7120        display_row: DisplayRow,
 7121        is_active: bool,
 7122        cx: &mut Context<Self>,
 7123    ) -> AnyElement {
 7124        let show_tooltip = !self.context_menu_visible();
 7125        IconButton::new("inline_code_actions", ui::IconName::BoltFilled)
 7126            .icon_size(icon_size)
 7127            .shape(ui::IconButtonShape::Square)
 7128            .icon_color(ui::Color::Hidden)
 7129            .toggle_state(is_active)
 7130            .when(show_tooltip, |this| {
 7131                this.tooltip({
 7132                    let focus_handle = self.focus_handle.clone();
 7133                    move |_window, cx| {
 7134                        Tooltip::for_action_in(
 7135                            "Toggle Code Actions",
 7136                            &ToggleCodeActions {
 7137                                deployed_from: None,
 7138                                quick_launch: false,
 7139                            },
 7140                            &focus_handle,
 7141                            cx,
 7142                        )
 7143                    }
 7144                })
 7145            })
 7146            .on_click(cx.listener(move |editor, _: &ClickEvent, window, cx| {
 7147                window.focus(&editor.focus_handle(cx), cx);
 7148                editor.toggle_code_actions(
 7149                    &crate::actions::ToggleCodeActions {
 7150                        deployed_from: Some(crate::actions::CodeActionSource::Indicator(
 7151                            display_row,
 7152                        )),
 7153                        quick_launch: false,
 7154                    },
 7155                    window,
 7156                    cx,
 7157                );
 7158            }))
 7159            .into_any_element()
 7160    }
 7161
 7162    pub fn context_menu(&self) -> &RefCell<Option<CodeContextMenu>> {
 7163        &self.context_menu
 7164    }
 7165
 7166    fn refresh_code_actions(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7167        self.code_actions_task = Some(cx.spawn_in(window, async move |this, cx| {
 7168            cx.background_executor()
 7169                .timer(CODE_ACTIONS_DEBOUNCE_TIMEOUT)
 7170                .await;
 7171
 7172            let (start_buffer, start, _, end, newest_selection) = this
 7173                .update(cx, |this, cx| {
 7174                    let newest_selection = this.selections.newest_anchor().clone();
 7175                    if newest_selection.head().diff_base_anchor.is_some() {
 7176                        return None;
 7177                    }
 7178                    let display_snapshot = this.display_snapshot(cx);
 7179                    let newest_selection_adjusted =
 7180                        this.selections.newest_adjusted(&display_snapshot);
 7181                    let buffer = this.buffer.read(cx);
 7182
 7183                    let (start_buffer, start) =
 7184                        buffer.text_anchor_for_position(newest_selection_adjusted.start, cx)?;
 7185                    let (end_buffer, end) =
 7186                        buffer.text_anchor_for_position(newest_selection_adjusted.end, cx)?;
 7187
 7188                    Some((start_buffer, start, end_buffer, end, newest_selection))
 7189                })?
 7190                .filter(|(start_buffer, _, end_buffer, _, _)| start_buffer == end_buffer)
 7191                .context(
 7192                    "Expected selection to lie in a single buffer when refreshing code actions",
 7193                )?;
 7194            let (providers, tasks) = this.update_in(cx, |this, window, cx| {
 7195                let providers = this.code_action_providers.clone();
 7196                let tasks = this
 7197                    .code_action_providers
 7198                    .iter()
 7199                    .map(|provider| provider.code_actions(&start_buffer, start..end, window, cx))
 7200                    .collect::<Vec<_>>();
 7201                (providers, tasks)
 7202            })?;
 7203
 7204            let mut actions = Vec::new();
 7205            for (provider, provider_actions) in
 7206                providers.into_iter().zip(future::join_all(tasks).await)
 7207            {
 7208                if let Some(provider_actions) = provider_actions.log_err() {
 7209                    actions.extend(provider_actions.into_iter().map(|action| {
 7210                        AvailableCodeAction {
 7211                            excerpt_id: newest_selection.start.excerpt_id,
 7212                            action,
 7213                            provider: provider.clone(),
 7214                        }
 7215                    }));
 7216                }
 7217            }
 7218
 7219            this.update(cx, |this, cx| {
 7220                this.available_code_actions = if actions.is_empty() {
 7221                    None
 7222                } else {
 7223                    Some((
 7224                        Location {
 7225                            buffer: start_buffer,
 7226                            range: start..end,
 7227                        },
 7228                        actions.into(),
 7229                    ))
 7230                };
 7231                cx.notify();
 7232            })
 7233        }));
 7234    }
 7235
 7236    fn start_inline_blame_timer(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7237        if let Some(delay) = ProjectSettings::get_global(cx).git.inline_blame_delay() {
 7238            self.show_git_blame_inline = false;
 7239
 7240            self.show_git_blame_inline_delay_task =
 7241                Some(cx.spawn_in(window, async move |this, cx| {
 7242                    cx.background_executor().timer(delay).await;
 7243
 7244                    this.update(cx, |this, cx| {
 7245                        this.show_git_blame_inline = true;
 7246                        cx.notify();
 7247                    })
 7248                    .log_err();
 7249                }));
 7250        }
 7251    }
 7252
 7253    pub fn blame_hover(&mut self, _: &BlameHover, window: &mut Window, cx: &mut Context<Self>) {
 7254        let snapshot = self.snapshot(window, cx);
 7255        let cursor = self
 7256            .selections
 7257            .newest::<Point>(&snapshot.display_snapshot)
 7258            .head();
 7259        let Some((buffer, point, _)) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)
 7260        else {
 7261            return;
 7262        };
 7263
 7264        if self.blame.is_none() {
 7265            self.start_git_blame(true, window, cx);
 7266        }
 7267        let Some(blame) = self.blame.as_ref() else {
 7268            return;
 7269        };
 7270
 7271        let row_info = RowInfo {
 7272            buffer_id: Some(buffer.remote_id()),
 7273            buffer_row: Some(point.row),
 7274            ..Default::default()
 7275        };
 7276        let Some((buffer, blame_entry)) = blame
 7277            .update(cx, |blame, cx| blame.blame_for_rows(&[row_info], cx).next())
 7278            .flatten()
 7279        else {
 7280            return;
 7281        };
 7282
 7283        let anchor = self.selections.newest_anchor().head();
 7284        let position = self.to_pixel_point(anchor, &snapshot, window, cx);
 7285        if let (Some(position), Some(last_bounds)) = (position, self.last_bounds) {
 7286            self.show_blame_popover(
 7287                buffer,
 7288                &blame_entry,
 7289                position + last_bounds.origin,
 7290                true,
 7291                cx,
 7292            );
 7293        };
 7294    }
 7295
 7296    fn show_blame_popover(
 7297        &mut self,
 7298        buffer: BufferId,
 7299        blame_entry: &BlameEntry,
 7300        position: gpui::Point<Pixels>,
 7301        ignore_timeout: bool,
 7302        cx: &mut Context<Self>,
 7303    ) {
 7304        if let Some(state) = &mut self.inline_blame_popover {
 7305            state.hide_task.take();
 7306        } else {
 7307            let blame_popover_delay = EditorSettings::get_global(cx).hover_popover_delay.0;
 7308            let blame_entry = blame_entry.clone();
 7309            let show_task = cx.spawn(async move |editor, cx| {
 7310                if !ignore_timeout {
 7311                    cx.background_executor()
 7312                        .timer(std::time::Duration::from_millis(blame_popover_delay))
 7313                        .await;
 7314                }
 7315                editor
 7316                    .update(cx, |editor, cx| {
 7317                        editor.inline_blame_popover_show_task.take();
 7318                        let Some(blame) = editor.blame.as_ref() else {
 7319                            return;
 7320                        };
 7321                        let blame = blame.read(cx);
 7322                        let details = blame.details_for_entry(buffer, &blame_entry);
 7323                        let markdown = cx.new(|cx| {
 7324                            Markdown::new(
 7325                                details
 7326                                    .as_ref()
 7327                                    .map(|message| message.message.clone())
 7328                                    .unwrap_or_default(),
 7329                                None,
 7330                                None,
 7331                                cx,
 7332                            )
 7333                        });
 7334                        editor.inline_blame_popover = Some(InlineBlamePopover {
 7335                            position,
 7336                            hide_task: None,
 7337                            popover_bounds: None,
 7338                            popover_state: InlineBlamePopoverState {
 7339                                scroll_handle: ScrollHandle::new(),
 7340                                commit_message: details,
 7341                                markdown,
 7342                            },
 7343                            keyboard_grace: ignore_timeout,
 7344                        });
 7345                        cx.notify();
 7346                    })
 7347                    .ok();
 7348            });
 7349            self.inline_blame_popover_show_task = Some(show_task);
 7350        }
 7351    }
 7352
 7353    pub fn has_mouse_context_menu(&self) -> bool {
 7354        self.mouse_context_menu.is_some()
 7355    }
 7356
 7357    pub fn hide_blame_popover(&mut self, ignore_timeout: bool, cx: &mut Context<Self>) -> bool {
 7358        self.inline_blame_popover_show_task.take();
 7359        if let Some(state) = &mut self.inline_blame_popover {
 7360            let hide_task = cx.spawn(async move |editor, cx| {
 7361                if !ignore_timeout {
 7362                    cx.background_executor()
 7363                        .timer(std::time::Duration::from_millis(100))
 7364                        .await;
 7365                }
 7366                editor
 7367                    .update(cx, |editor, cx| {
 7368                        editor.inline_blame_popover.take();
 7369                        cx.notify();
 7370                    })
 7371                    .ok();
 7372            });
 7373            state.hide_task = Some(hide_task);
 7374            true
 7375        } else {
 7376            false
 7377        }
 7378    }
 7379
 7380    fn refresh_document_highlights(&mut self, cx: &mut Context<Self>) -> Option<()> {
 7381        if self.pending_rename.is_some() {
 7382            return None;
 7383        }
 7384
 7385        let provider = self.semantics_provider.clone()?;
 7386        let buffer = self.buffer.read(cx);
 7387        let newest_selection = self.selections.newest_anchor().clone();
 7388        let cursor_position = newest_selection.head();
 7389        let (cursor_buffer, cursor_buffer_position) =
 7390            buffer.text_anchor_for_position(cursor_position, cx)?;
 7391        let (tail_buffer, tail_buffer_position) =
 7392            buffer.text_anchor_for_position(newest_selection.tail(), cx)?;
 7393        if cursor_buffer != tail_buffer {
 7394            return None;
 7395        }
 7396
 7397        let snapshot = cursor_buffer.read(cx).snapshot();
 7398        let word_ranges = cx.background_spawn(async move {
 7399            // this might look odd to put on the background thread, but
 7400            // `surrounding_word` can be quite expensive as it calls into
 7401            // tree-sitter language scopes
 7402            let (start_word_range, _) = snapshot.surrounding_word(cursor_buffer_position, None);
 7403            let (end_word_range, _) = snapshot.surrounding_word(tail_buffer_position, None);
 7404            (start_word_range, end_word_range)
 7405        });
 7406
 7407        let debounce = EditorSettings::get_global(cx).lsp_highlight_debounce.0;
 7408        self.document_highlights_task = Some(cx.spawn(async move |this, cx| {
 7409            let (start_word_range, end_word_range) = word_ranges.await;
 7410            if start_word_range != end_word_range {
 7411                this.update(cx, |this, cx| {
 7412                    this.document_highlights_task.take();
 7413                    this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
 7414                    this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
 7415                })
 7416                .ok();
 7417                return;
 7418            }
 7419            cx.background_executor()
 7420                .timer(Duration::from_millis(debounce))
 7421                .await;
 7422
 7423            let highlights = if let Some(highlights) = cx.update(|cx| {
 7424                provider.document_highlights(&cursor_buffer, cursor_buffer_position, cx)
 7425            }) {
 7426                highlights.await.log_err()
 7427            } else {
 7428                None
 7429            };
 7430
 7431            if let Some(highlights) = highlights {
 7432                this.update(cx, |this, cx| {
 7433                    if this.pending_rename.is_some() {
 7434                        return;
 7435                    }
 7436
 7437                    let buffer = this.buffer.read(cx);
 7438                    if buffer
 7439                        .text_anchor_for_position(cursor_position, cx)
 7440                        .is_none_or(|(buffer, _)| buffer != cursor_buffer)
 7441                    {
 7442                        return;
 7443                    }
 7444
 7445                    let cursor_buffer_snapshot = cursor_buffer.read(cx);
 7446                    let mut write_ranges = Vec::new();
 7447                    let mut read_ranges = Vec::new();
 7448                    for highlight in highlights {
 7449                        let buffer_id = cursor_buffer.read(cx).remote_id();
 7450                        for (excerpt_id, _, excerpt_range) in
 7451                            buffer.excerpts_for_buffer(buffer_id, cx)
 7452                        {
 7453                            let start = highlight
 7454                                .range
 7455                                .start
 7456                                .max(&excerpt_range.context.start, cursor_buffer_snapshot);
 7457                            let end = highlight
 7458                                .range
 7459                                .end
 7460                                .min(&excerpt_range.context.end, cursor_buffer_snapshot);
 7461                            if start.cmp(&end, cursor_buffer_snapshot).is_ge() {
 7462                                continue;
 7463                            }
 7464
 7465                            let range = Anchor::range_in_buffer(excerpt_id, *start..*end);
 7466                            if highlight.kind == lsp::DocumentHighlightKind::WRITE {
 7467                                write_ranges.push(range);
 7468                            } else {
 7469                                read_ranges.push(range);
 7470                            }
 7471                        }
 7472                    }
 7473
 7474                    this.highlight_background(
 7475                        HighlightKey::DocumentHighlightRead,
 7476                        &read_ranges,
 7477                        |_, theme| theme.colors().editor_document_highlight_read_background,
 7478                        cx,
 7479                    );
 7480                    this.highlight_background(
 7481                        HighlightKey::DocumentHighlightWrite,
 7482                        &write_ranges,
 7483                        |_, theme| theme.colors().editor_document_highlight_write_background,
 7484                        cx,
 7485                    );
 7486                    cx.notify();
 7487                })
 7488                .log_err();
 7489            }
 7490        }));
 7491        None
 7492    }
 7493
 7494    fn prepare_highlight_query_from_selection(
 7495        &mut self,
 7496        snapshot: &DisplaySnapshot,
 7497        cx: &mut Context<Editor>,
 7498    ) -> Option<(String, Range<Anchor>)> {
 7499        if matches!(self.mode, EditorMode::SingleLine) {
 7500            return None;
 7501        }
 7502        if !EditorSettings::get_global(cx).selection_highlight {
 7503            return None;
 7504        }
 7505        if self.selections.count() != 1 || self.selections.line_mode() {
 7506            return None;
 7507        }
 7508        let selection = self.selections.newest::<Point>(&snapshot);
 7509        // If the selection spans multiple rows OR it is empty
 7510        if selection.start.row != selection.end.row
 7511            || selection.start.column == selection.end.column
 7512        {
 7513            return None;
 7514        }
 7515        let selection_anchor_range = selection.range().to_anchors(snapshot.buffer_snapshot());
 7516        let query = snapshot
 7517            .buffer_snapshot()
 7518            .text_for_range(selection_anchor_range.clone())
 7519            .collect::<String>();
 7520        if query.trim().is_empty() {
 7521            return None;
 7522        }
 7523        Some((query, selection_anchor_range))
 7524    }
 7525
 7526    #[ztracing::instrument(skip_all)]
 7527    fn update_selection_occurrence_highlights(
 7528        &mut self,
 7529        multi_buffer_snapshot: MultiBufferSnapshot,
 7530        query_text: String,
 7531        query_range: Range<Anchor>,
 7532        multi_buffer_range_to_query: Range<Point>,
 7533        use_debounce: bool,
 7534        window: &mut Window,
 7535        cx: &mut Context<Editor>,
 7536    ) -> Task<()> {
 7537        cx.spawn_in(window, async move |editor, cx| {
 7538            if use_debounce {
 7539                cx.background_executor()
 7540                    .timer(SELECTION_HIGHLIGHT_DEBOUNCE_TIMEOUT)
 7541                    .await;
 7542            }
 7543            let match_task = cx.background_spawn(async move {
 7544                let buffer_ranges = multi_buffer_snapshot
 7545                    .range_to_buffer_ranges(
 7546                        multi_buffer_range_to_query.start..=multi_buffer_range_to_query.end,
 7547                    )
 7548                    .into_iter()
 7549                    .filter(|(_, excerpt_visible_range, _)| !excerpt_visible_range.is_empty());
 7550                let mut match_ranges = Vec::new();
 7551                let Ok(regex) = project::search::SearchQuery::text(
 7552                    query_text,
 7553                    false,
 7554                    false,
 7555                    false,
 7556                    Default::default(),
 7557                    Default::default(),
 7558                    false,
 7559                    None,
 7560                ) else {
 7561                    return Vec::default();
 7562                };
 7563                let query_range = query_range.to_anchors(&multi_buffer_snapshot);
 7564                for (buffer_snapshot, search_range, excerpt_id) in buffer_ranges {
 7565                    match_ranges.extend(
 7566                        regex
 7567                            .search(
 7568                                buffer_snapshot,
 7569                                Some(search_range.start.0..search_range.end.0),
 7570                            )
 7571                            .await
 7572                            .into_iter()
 7573                            .filter_map(|match_range| {
 7574                                let match_start = buffer_snapshot
 7575                                    .anchor_after(search_range.start + match_range.start);
 7576                                let match_end = buffer_snapshot
 7577                                    .anchor_before(search_range.start + match_range.end);
 7578                                let match_anchor_range =
 7579                                    Anchor::range_in_buffer(excerpt_id, match_start..match_end);
 7580                                (match_anchor_range != query_range).then_some(match_anchor_range)
 7581                            }),
 7582                    );
 7583                }
 7584                match_ranges
 7585            });
 7586            let match_ranges = match_task.await;
 7587            editor
 7588                .update_in(cx, |editor, _, cx| {
 7589                    if use_debounce {
 7590                        editor.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7591                        editor.debounced_selection_highlight_complete = true;
 7592                    } else if editor.debounced_selection_highlight_complete {
 7593                        return;
 7594                    }
 7595                    if !match_ranges.is_empty() {
 7596                        editor.highlight_background(
 7597                            HighlightKey::SelectedTextHighlight,
 7598                            &match_ranges,
 7599                            |_, theme| theme.colors().editor_document_highlight_bracket_background,
 7600                            cx,
 7601                        )
 7602                    }
 7603                })
 7604                .log_err();
 7605        })
 7606    }
 7607
 7608    fn refresh_single_line_folds(&mut self, window: &mut Window, cx: &mut Context<Editor>) {
 7609        struct NewlineFold;
 7610        let type_id = std::any::TypeId::of::<NewlineFold>();
 7611        if !self.mode.is_single_line() {
 7612            return;
 7613        }
 7614        let snapshot = self.snapshot(window, cx);
 7615        if snapshot.buffer_snapshot().max_point().row == 0 {
 7616            return;
 7617        }
 7618        let task = cx.background_spawn(async move {
 7619            let new_newlines = snapshot
 7620                .buffer_chars_at(MultiBufferOffset(0))
 7621                .filter_map(|(c, i)| {
 7622                    if c == '\n' {
 7623                        Some(
 7624                            snapshot.buffer_snapshot().anchor_after(i)
 7625                                ..snapshot.buffer_snapshot().anchor_before(i + 1usize),
 7626                        )
 7627                    } else {
 7628                        None
 7629                    }
 7630                })
 7631                .collect::<Vec<_>>();
 7632            let existing_newlines = snapshot
 7633                .folds_in_range(MultiBufferOffset(0)..snapshot.buffer_snapshot().len())
 7634                .filter_map(|fold| {
 7635                    if fold.placeholder.type_tag == Some(type_id) {
 7636                        Some(fold.range.start..fold.range.end)
 7637                    } else {
 7638                        None
 7639                    }
 7640                })
 7641                .collect::<Vec<_>>();
 7642
 7643            (new_newlines, existing_newlines)
 7644        });
 7645        self.folding_newlines = cx.spawn(async move |this, cx| {
 7646            let (new_newlines, existing_newlines) = task.await;
 7647            if new_newlines == existing_newlines {
 7648                return;
 7649            }
 7650            let placeholder = FoldPlaceholder {
 7651                render: Arc::new(move |_, _, cx| {
 7652                    div()
 7653                        .bg(cx.theme().status().hint_background)
 7654                        .border_b_1()
 7655                        .size_full()
 7656                        .font(ThemeSettings::get_global(cx).buffer_font.clone())
 7657                        .border_color(cx.theme().status().hint)
 7658                        .child("\\n")
 7659                        .into_any()
 7660                }),
 7661                constrain_width: false,
 7662                merge_adjacent: false,
 7663                type_tag: Some(type_id),
 7664                collapsed_text: None,
 7665            };
 7666            let creases = new_newlines
 7667                .into_iter()
 7668                .map(|range| Crease::simple(range, placeholder.clone()))
 7669                .collect();
 7670            this.update(cx, |this, cx| {
 7671                this.display_map.update(cx, |display_map, cx| {
 7672                    display_map.remove_folds_with_type(existing_newlines, type_id, cx);
 7673                    display_map.fold(creases, cx);
 7674                });
 7675            })
 7676            .ok();
 7677        });
 7678    }
 7679
 7680    #[ztracing::instrument(skip_all)]
 7681    fn refresh_outline_symbols_at_cursor(&mut self, cx: &mut Context<Editor>) {
 7682        if !self.lsp_data_enabled() {
 7683            return;
 7684        }
 7685        let cursor = self.selections.newest_anchor().head();
 7686        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7687
 7688        if self.uses_lsp_document_symbols(cursor, &multi_buffer_snapshot, cx) {
 7689            self.outline_symbols_at_cursor =
 7690                self.lsp_symbols_at_cursor(cursor, &multi_buffer_snapshot, cx);
 7691            cx.emit(EditorEvent::OutlineSymbolsChanged);
 7692            cx.notify();
 7693        } else {
 7694            let syntax = cx.theme().syntax().clone();
 7695            let background_task = cx.background_spawn(async move {
 7696                multi_buffer_snapshot.symbols_containing(cursor, Some(&syntax))
 7697            });
 7698            self.refresh_outline_symbols_at_cursor_at_cursor_task =
 7699                cx.spawn(async move |this, cx| {
 7700                    let symbols = background_task.await;
 7701                    this.update(cx, |this, cx| {
 7702                        this.outline_symbols_at_cursor = symbols;
 7703                        cx.emit(EditorEvent::OutlineSymbolsChanged);
 7704                        cx.notify();
 7705                    })
 7706                    .ok();
 7707                });
 7708        }
 7709    }
 7710
 7711    #[ztracing::instrument(skip_all)]
 7712    fn refresh_selected_text_highlights(
 7713        &mut self,
 7714        snapshot: &DisplaySnapshot,
 7715        on_buffer_edit: bool,
 7716        window: &mut Window,
 7717        cx: &mut Context<Editor>,
 7718    ) {
 7719        let Some((query_text, query_range)) =
 7720            self.prepare_highlight_query_from_selection(snapshot, cx)
 7721        else {
 7722            self.clear_background_highlights(HighlightKey::SelectedTextHighlight, cx);
 7723            self.quick_selection_highlight_task.take();
 7724            self.debounced_selection_highlight_task.take();
 7725            self.debounced_selection_highlight_complete = false;
 7726            return;
 7727        };
 7728        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
 7729        let multi_buffer_snapshot = self.buffer().read(cx).snapshot(cx);
 7730        let query_changed = self
 7731            .quick_selection_highlight_task
 7732            .as_ref()
 7733            .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range);
 7734        if query_changed {
 7735            self.debounced_selection_highlight_complete = false;
 7736        }
 7737        if on_buffer_edit || query_changed {
 7738            self.quick_selection_highlight_task = Some((
 7739                query_range.clone(),
 7740                self.update_selection_occurrence_highlights(
 7741                    snapshot.buffer.clone(),
 7742                    query_text.clone(),
 7743                    query_range.clone(),
 7744                    self.multi_buffer_visible_range(&display_snapshot, cx),
 7745                    false,
 7746                    window,
 7747                    cx,
 7748                ),
 7749            ));
 7750        }
 7751        if on_buffer_edit
 7752            || self
 7753                .debounced_selection_highlight_task
 7754                .as_ref()
 7755                .is_none_or(|(prev_anchor_range, _)| prev_anchor_range != &query_range)
 7756        {
 7757            let multi_buffer_start = multi_buffer_snapshot
 7758                .anchor_before(MultiBufferOffset(0))
 7759                .to_point(&multi_buffer_snapshot);
 7760            let multi_buffer_end = multi_buffer_snapshot
 7761                .anchor_after(multi_buffer_snapshot.len())
 7762                .to_point(&multi_buffer_snapshot);
 7763            let multi_buffer_full_range = multi_buffer_start..multi_buffer_end;
 7764            self.debounced_selection_highlight_task = Some((
 7765                query_range.clone(),
 7766                self.update_selection_occurrence_highlights(
 7767                    snapshot.buffer.clone(),
 7768                    query_text,
 7769                    query_range,
 7770                    multi_buffer_full_range,
 7771                    true,
 7772                    window,
 7773                    cx,
 7774                ),
 7775            ));
 7776        }
 7777    }
 7778
 7779    pub fn multi_buffer_visible_range(
 7780        &self,
 7781        display_snapshot: &DisplaySnapshot,
 7782        cx: &App,
 7783    ) -> Range<Point> {
 7784        let visible_start = self
 7785            .scroll_manager
 7786            .native_anchor(display_snapshot, cx)
 7787            .anchor
 7788            .to_point(display_snapshot.buffer_snapshot())
 7789            .to_display_point(display_snapshot);
 7790
 7791        let mut target_end = visible_start;
 7792        *target_end.row_mut() += self.visible_line_count().unwrap_or(0.).ceil() as u32;
 7793
 7794        visible_start.to_point(display_snapshot)
 7795            ..display_snapshot
 7796                .clip_point(target_end, Bias::Right)
 7797                .to_point(display_snapshot)
 7798    }
 7799
 7800    pub fn refresh_edit_prediction(
 7801        &mut self,
 7802        debounce: bool,
 7803        user_requested: bool,
 7804        window: &mut Window,
 7805        cx: &mut Context<Self>,
 7806    ) -> Option<()> {
 7807        let provider = self.edit_prediction_provider()?;
 7808        let cursor = self.selections.newest_anchor().head();
 7809        let (buffer, cursor_buffer_position) =
 7810            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 7811
 7812        if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 7813            return None;
 7814        }
 7815
 7816        if !self.edit_predictions_enabled_in_buffer(&buffer, cursor_buffer_position, cx) {
 7817            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7818            return None;
 7819        }
 7820
 7821        self.update_visible_edit_prediction(window, cx);
 7822
 7823        if !user_requested
 7824            && (!self.should_show_edit_predictions()
 7825                || !self.is_focused(window)
 7826                || buffer.read(cx).is_empty())
 7827        {
 7828            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7829            return None;
 7830        }
 7831
 7832        provider.refresh(buffer, cursor_buffer_position, debounce, cx);
 7833        Some(())
 7834    }
 7835
 7836    fn show_edit_predictions_in_menu(&self) -> bool {
 7837        match self.edit_prediction_settings {
 7838            EditPredictionSettings::Disabled => false,
 7839            EditPredictionSettings::Enabled { show_in_menu, .. } => show_in_menu,
 7840        }
 7841    }
 7842
 7843    pub fn edit_predictions_enabled(&self) -> bool {
 7844        match self.edit_prediction_settings {
 7845            EditPredictionSettings::Disabled => false,
 7846            EditPredictionSettings::Enabled { .. } => true,
 7847        }
 7848    }
 7849
 7850    fn edit_prediction_requires_modifier(&self) -> bool {
 7851        match self.edit_prediction_settings {
 7852            EditPredictionSettings::Disabled => false,
 7853            EditPredictionSettings::Enabled {
 7854                preview_requires_modifier,
 7855                ..
 7856            } => preview_requires_modifier,
 7857        }
 7858    }
 7859
 7860    pub fn update_edit_prediction_settings(&mut self, cx: &mut Context<Self>) {
 7861        if self.edit_prediction_provider.is_none() {
 7862            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7863            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7864            return;
 7865        }
 7866
 7867        let selection = self.selections.newest_anchor();
 7868        let cursor = selection.head();
 7869
 7870        if let Some((buffer, cursor_buffer_position)) =
 7871            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7872        {
 7873            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 7874                self.edit_prediction_settings = EditPredictionSettings::Disabled;
 7875                self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 7876                return;
 7877            }
 7878            self.edit_prediction_settings =
 7879                self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 7880        }
 7881    }
 7882
 7883    fn edit_prediction_settings_at_position(
 7884        &self,
 7885        buffer: &Entity<Buffer>,
 7886        buffer_position: language::Anchor,
 7887        cx: &App,
 7888    ) -> EditPredictionSettings {
 7889        if !self.mode.is_full()
 7890            || !self.show_edit_predictions_override.unwrap_or(true)
 7891            || self.edit_predictions_disabled_in_scope(buffer, buffer_position, cx)
 7892        {
 7893            return EditPredictionSettings::Disabled;
 7894        }
 7895
 7896        let buffer = buffer.read(cx);
 7897
 7898        let file = buffer.file();
 7899
 7900        if !language_settings(buffer.language().map(|l| l.name()), file, cx).show_edit_predictions {
 7901            return EditPredictionSettings::Disabled;
 7902        };
 7903
 7904        let by_provider = matches!(
 7905            self.menu_edit_predictions_policy,
 7906            MenuEditPredictionsPolicy::ByProvider
 7907        );
 7908
 7909        let show_in_menu = by_provider
 7910            && self
 7911                .edit_prediction_provider
 7912                .as_ref()
 7913                .is_some_and(|provider| provider.provider.show_predictions_in_menu());
 7914
 7915        let preview_requires_modifier =
 7916            all_language_settings(file, cx).edit_predictions_mode() == EditPredictionsMode::Subtle;
 7917
 7918        EditPredictionSettings::Enabled {
 7919            show_in_menu,
 7920            preview_requires_modifier,
 7921        }
 7922    }
 7923
 7924    fn should_show_edit_predictions(&self) -> bool {
 7925        self.snippet_stack.is_empty() && self.edit_predictions_enabled()
 7926    }
 7927
 7928    pub fn edit_prediction_preview_is_active(&self) -> bool {
 7929        matches!(
 7930            self.edit_prediction_preview,
 7931            EditPredictionPreview::Active { .. }
 7932        )
 7933    }
 7934
 7935    pub fn edit_predictions_enabled_at_cursor(&self, cx: &App) -> bool {
 7936        let cursor = self.selections.newest_anchor().head();
 7937        if let Some((buffer, cursor_position)) =
 7938            self.buffer.read(cx).text_anchor_for_position(cursor, cx)
 7939        {
 7940            self.edit_predictions_enabled_in_buffer(&buffer, cursor_position, cx)
 7941        } else {
 7942            false
 7943        }
 7944    }
 7945
 7946    pub fn supports_minimap(&self, cx: &App) -> bool {
 7947        !self.minimap_visibility.disabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton
 7948    }
 7949
 7950    fn edit_predictions_enabled_in_buffer(
 7951        &self,
 7952        buffer: &Entity<Buffer>,
 7953        buffer_position: language::Anchor,
 7954        cx: &App,
 7955    ) -> bool {
 7956        maybe!({
 7957            if self.read_only(cx) {
 7958                return Some(false);
 7959            }
 7960            let provider = self.edit_prediction_provider()?;
 7961            if !provider.is_enabled(buffer, buffer_position, cx) {
 7962                return Some(false);
 7963            }
 7964            let buffer = buffer.read(cx);
 7965            let Some(file) = buffer.file() else {
 7966                return Some(true);
 7967            };
 7968            let settings = all_language_settings(Some(file), cx);
 7969            Some(settings.edit_predictions_enabled_for_file(file, cx))
 7970        })
 7971        .unwrap_or(false)
 7972    }
 7973
 7974    pub fn show_edit_prediction(
 7975        &mut self,
 7976        _: &ShowEditPrediction,
 7977        window: &mut Window,
 7978        cx: &mut Context<Self>,
 7979    ) {
 7980        if !self.has_active_edit_prediction() {
 7981            self.refresh_edit_prediction(false, true, window, cx);
 7982            return;
 7983        }
 7984
 7985        self.update_visible_edit_prediction(window, cx);
 7986    }
 7987
 7988    pub fn display_cursor_names(
 7989        &mut self,
 7990        _: &DisplayCursorNames,
 7991        window: &mut Window,
 7992        cx: &mut Context<Self>,
 7993    ) {
 7994        self.show_cursor_names(window, cx);
 7995    }
 7996
 7997    fn show_cursor_names(&mut self, window: &mut Window, cx: &mut Context<Self>) {
 7998        self.show_cursor_names = true;
 7999        cx.notify();
 8000        cx.spawn_in(window, async move |this, cx| {
 8001            cx.background_executor().timer(CURSORS_VISIBLE_FOR).await;
 8002            this.update(cx, |this, cx| {
 8003                this.show_cursor_names = false;
 8004                cx.notify()
 8005            })
 8006            .ok()
 8007        })
 8008        .detach();
 8009    }
 8010
 8011    pub fn accept_partial_edit_prediction(
 8012        &mut self,
 8013        granularity: EditPredictionGranularity,
 8014        window: &mut Window,
 8015        cx: &mut Context<Self>,
 8016    ) {
 8017        if self.show_edit_predictions_in_menu() {
 8018            self.hide_context_menu(window, cx);
 8019        }
 8020
 8021        let Some(active_edit_prediction) = self.active_edit_prediction.as_ref() else {
 8022            return;
 8023        };
 8024
 8025        if !matches!(granularity, EditPredictionGranularity::Full) && self.selections.count() != 1 {
 8026            return;
 8027        }
 8028
 8029        match &active_edit_prediction.completion {
 8030            EditPrediction::MoveWithin { target, .. } => {
 8031                let target = *target;
 8032
 8033                if matches!(granularity, EditPredictionGranularity::Full) {
 8034                    if let Some(position_map) = &self.last_position_map {
 8035                        let target_row = target.to_display_point(&position_map.snapshot).row();
 8036                        let is_visible = position_map.visible_row_range.contains(&target_row);
 8037
 8038                        if is_visible || !self.edit_prediction_requires_modifier() {
 8039                            self.unfold_ranges(&[target..target], true, false, cx);
 8040                            self.change_selections(
 8041                                SelectionEffects::scroll(Autoscroll::newest()),
 8042                                window,
 8043                                cx,
 8044                                |selections| {
 8045                                    selections.select_anchor_ranges([target..target]);
 8046                                },
 8047                            );
 8048                            self.clear_row_highlights::<EditPredictionPreview>();
 8049                            self.edit_prediction_preview
 8050                                .set_previous_scroll_position(None);
 8051                        } else {
 8052                            // Highlight and request scroll
 8053                            self.edit_prediction_preview
 8054                                .set_previous_scroll_position(Some(
 8055                                    position_map.snapshot.scroll_anchor,
 8056                                ));
 8057                            self.highlight_rows::<EditPredictionPreview>(
 8058                                target..target,
 8059                                cx.theme().colors().editor_highlighted_line_background,
 8060                                RowHighlightOptions {
 8061                                    autoscroll: true,
 8062                                    ..Default::default()
 8063                                },
 8064                                cx,
 8065                            );
 8066                            self.request_autoscroll(Autoscroll::fit(), cx);
 8067                        }
 8068                    }
 8069                } else {
 8070                    self.change_selections(
 8071                        SelectionEffects::scroll(Autoscroll::newest()),
 8072                        window,
 8073                        cx,
 8074                        |selections| {
 8075                            selections.select_anchor_ranges([target..target]);
 8076                        },
 8077                    );
 8078                }
 8079            }
 8080            EditPrediction::MoveOutside { snapshot, target } => {
 8081                if let Some(workspace) = self.workspace() {
 8082                    Self::open_editor_at_anchor(snapshot, *target, &workspace, window, cx)
 8083                        .detach_and_log_err(cx);
 8084                }
 8085            }
 8086            EditPrediction::Edit {
 8087                edits,
 8088                cursor_position,
 8089                ..
 8090            } => {
 8091                self.report_edit_prediction_event(
 8092                    active_edit_prediction.completion_id.clone(),
 8093                    true,
 8094                    cx,
 8095                );
 8096
 8097                match granularity {
 8098                    EditPredictionGranularity::Full => {
 8099                        let transaction_id_prev = self.buffer.read(cx).last_transaction_id(cx);
 8100
 8101                        // Compute fallback cursor position BEFORE applying the edit,
 8102                        // so the anchor tracks through the edit correctly
 8103                        let fallback_cursor_target = {
 8104                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8105                            edits.last().unwrap().0.end.bias_right(&snapshot)
 8106                        };
 8107
 8108                        self.buffer.update(cx, |buffer, cx| {
 8109                            buffer.edit(edits.iter().cloned(), None, cx)
 8110                        });
 8111
 8112                        if let Some(provider) = self.edit_prediction_provider() {
 8113                            provider.accept(cx);
 8114                        }
 8115
 8116                        // Resolve cursor position after the edit is applied
 8117                        let cursor_target = if let Some((anchor, offset)) = cursor_position {
 8118                            // The anchor tracks through the edit, then we add the offset
 8119                            let snapshot = self.buffer.read(cx).snapshot(cx);
 8120                            let base_offset = anchor.to_offset(&snapshot).0;
 8121                            let target_offset =
 8122                                MultiBufferOffset((base_offset + offset).min(snapshot.len().0));
 8123                            snapshot.anchor_after(target_offset)
 8124                        } else {
 8125                            fallback_cursor_target
 8126                        };
 8127
 8128                        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
 8129                            s.select_anchor_ranges([cursor_target..cursor_target]);
 8130                        });
 8131
 8132                        let selections = self.selections.disjoint_anchors_arc();
 8133                        if let Some(transaction_id_now) =
 8134                            self.buffer.read(cx).last_transaction_id(cx)
 8135                        {
 8136                            if transaction_id_prev != Some(transaction_id_now) {
 8137                                self.selection_history
 8138                                    .insert_transaction(transaction_id_now, selections);
 8139                            }
 8140                        }
 8141
 8142                        self.update_visible_edit_prediction(window, cx);
 8143                        if self.active_edit_prediction.is_none() {
 8144                            self.refresh_edit_prediction(true, true, window, cx);
 8145                        }
 8146                        cx.notify();
 8147                    }
 8148                    _ => {
 8149                        let snapshot = self.buffer.read(cx).snapshot(cx);
 8150                        let cursor_offset = self
 8151                            .selections
 8152                            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
 8153                            .head();
 8154
 8155                        let insertion = edits.iter().find_map(|(range, text)| {
 8156                            let range = range.to_offset(&snapshot);
 8157                            if range.is_empty() && range.start == cursor_offset {
 8158                                Some(text)
 8159                            } else {
 8160                                None
 8161                            }
 8162                        });
 8163
 8164                        if let Some(text) = insertion {
 8165                            let text_to_insert = match granularity {
 8166                                EditPredictionGranularity::Word => {
 8167                                    let mut partial = text
 8168                                        .chars()
 8169                                        .by_ref()
 8170                                        .take_while(|c| c.is_alphabetic())
 8171                                        .collect::<String>();
 8172                                    if partial.is_empty() {
 8173                                        partial = text
 8174                                            .chars()
 8175                                            .by_ref()
 8176                                            .take_while(|c| c.is_whitespace() || !c.is_alphabetic())
 8177                                            .collect::<String>();
 8178                                    }
 8179                                    partial
 8180                                }
 8181                                EditPredictionGranularity::Line => {
 8182                                    if let Some(line) = text.split_inclusive('\n').next() {
 8183                                        line.to_string()
 8184                                    } else {
 8185                                        text.to_string()
 8186                                    }
 8187                                }
 8188                                EditPredictionGranularity::Full => unreachable!(),
 8189                            };
 8190
 8191                            cx.emit(EditorEvent::InputHandled {
 8192                                utf16_range_to_replace: None,
 8193                                text: text_to_insert.clone().into(),
 8194                            });
 8195
 8196                            self.replace_selections(&text_to_insert, None, window, cx, false);
 8197                            self.refresh_edit_prediction(true, true, window, cx);
 8198                            cx.notify();
 8199                        } else {
 8200                            self.accept_partial_edit_prediction(
 8201                                EditPredictionGranularity::Full,
 8202                                window,
 8203                                cx,
 8204                            );
 8205                        }
 8206                    }
 8207                }
 8208            }
 8209        }
 8210
 8211        self.edit_prediction_requires_modifier_in_indent_conflict = false;
 8212    }
 8213
 8214    pub fn accept_next_word_edit_prediction(
 8215        &mut self,
 8216        _: &AcceptNextWordEditPrediction,
 8217        window: &mut Window,
 8218        cx: &mut Context<Self>,
 8219    ) {
 8220        self.accept_partial_edit_prediction(EditPredictionGranularity::Word, window, cx);
 8221    }
 8222
 8223    pub fn accept_next_line_edit_prediction(
 8224        &mut self,
 8225        _: &AcceptNextLineEditPrediction,
 8226        window: &mut Window,
 8227        cx: &mut Context<Self>,
 8228    ) {
 8229        self.accept_partial_edit_prediction(EditPredictionGranularity::Line, window, cx);
 8230    }
 8231
 8232    pub fn accept_edit_prediction(
 8233        &mut self,
 8234        _: &AcceptEditPrediction,
 8235        window: &mut Window,
 8236        cx: &mut Context<Self>,
 8237    ) {
 8238        self.accept_partial_edit_prediction(EditPredictionGranularity::Full, window, cx);
 8239    }
 8240
 8241    fn discard_edit_prediction(
 8242        &mut self,
 8243        reason: EditPredictionDiscardReason,
 8244        cx: &mut Context<Self>,
 8245    ) -> bool {
 8246        if reason == EditPredictionDiscardReason::Rejected {
 8247            let completion_id = self
 8248                .active_edit_prediction
 8249                .as_ref()
 8250                .and_then(|active_completion| active_completion.completion_id.clone());
 8251
 8252            self.report_edit_prediction_event(completion_id, false, cx);
 8253        }
 8254
 8255        if let Some(provider) = self.edit_prediction_provider() {
 8256            provider.discard(reason, cx);
 8257        }
 8258
 8259        self.take_active_edit_prediction(cx)
 8260    }
 8261
 8262    fn report_edit_prediction_event(&self, id: Option<SharedString>, accepted: bool, cx: &App) {
 8263        let Some(provider) = self.edit_prediction_provider() else {
 8264            return;
 8265        };
 8266
 8267        let Some((_, buffer, _)) = self
 8268            .buffer
 8269            .read(cx)
 8270            .excerpt_containing(self.selections.newest_anchor().head(), cx)
 8271        else {
 8272            return;
 8273        };
 8274
 8275        let extension = buffer
 8276            .read(cx)
 8277            .file()
 8278            .and_then(|file| Some(file.path().extension()?.to_string()));
 8279
 8280        let event_type = match accepted {
 8281            true => "Edit Prediction Accepted",
 8282            false => "Edit Prediction Discarded",
 8283        };
 8284        telemetry::event!(
 8285            event_type,
 8286            provider = provider.name(),
 8287            prediction_id = id,
 8288            suggestion_accepted = accepted,
 8289            file_extension = extension,
 8290        );
 8291    }
 8292
 8293    fn open_editor_at_anchor(
 8294        snapshot: &language::BufferSnapshot,
 8295        target: language::Anchor,
 8296        workspace: &Entity<Workspace>,
 8297        window: &mut Window,
 8298        cx: &mut App,
 8299    ) -> Task<Result<()>> {
 8300        workspace.update(cx, |workspace, cx| {
 8301            let path = snapshot.file().map(|file| file.full_path(cx));
 8302            let Some(path) =
 8303                path.and_then(|path| workspace.project().read(cx).find_project_path(path, cx))
 8304            else {
 8305                return Task::ready(Err(anyhow::anyhow!("Project path not found")));
 8306            };
 8307            let target = text::ToPoint::to_point(&target, snapshot);
 8308            let item = workspace.open_path(path, None, true, window, cx);
 8309            window.spawn(cx, async move |cx| {
 8310                let Some(editor) = item.await?.downcast::<Editor>() else {
 8311                    return Ok(());
 8312                };
 8313                editor
 8314                    .update_in(cx, |editor, window, cx| {
 8315                        editor.go_to_singleton_buffer_point(target, window, cx);
 8316                    })
 8317                    .ok();
 8318                anyhow::Ok(())
 8319            })
 8320        })
 8321    }
 8322
 8323    pub fn has_active_edit_prediction(&self) -> bool {
 8324        self.active_edit_prediction.is_some()
 8325    }
 8326
 8327    fn take_active_edit_prediction(&mut self, cx: &mut Context<Self>) -> bool {
 8328        let Some(active_edit_prediction) = self.active_edit_prediction.take() else {
 8329            return false;
 8330        };
 8331
 8332        self.splice_inlays(&active_edit_prediction.inlay_ids, Default::default(), cx);
 8333        self.clear_highlights(HighlightKey::EditPredictionHighlight, cx);
 8334        self.stale_edit_prediction_in_menu = Some(active_edit_prediction);
 8335        true
 8336    }
 8337
 8338    /// Returns true when we're displaying the edit prediction popover below the cursor
 8339    /// like we are not previewing and the LSP autocomplete menu is visible
 8340    /// or we are in `when_holding_modifier` mode.
 8341    pub fn edit_prediction_visible_in_cursor_popover(&self, has_completion: bool) -> bool {
 8342        if self.edit_prediction_preview_is_active()
 8343            || !self.show_edit_predictions_in_menu()
 8344            || !self.edit_predictions_enabled()
 8345        {
 8346            return false;
 8347        }
 8348
 8349        if self.has_visible_completions_menu() {
 8350            return true;
 8351        }
 8352
 8353        has_completion && self.edit_prediction_requires_modifier()
 8354    }
 8355
 8356    fn handle_modifiers_changed(
 8357        &mut self,
 8358        modifiers: Modifiers,
 8359        position_map: &PositionMap,
 8360        window: &mut Window,
 8361        cx: &mut Context<Self>,
 8362    ) {
 8363        // Ensure that the edit prediction preview is updated, even when not
 8364        // enabled, if there's an active edit prediction preview.
 8365        if self.show_edit_predictions_in_menu()
 8366            || matches!(
 8367                self.edit_prediction_preview,
 8368                EditPredictionPreview::Active { .. }
 8369            )
 8370        {
 8371            self.update_edit_prediction_preview(&modifiers, window, cx);
 8372        }
 8373
 8374        self.update_selection_mode(&modifiers, position_map, window, cx);
 8375
 8376        let mouse_position = window.mouse_position();
 8377        if !position_map.text_hitbox.is_hovered(window) {
 8378            return;
 8379        }
 8380
 8381        self.update_hovered_link(
 8382            position_map.point_for_position(mouse_position),
 8383            Some(mouse_position),
 8384            &position_map.snapshot,
 8385            modifiers,
 8386            window,
 8387            cx,
 8388        )
 8389    }
 8390
 8391    fn is_cmd_or_ctrl_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8392        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8393            MultiCursorModifier::Alt => modifiers.secondary(),
 8394            MultiCursorModifier::CmdOrCtrl => modifiers.alt,
 8395        }
 8396    }
 8397
 8398    fn is_alt_pressed(modifiers: &Modifiers, cx: &mut Context<Self>) -> bool {
 8399        match EditorSettings::get_global(cx).multi_cursor_modifier {
 8400            MultiCursorModifier::Alt => modifiers.alt,
 8401            MultiCursorModifier::CmdOrCtrl => modifiers.secondary(),
 8402        }
 8403    }
 8404
 8405    fn columnar_selection_mode(
 8406        modifiers: &Modifiers,
 8407        cx: &mut Context<Self>,
 8408    ) -> Option<ColumnarMode> {
 8409        if modifiers.shift && modifiers.number_of_modifiers() == 2 {
 8410            if Self::is_cmd_or_ctrl_pressed(modifiers, cx) {
 8411                Some(ColumnarMode::FromMouse)
 8412            } else if Self::is_alt_pressed(modifiers, cx) {
 8413                Some(ColumnarMode::FromSelection)
 8414            } else {
 8415                None
 8416            }
 8417        } else {
 8418            None
 8419        }
 8420    }
 8421
 8422    fn update_selection_mode(
 8423        &mut self,
 8424        modifiers: &Modifiers,
 8425        position_map: &PositionMap,
 8426        window: &mut Window,
 8427        cx: &mut Context<Self>,
 8428    ) {
 8429        let Some(mode) = Self::columnar_selection_mode(modifiers, cx) else {
 8430            return;
 8431        };
 8432        if self.selections.pending_anchor().is_none() {
 8433            return;
 8434        }
 8435
 8436        let mouse_position = window.mouse_position();
 8437        let point_for_position = position_map.point_for_position(mouse_position);
 8438        let position = point_for_position.previous_valid;
 8439
 8440        self.select(
 8441            SelectPhase::BeginColumnar {
 8442                position,
 8443                reset: false,
 8444                mode,
 8445                goal_column: point_for_position.exact_unclipped.column(),
 8446            },
 8447            window,
 8448            cx,
 8449        );
 8450    }
 8451
 8452    fn update_edit_prediction_preview(
 8453        &mut self,
 8454        modifiers: &Modifiers,
 8455        window: &mut Window,
 8456        cx: &mut Context<Self>,
 8457    ) {
 8458        let mut modifiers_held = false;
 8459
 8460        // Check bindings for all granularities.
 8461        // If the user holds the key for Word, Line, or Full, we want to show the preview.
 8462        let granularities = [
 8463            EditPredictionGranularity::Full,
 8464            EditPredictionGranularity::Line,
 8465            EditPredictionGranularity::Word,
 8466        ];
 8467
 8468        for granularity in granularities {
 8469            if let Some(keystroke) = self
 8470                .accept_edit_prediction_keybind(granularity, window, cx)
 8471                .keystroke()
 8472            {
 8473                modifiers_held = modifiers_held
 8474                    || (keystroke.modifiers() == modifiers && keystroke.modifiers().modified());
 8475            }
 8476        }
 8477
 8478        if modifiers_held {
 8479            if matches!(
 8480                self.edit_prediction_preview,
 8481                EditPredictionPreview::Inactive { .. }
 8482            ) {
 8483                self.edit_prediction_preview = EditPredictionPreview::Active {
 8484                    previous_scroll_position: None,
 8485                    since: Instant::now(),
 8486                };
 8487
 8488                self.update_visible_edit_prediction(window, cx);
 8489                cx.notify();
 8490            }
 8491        } else if let EditPredictionPreview::Active {
 8492            previous_scroll_position,
 8493            since,
 8494        } = self.edit_prediction_preview
 8495        {
 8496            if let (Some(previous_scroll_position), Some(position_map)) =
 8497                (previous_scroll_position, self.last_position_map.as_ref())
 8498            {
 8499                self.set_scroll_position(
 8500                    previous_scroll_position
 8501                        .scroll_position(&position_map.snapshot.display_snapshot),
 8502                    window,
 8503                    cx,
 8504                );
 8505            }
 8506
 8507            self.edit_prediction_preview = EditPredictionPreview::Inactive {
 8508                released_too_fast: since.elapsed() < Duration::from_millis(200),
 8509            };
 8510            self.clear_row_highlights::<EditPredictionPreview>();
 8511            self.update_visible_edit_prediction(window, cx);
 8512            cx.notify();
 8513        }
 8514    }
 8515
 8516    fn update_visible_edit_prediction(
 8517        &mut self,
 8518        _window: &mut Window,
 8519        cx: &mut Context<Self>,
 8520    ) -> Option<()> {
 8521        if self.ime_transaction.is_some() {
 8522            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8523            return None;
 8524        }
 8525
 8526        let selection = self.selections.newest_anchor();
 8527        let cursor = selection.head();
 8528        let multibuffer = self.buffer.read(cx).snapshot(cx);
 8529
 8530        // Check project-level disable_ai setting for the current buffer
 8531        if let Some((buffer, _)) = self.buffer.read(cx).text_anchor_for_position(cursor, cx) {
 8532            if DisableAiSettings::is_ai_disabled_for_buffer(Some(&buffer), cx) {
 8533                return None;
 8534            }
 8535        }
 8536        let offset_selection = selection.map(|endpoint| endpoint.to_offset(&multibuffer));
 8537        let excerpt_id = cursor.excerpt_id;
 8538
 8539        let show_in_menu = self.show_edit_predictions_in_menu();
 8540        let completions_menu_has_precedence = !show_in_menu
 8541            && (self.context_menu.borrow().is_some()
 8542                || (!self.completion_tasks.is_empty() && !self.has_active_edit_prediction()));
 8543
 8544        if completions_menu_has_precedence
 8545            || !offset_selection.is_empty()
 8546            || self
 8547                .active_edit_prediction
 8548                .as_ref()
 8549                .is_some_and(|completion| {
 8550                    let Some(invalidation_range) = completion.invalidation_range.as_ref() else {
 8551                        return false;
 8552                    };
 8553                    let invalidation_range = invalidation_range.to_offset(&multibuffer);
 8554                    let invalidation_range = invalidation_range.start..=invalidation_range.end;
 8555                    !invalidation_range.contains(&offset_selection.head())
 8556                })
 8557        {
 8558            self.discard_edit_prediction(EditPredictionDiscardReason::Ignored, cx);
 8559            return None;
 8560        }
 8561
 8562        self.take_active_edit_prediction(cx);
 8563        let Some(provider) = self.edit_prediction_provider() else {
 8564            self.edit_prediction_settings = EditPredictionSettings::Disabled;
 8565            return None;
 8566        };
 8567
 8568        let (buffer, cursor_buffer_position) =
 8569            self.buffer.read(cx).text_anchor_for_position(cursor, cx)?;
 8570
 8571        self.edit_prediction_settings =
 8572            self.edit_prediction_settings_at_position(&buffer, cursor_buffer_position, cx);
 8573
 8574        self.edit_prediction_indent_conflict = multibuffer.is_line_whitespace_upto(cursor);
 8575
 8576        if self.edit_prediction_indent_conflict {
 8577            let cursor_point = cursor.to_point(&multibuffer);
 8578            let mut suggested_indent = None;
 8579            multibuffer.suggested_indents_callback(
 8580                cursor_point.row..cursor_point.row + 1,
 8581                &mut |_, indent| {
 8582                    suggested_indent = Some(indent);
 8583                    ControlFlow::Break(())
 8584                },
 8585                cx,
 8586            );
 8587
 8588            if let Some(indent) = suggested_indent
 8589                && indent.len == cursor_point.column
 8590            {
 8591                self.edit_prediction_indent_conflict = false;
 8592            }
 8593        }
 8594
 8595        let edit_prediction = provider.suggest(&buffer, cursor_buffer_position, cx)?;
 8596
 8597        let (completion_id, edits, predicted_cursor_position, edit_preview) = match edit_prediction
 8598        {
 8599            edit_prediction_types::EditPrediction::Local {
 8600                id,
 8601                edits,
 8602                cursor_position,
 8603                edit_preview,
 8604            } => (id, edits, cursor_position, edit_preview),
 8605            edit_prediction_types::EditPrediction::Jump {
 8606                id,
 8607                snapshot,
 8608                target,
 8609            } => {
 8610                if let Some(provider) = &self.edit_prediction_provider {
 8611                    provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8612                }
 8613                self.stale_edit_prediction_in_menu = None;
 8614                self.active_edit_prediction = Some(EditPredictionState {
 8615                    inlay_ids: vec![],
 8616                    completion: EditPrediction::MoveOutside { snapshot, target },
 8617                    completion_id: id,
 8618                    invalidation_range: None,
 8619                });
 8620                cx.notify();
 8621                return Some(());
 8622            }
 8623        };
 8624
 8625        let edits = edits
 8626            .into_iter()
 8627            .flat_map(|(range, new_text)| {
 8628                Some((
 8629                    multibuffer.anchor_range_in_excerpt(excerpt_id, range)?,
 8630                    new_text,
 8631                ))
 8632            })
 8633            .collect::<Vec<_>>();
 8634        if edits.is_empty() {
 8635            return None;
 8636        }
 8637
 8638        let cursor_position = predicted_cursor_position.and_then(|predicted| {
 8639            let anchor = multibuffer.anchor_in_excerpt(excerpt_id, predicted.anchor)?;
 8640            Some((anchor, predicted.offset))
 8641        });
 8642
 8643        let first_edit_start = edits.first().unwrap().0.start;
 8644        let first_edit_start_point = first_edit_start.to_point(&multibuffer);
 8645        let edit_start_row = first_edit_start_point.row.saturating_sub(2);
 8646
 8647        let last_edit_end = edits.last().unwrap().0.end;
 8648        let last_edit_end_point = last_edit_end.to_point(&multibuffer);
 8649        let edit_end_row = cmp::min(multibuffer.max_point().row, last_edit_end_point.row + 2);
 8650
 8651        let cursor_row = cursor.to_point(&multibuffer).row;
 8652
 8653        let snapshot = multibuffer.buffer_for_excerpt(excerpt_id).cloned()?;
 8654
 8655        let mut inlay_ids = Vec::new();
 8656        let invalidation_row_range;
 8657        let move_invalidation_row_range = if cursor_row < edit_start_row {
 8658            Some(cursor_row..edit_end_row)
 8659        } else if cursor_row > edit_end_row {
 8660            Some(edit_start_row..cursor_row)
 8661        } else {
 8662            None
 8663        };
 8664        let supports_jump = self
 8665            .edit_prediction_provider
 8666            .as_ref()
 8667            .map(|provider| provider.provider.supports_jump_to_edit())
 8668            .unwrap_or(true);
 8669
 8670        let is_move = supports_jump
 8671            && (move_invalidation_row_range.is_some() || self.edit_predictions_hidden_for_vim_mode);
 8672        let completion = if is_move {
 8673            if let Some(provider) = &self.edit_prediction_provider {
 8674                provider.provider.did_show(SuggestionDisplayType::Jump, cx);
 8675            }
 8676            invalidation_row_range =
 8677                move_invalidation_row_range.unwrap_or(edit_start_row..edit_end_row);
 8678            let target = first_edit_start;
 8679            EditPrediction::MoveWithin { target, snapshot }
 8680        } else {
 8681            let show_completions_in_buffer = !self.edit_prediction_visible_in_cursor_popover(true)
 8682                && !self.edit_predictions_hidden_for_vim_mode;
 8683
 8684            let display_mode = if all_edits_insertions_or_deletions(&edits, &multibuffer) {
 8685                if provider.show_tab_accept_marker() {
 8686                    EditDisplayMode::TabAccept
 8687                } else {
 8688                    EditDisplayMode::Inline
 8689                }
 8690            } else {
 8691                EditDisplayMode::DiffPopover
 8692            };
 8693
 8694            if show_completions_in_buffer {
 8695                if let Some(provider) = &self.edit_prediction_provider {
 8696                    let suggestion_display_type = match display_mode {
 8697                        EditDisplayMode::DiffPopover => SuggestionDisplayType::DiffPopover,
 8698                        EditDisplayMode::Inline | EditDisplayMode::TabAccept => {
 8699                            SuggestionDisplayType::GhostText
 8700                        }
 8701                    };
 8702                    provider.provider.did_show(suggestion_display_type, cx);
 8703                }
 8704                if edits
 8705                    .iter()
 8706                    .all(|(range, _)| range.to_offset(&multibuffer).is_empty())
 8707                {
 8708                    let mut inlays = Vec::new();
 8709                    for (range, new_text) in &edits {
 8710                        let inlay = Inlay::edit_prediction(
 8711                            post_inc(&mut self.next_inlay_id),
 8712                            range.start,
 8713                            new_text.as_ref(),
 8714                        );
 8715                        inlay_ids.push(inlay.id);
 8716                        inlays.push(inlay);
 8717                    }
 8718
 8719                    self.splice_inlays(&[], inlays, cx);
 8720                } else {
 8721                    let background_color = cx.theme().status().deleted_background;
 8722                    self.highlight_text(
 8723                        HighlightKey::EditPredictionHighlight,
 8724                        edits.iter().map(|(range, _)| range.clone()).collect(),
 8725                        HighlightStyle {
 8726                            background_color: Some(background_color),
 8727                            ..Default::default()
 8728                        },
 8729                        cx,
 8730                    );
 8731                }
 8732            }
 8733
 8734            invalidation_row_range = edit_start_row..edit_end_row;
 8735
 8736            EditPrediction::Edit {
 8737                edits,
 8738                cursor_position,
 8739                edit_preview,
 8740                display_mode,
 8741                snapshot,
 8742            }
 8743        };
 8744
 8745        let invalidation_range = multibuffer
 8746            .anchor_before(Point::new(invalidation_row_range.start, 0))
 8747            ..multibuffer.anchor_after(Point::new(
 8748                invalidation_row_range.end,
 8749                multibuffer.line_len(MultiBufferRow(invalidation_row_range.end)),
 8750            ));
 8751
 8752        self.stale_edit_prediction_in_menu = None;
 8753        self.active_edit_prediction = Some(EditPredictionState {
 8754            inlay_ids,
 8755            completion,
 8756            completion_id,
 8757            invalidation_range: Some(invalidation_range),
 8758        });
 8759
 8760        cx.notify();
 8761
 8762        Some(())
 8763    }
 8764
 8765    pub fn edit_prediction_provider(&self) -> Option<Arc<dyn EditPredictionDelegateHandle>> {
 8766        Some(self.edit_prediction_provider.as_ref()?.provider.clone())
 8767    }
 8768
 8769    /// Get all display points of breakpoints that will be rendered within editor
 8770    ///
 8771    /// This function is used to handle overlaps between breakpoints and Code action/runner symbol.
 8772    /// It's also used to set the color of line numbers with breakpoints to the breakpoint color.
 8773    /// TODO debugger: Use this function to color toggle symbols that house nested breakpoints
 8774    fn active_breakpoints(
 8775        &self,
 8776        range: Range<DisplayRow>,
 8777        window: &mut Window,
 8778        cx: &mut Context<Self>,
 8779    ) -> HashMap<DisplayRow, (Anchor, Breakpoint, Option<BreakpointSessionState>)> {
 8780        let mut breakpoint_display_points = HashMap::default();
 8781
 8782        let Some(breakpoint_store) = self.breakpoint_store.clone() else {
 8783            return breakpoint_display_points;
 8784        };
 8785
 8786        let snapshot = self.snapshot(window, cx);
 8787
 8788        let multi_buffer_snapshot = snapshot.buffer_snapshot();
 8789        let Some(project) = self.project() else {
 8790            return breakpoint_display_points;
 8791        };
 8792
 8793        let range = snapshot.display_point_to_point(DisplayPoint::new(range.start, 0), Bias::Left)
 8794            ..snapshot.display_point_to_point(DisplayPoint::new(range.end, 0), Bias::Right);
 8795
 8796        for (buffer_snapshot, range, excerpt_id) in
 8797            multi_buffer_snapshot.range_to_buffer_ranges(range.start..=range.end)
 8798        {
 8799            let Some(buffer) = project
 8800                .read(cx)
 8801                .buffer_for_id(buffer_snapshot.remote_id(), cx)
 8802            else {
 8803                continue;
 8804            };
 8805            let breakpoints = breakpoint_store.read(cx).breakpoints(
 8806                &buffer,
 8807                Some(
 8808                    buffer_snapshot.anchor_before(range.start)
 8809                        ..buffer_snapshot.anchor_after(range.end),
 8810                ),
 8811                buffer_snapshot,
 8812                cx,
 8813            );
 8814            for (breakpoint, state) in breakpoints {
 8815                let multi_buffer_anchor = Anchor::in_buffer(excerpt_id, breakpoint.position);
 8816                let position = multi_buffer_anchor
 8817                    .to_point(&multi_buffer_snapshot)
 8818                    .to_display_point(&snapshot);
 8819
 8820                breakpoint_display_points.insert(
 8821                    position.row(),
 8822                    (multi_buffer_anchor, breakpoint.bp.clone(), state),
 8823                );
 8824            }
 8825        }
 8826
 8827        breakpoint_display_points
 8828    }
 8829
 8830    fn breakpoint_context_menu(
 8831        &self,
 8832        anchor: Anchor,
 8833        window: &mut Window,
 8834        cx: &mut Context<Self>,
 8835    ) -> Entity<ui::ContextMenu> {
 8836        let weak_editor = cx.weak_entity();
 8837        let focus_handle = self.focus_handle(cx);
 8838
 8839        let row = self
 8840            .buffer
 8841            .read(cx)
 8842            .snapshot(cx)
 8843            .summary_for_anchor::<Point>(&anchor)
 8844            .row;
 8845
 8846        let breakpoint = self
 8847            .breakpoint_at_row(row, window, cx)
 8848            .map(|(anchor, bp)| (anchor, Arc::from(bp)));
 8849
 8850        let log_breakpoint_msg = if breakpoint.as_ref().is_some_and(|bp| bp.1.message.is_some()) {
 8851            "Edit Log Breakpoint"
 8852        } else {
 8853            "Set Log Breakpoint"
 8854        };
 8855
 8856        let condition_breakpoint_msg = if breakpoint
 8857            .as_ref()
 8858            .is_some_and(|bp| bp.1.condition.is_some())
 8859        {
 8860            "Edit Condition Breakpoint"
 8861        } else {
 8862            "Set Condition Breakpoint"
 8863        };
 8864
 8865        let hit_condition_breakpoint_msg = if breakpoint
 8866            .as_ref()
 8867            .is_some_and(|bp| bp.1.hit_condition.is_some())
 8868        {
 8869            "Edit Hit Condition Breakpoint"
 8870        } else {
 8871            "Set Hit Condition Breakpoint"
 8872        };
 8873
 8874        let set_breakpoint_msg = if breakpoint.as_ref().is_some() {
 8875            "Unset Breakpoint"
 8876        } else {
 8877            "Set Breakpoint"
 8878        };
 8879
 8880        let run_to_cursor = window.is_action_available(&RunToCursor, cx);
 8881
 8882        let toggle_state_msg = breakpoint.as_ref().map_or(None, |bp| match bp.1.state {
 8883            BreakpointState::Enabled => Some("Disable"),
 8884            BreakpointState::Disabled => Some("Enable"),
 8885        });
 8886
 8887        let (anchor, breakpoint) =
 8888            breakpoint.unwrap_or_else(|| (anchor, Arc::new(Breakpoint::new_standard())));
 8889
 8890        ui::ContextMenu::build(window, cx, |menu, _, _cx| {
 8891            menu.on_blur_subscription(Subscription::new(|| {}))
 8892                .context(focus_handle)
 8893                .when(run_to_cursor, |this| {
 8894                    let weak_editor = weak_editor.clone();
 8895                    this.entry("Run to Cursor", None, move |window, cx| {
 8896                        weak_editor
 8897                            .update(cx, |editor, cx| {
 8898                                editor.change_selections(
 8899                                    SelectionEffects::no_scroll(),
 8900                                    window,
 8901                                    cx,
 8902                                    |s| s.select_ranges([Point::new(row, 0)..Point::new(row, 0)]),
 8903                                );
 8904                            })
 8905                            .ok();
 8906
 8907                        window.dispatch_action(Box::new(RunToCursor), cx);
 8908                    })
 8909                    .separator()
 8910                })
 8911                .when_some(toggle_state_msg, |this, msg| {
 8912                    this.entry(msg, None, {
 8913                        let weak_editor = weak_editor.clone();
 8914                        let breakpoint = breakpoint.clone();
 8915                        move |_window, cx| {
 8916                            weak_editor
 8917                                .update(cx, |this, cx| {
 8918                                    this.edit_breakpoint_at_anchor(
 8919                                        anchor,
 8920                                        breakpoint.as_ref().clone(),
 8921                                        BreakpointEditAction::InvertState,
 8922                                        cx,
 8923                                    );
 8924                                })
 8925                                .log_err();
 8926                        }
 8927                    })
 8928                })
 8929                .entry(set_breakpoint_msg, None, {
 8930                    let weak_editor = weak_editor.clone();
 8931                    let breakpoint = breakpoint.clone();
 8932                    move |_window, cx| {
 8933                        weak_editor
 8934                            .update(cx, |this, cx| {
 8935                                this.edit_breakpoint_at_anchor(
 8936                                    anchor,
 8937                                    breakpoint.as_ref().clone(),
 8938                                    BreakpointEditAction::Toggle,
 8939                                    cx,
 8940                                );
 8941                            })
 8942                            .log_err();
 8943                    }
 8944                })
 8945                .entry(log_breakpoint_msg, None, {
 8946                    let breakpoint = breakpoint.clone();
 8947                    let weak_editor = weak_editor.clone();
 8948                    move |window, cx| {
 8949                        weak_editor
 8950                            .update(cx, |this, cx| {
 8951                                this.add_edit_breakpoint_block(
 8952                                    anchor,
 8953                                    breakpoint.as_ref(),
 8954                                    BreakpointPromptEditAction::Log,
 8955                                    window,
 8956                                    cx,
 8957                                );
 8958                            })
 8959                            .log_err();
 8960                    }
 8961                })
 8962                .entry(condition_breakpoint_msg, None, {
 8963                    let breakpoint = breakpoint.clone();
 8964                    let weak_editor = weak_editor.clone();
 8965                    move |window, cx| {
 8966                        weak_editor
 8967                            .update(cx, |this, cx| {
 8968                                this.add_edit_breakpoint_block(
 8969                                    anchor,
 8970                                    breakpoint.as_ref(),
 8971                                    BreakpointPromptEditAction::Condition,
 8972                                    window,
 8973                                    cx,
 8974                                );
 8975                            })
 8976                            .log_err();
 8977                    }
 8978                })
 8979                .entry(hit_condition_breakpoint_msg, None, move |window, cx| {
 8980                    weak_editor
 8981                        .update(cx, |this, cx| {
 8982                            this.add_edit_breakpoint_block(
 8983                                anchor,
 8984                                breakpoint.as_ref(),
 8985                                BreakpointPromptEditAction::HitCondition,
 8986                                window,
 8987                                cx,
 8988                            );
 8989                        })
 8990                        .log_err();
 8991                })
 8992        })
 8993    }
 8994
 8995    fn render_breakpoint(
 8996        &self,
 8997        position: Anchor,
 8998        row: DisplayRow,
 8999        breakpoint: &Breakpoint,
 9000        state: Option<BreakpointSessionState>,
 9001        cx: &mut Context<Self>,
 9002    ) -> IconButton {
 9003        let is_rejected = state.is_some_and(|s| !s.verified);
 9004        // Is it a breakpoint that shows up when hovering over gutter?
 9005        let (is_phantom, collides_with_existing) = self.gutter_breakpoint_indicator.0.map_or(
 9006            (false, false),
 9007            |PhantomBreakpointIndicator {
 9008                 is_active,
 9009                 display_row,
 9010                 collides_with_existing_breakpoint,
 9011             }| {
 9012                (
 9013                    is_active && display_row == row,
 9014                    collides_with_existing_breakpoint,
 9015                )
 9016            },
 9017        );
 9018
 9019        let (color, icon) = {
 9020            let icon = match (&breakpoint.message.is_some(), breakpoint.is_disabled()) {
 9021                (false, false) => ui::IconName::DebugBreakpoint,
 9022                (true, false) => ui::IconName::DebugLogBreakpoint,
 9023                (false, true) => ui::IconName::DebugDisabledBreakpoint,
 9024                (true, true) => ui::IconName::DebugDisabledLogBreakpoint,
 9025            };
 9026
 9027            let theme_colors = cx.theme().colors();
 9028
 9029            let color = if is_phantom {
 9030                if collides_with_existing {
 9031                    Color::Custom(
 9032                        theme_colors
 9033                            .debugger_accent
 9034                            .blend(theme_colors.text.opacity(0.6)),
 9035                    )
 9036                } else {
 9037                    Color::Hint
 9038                }
 9039            } else if is_rejected {
 9040                Color::Disabled
 9041            } else {
 9042                Color::Debugger
 9043            };
 9044
 9045            (color, icon)
 9046        };
 9047
 9048        let breakpoint = Arc::from(breakpoint.clone());
 9049
 9050        let alt_as_text = gpui::Keystroke {
 9051            modifiers: Modifiers::secondary_key(),
 9052            ..Default::default()
 9053        };
 9054        let primary_action_text = if breakpoint.is_disabled() {
 9055            "Enable breakpoint"
 9056        } else if is_phantom && !collides_with_existing {
 9057            "Set breakpoint"
 9058        } else {
 9059            "Unset breakpoint"
 9060        };
 9061        let focus_handle = self.focus_handle.clone();
 9062
 9063        let meta = if is_rejected {
 9064            SharedString::from("No executable code is associated with this line.")
 9065        } else if collides_with_existing && !breakpoint.is_disabled() {
 9066            SharedString::from(format!(
 9067                "{alt_as_text}-click to disable,\nright-click for more options."
 9068            ))
 9069        } else {
 9070            SharedString::from("Right-click for more options.")
 9071        };
 9072        IconButton::new(("breakpoint_indicator", row.0 as usize), icon)
 9073            .icon_size(IconSize::XSmall)
 9074            .size(ui::ButtonSize::None)
 9075            .when(is_rejected, |this| {
 9076                this.indicator(Indicator::icon(Icon::new(IconName::Warning)).color(Color::Warning))
 9077            })
 9078            .icon_color(color)
 9079            .style(ButtonStyle::Transparent)
 9080            .on_click(cx.listener({
 9081                move |editor, event: &ClickEvent, window, cx| {
 9082                    let edit_action = if event.modifiers().platform || breakpoint.is_disabled() {
 9083                        BreakpointEditAction::InvertState
 9084                    } else {
 9085                        BreakpointEditAction::Toggle
 9086                    };
 9087
 9088                    window.focus(&editor.focus_handle(cx), cx);
 9089                    editor.update_breakpoint_collision_on_toggle(row, &edit_action);
 9090                    editor.edit_breakpoint_at_anchor(
 9091                        position,
 9092                        breakpoint.as_ref().clone(),
 9093                        edit_action,
 9094                        cx,
 9095                    );
 9096                }
 9097            }))
 9098            .on_right_click(cx.listener(move |editor, event: &ClickEvent, window, cx| {
 9099                editor.set_breakpoint_context_menu(
 9100                    row,
 9101                    Some(position),
 9102                    event.position(),
 9103                    window,
 9104                    cx,
 9105                );
 9106            }))
 9107            .tooltip(move |_window, cx| {
 9108                Tooltip::with_meta_in(
 9109                    primary_action_text,
 9110                    Some(&ToggleBreakpoint),
 9111                    meta.clone(),
 9112                    &focus_handle,
 9113                    cx,
 9114                )
 9115            })
 9116    }
 9117
 9118    fn build_tasks_context(
 9119        project: &Entity<Project>,
 9120        buffer: &Entity<Buffer>,
 9121        buffer_row: u32,
 9122        tasks: &Arc<RunnableTasks>,
 9123        cx: &mut Context<Self>,
 9124    ) -> Task<Option<task::TaskContext>> {
 9125        let position = Point::new(buffer_row, tasks.column);
 9126        let range_start = buffer.read(cx).anchor_at(position, Bias::Right);
 9127        let location = Location {
 9128            buffer: buffer.clone(),
 9129            range: range_start..range_start,
 9130        };
 9131        // Fill in the environmental variables from the tree-sitter captures
 9132        let mut captured_task_variables = TaskVariables::default();
 9133        for (capture_name, value) in tasks.extra_variables.clone() {
 9134            captured_task_variables.insert(
 9135                task::VariableName::Custom(capture_name.into()),
 9136                value.clone(),
 9137            );
 9138        }
 9139        project.update(cx, |project, cx| {
 9140            project.task_store().update(cx, |task_store, cx| {
 9141                task_store.task_context_for_location(captured_task_variables, location, cx)
 9142            })
 9143        })
 9144    }
 9145
 9146    pub fn context_menu_visible(&self) -> bool {
 9147        !self.edit_prediction_preview_is_active()
 9148            && self
 9149                .context_menu
 9150                .borrow()
 9151                .as_ref()
 9152                .is_some_and(|menu| menu.visible())
 9153    }
 9154
 9155    pub fn context_menu_origin(&self) -> Option<ContextMenuOrigin> {
 9156        self.context_menu
 9157            .borrow()
 9158            .as_ref()
 9159            .map(|menu| menu.origin())
 9160    }
 9161
 9162    pub fn set_context_menu_options(&mut self, options: ContextMenuOptions) {
 9163        self.context_menu_options = Some(options);
 9164    }
 9165
 9166    const EDIT_PREDICTION_POPOVER_PADDING_X: Pixels = px(24.);
 9167    const EDIT_PREDICTION_POPOVER_PADDING_Y: Pixels = px(2.);
 9168
 9169    fn render_edit_prediction_popover(
 9170        &mut self,
 9171        text_bounds: &Bounds<Pixels>,
 9172        content_origin: gpui::Point<Pixels>,
 9173        right_margin: Pixels,
 9174        editor_snapshot: &EditorSnapshot,
 9175        visible_row_range: Range<DisplayRow>,
 9176        scroll_top: ScrollOffset,
 9177        scroll_bottom: ScrollOffset,
 9178        line_layouts: &[LineWithInvisibles],
 9179        line_height: Pixels,
 9180        scroll_position: gpui::Point<ScrollOffset>,
 9181        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9182        newest_selection_head: Option<DisplayPoint>,
 9183        editor_width: Pixels,
 9184        style: &EditorStyle,
 9185        window: &mut Window,
 9186        cx: &mut App,
 9187    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9188        if self.mode().is_minimap() {
 9189            return None;
 9190        }
 9191        let active_edit_prediction = self.active_edit_prediction.as_ref()?;
 9192
 9193        if self.edit_prediction_visible_in_cursor_popover(true) {
 9194            return None;
 9195        }
 9196
 9197        match &active_edit_prediction.completion {
 9198            EditPrediction::MoveWithin { target, .. } => {
 9199                let target_display_point = target.to_display_point(editor_snapshot);
 9200
 9201                if self.edit_prediction_requires_modifier() {
 9202                    if !self.edit_prediction_preview_is_active() {
 9203                        return None;
 9204                    }
 9205
 9206                    self.render_edit_prediction_modifier_jump_popover(
 9207                        text_bounds,
 9208                        content_origin,
 9209                        visible_row_range,
 9210                        line_layouts,
 9211                        line_height,
 9212                        scroll_pixel_position,
 9213                        newest_selection_head,
 9214                        target_display_point,
 9215                        window,
 9216                        cx,
 9217                    )
 9218                } else {
 9219                    self.render_edit_prediction_eager_jump_popover(
 9220                        text_bounds,
 9221                        content_origin,
 9222                        editor_snapshot,
 9223                        visible_row_range,
 9224                        scroll_top,
 9225                        scroll_bottom,
 9226                        line_height,
 9227                        scroll_pixel_position,
 9228                        target_display_point,
 9229                        editor_width,
 9230                        window,
 9231                        cx,
 9232                    )
 9233                }
 9234            }
 9235            EditPrediction::Edit {
 9236                display_mode: EditDisplayMode::Inline,
 9237                ..
 9238            } => None,
 9239            EditPrediction::Edit {
 9240                display_mode: EditDisplayMode::TabAccept,
 9241                edits,
 9242                ..
 9243            } => {
 9244                let range = &edits.first()?.0;
 9245                let target_display_point = range.end.to_display_point(editor_snapshot);
 9246
 9247                self.render_edit_prediction_end_of_line_popover(
 9248                    "Accept",
 9249                    editor_snapshot,
 9250                    visible_row_range,
 9251                    target_display_point,
 9252                    line_height,
 9253                    scroll_pixel_position,
 9254                    content_origin,
 9255                    editor_width,
 9256                    window,
 9257                    cx,
 9258                )
 9259            }
 9260            EditPrediction::Edit {
 9261                edits,
 9262                edit_preview,
 9263                display_mode: EditDisplayMode::DiffPopover,
 9264                snapshot,
 9265                ..
 9266            } => self.render_edit_prediction_diff_popover(
 9267                text_bounds,
 9268                content_origin,
 9269                right_margin,
 9270                editor_snapshot,
 9271                visible_row_range,
 9272                line_layouts,
 9273                line_height,
 9274                scroll_position,
 9275                scroll_pixel_position,
 9276                newest_selection_head,
 9277                editor_width,
 9278                style,
 9279                edits,
 9280                edit_preview,
 9281                snapshot,
 9282                window,
 9283                cx,
 9284            ),
 9285            EditPrediction::MoveOutside { snapshot, .. } => {
 9286                let mut element = self
 9287                    .render_edit_prediction_jump_outside_popover(snapshot, window, cx)
 9288                    .into_any();
 9289
 9290                let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9291                let origin_x = text_bounds.size.width - size.width - px(30.);
 9292                let origin = text_bounds.origin + gpui::Point::new(origin_x, px(16.));
 9293                element.prepaint_at(origin, window, cx);
 9294
 9295                Some((element, origin))
 9296            }
 9297        }
 9298    }
 9299
 9300    fn render_edit_prediction_modifier_jump_popover(
 9301        &mut self,
 9302        text_bounds: &Bounds<Pixels>,
 9303        content_origin: gpui::Point<Pixels>,
 9304        visible_row_range: Range<DisplayRow>,
 9305        line_layouts: &[LineWithInvisibles],
 9306        line_height: Pixels,
 9307        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9308        newest_selection_head: Option<DisplayPoint>,
 9309        target_display_point: DisplayPoint,
 9310        window: &mut Window,
 9311        cx: &mut App,
 9312    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9313        let scrolled_content_origin =
 9314            content_origin - gpui::Point::new(scroll_pixel_position.x.into(), Pixels::ZERO);
 9315
 9316        const SCROLL_PADDING_Y: Pixels = px(12.);
 9317
 9318        if target_display_point.row() < visible_row_range.start {
 9319            return self.render_edit_prediction_scroll_popover(
 9320                &|_| SCROLL_PADDING_Y,
 9321                IconName::ArrowUp,
 9322                visible_row_range,
 9323                line_layouts,
 9324                newest_selection_head,
 9325                scrolled_content_origin,
 9326                window,
 9327                cx,
 9328            );
 9329        } else if target_display_point.row() >= visible_row_range.end {
 9330            return self.render_edit_prediction_scroll_popover(
 9331                &|size| text_bounds.size.height - size.height - SCROLL_PADDING_Y,
 9332                IconName::ArrowDown,
 9333                visible_row_range,
 9334                line_layouts,
 9335                newest_selection_head,
 9336                scrolled_content_origin,
 9337                window,
 9338                cx,
 9339            );
 9340        }
 9341
 9342        const POLE_WIDTH: Pixels = px(2.);
 9343
 9344        let line_layout =
 9345            line_layouts.get(target_display_point.row().minus(visible_row_range.start) as usize)?;
 9346        let target_column = target_display_point.column() as usize;
 9347
 9348        let target_x = line_layout.x_for_index(target_column);
 9349        let target_y = (target_display_point.row().as_f64() * f64::from(line_height))
 9350            - scroll_pixel_position.y;
 9351
 9352        let flag_on_right = target_x < text_bounds.size.width / 2.;
 9353
 9354        let mut border_color = Self::edit_prediction_callout_popover_border_color(cx);
 9355        border_color.l += 0.001;
 9356
 9357        let mut element = v_flex()
 9358            .items_end()
 9359            .when(flag_on_right, |el| el.items_start())
 9360            .child(if flag_on_right {
 9361                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9362                    .rounded_bl(px(0.))
 9363                    .rounded_tl(px(0.))
 9364                    .border_l_2()
 9365                    .border_color(border_color)
 9366            } else {
 9367                self.render_edit_prediction_line_popover("Jump", None, window, cx)
 9368                    .rounded_br(px(0.))
 9369                    .rounded_tr(px(0.))
 9370                    .border_r_2()
 9371                    .border_color(border_color)
 9372            })
 9373            .child(div().w(POLE_WIDTH).bg(border_color).h(line_height))
 9374            .into_any();
 9375
 9376        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9377
 9378        let mut origin = scrolled_content_origin + point(target_x, target_y.into())
 9379            - point(
 9380                if flag_on_right {
 9381                    POLE_WIDTH
 9382                } else {
 9383                    size.width - POLE_WIDTH
 9384                },
 9385                size.height - line_height,
 9386            );
 9387
 9388        origin.x = origin.x.max(content_origin.x);
 9389
 9390        element.prepaint_at(origin, window, cx);
 9391
 9392        Some((element, origin))
 9393    }
 9394
 9395    fn render_edit_prediction_scroll_popover(
 9396        &mut self,
 9397        to_y: &dyn Fn(Size<Pixels>) -> Pixels,
 9398        scroll_icon: IconName,
 9399        visible_row_range: Range<DisplayRow>,
 9400        line_layouts: &[LineWithInvisibles],
 9401        newest_selection_head: Option<DisplayPoint>,
 9402        scrolled_content_origin: gpui::Point<Pixels>,
 9403        window: &mut Window,
 9404        cx: &mut App,
 9405    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9406        let mut element = self
 9407            .render_edit_prediction_line_popover("Scroll", Some(scroll_icon), window, cx)
 9408            .into_any();
 9409
 9410        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9411
 9412        let cursor = newest_selection_head?;
 9413        let cursor_row_layout =
 9414            line_layouts.get(cursor.row().minus(visible_row_range.start) as usize)?;
 9415        let cursor_column = cursor.column() as usize;
 9416
 9417        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 9418
 9419        let origin = scrolled_content_origin + point(cursor_character_x, to_y(size));
 9420
 9421        element.prepaint_at(origin, window, cx);
 9422        Some((element, origin))
 9423    }
 9424
 9425    fn render_edit_prediction_eager_jump_popover(
 9426        &mut self,
 9427        text_bounds: &Bounds<Pixels>,
 9428        content_origin: gpui::Point<Pixels>,
 9429        editor_snapshot: &EditorSnapshot,
 9430        visible_row_range: Range<DisplayRow>,
 9431        scroll_top: ScrollOffset,
 9432        scroll_bottom: ScrollOffset,
 9433        line_height: Pixels,
 9434        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9435        target_display_point: DisplayPoint,
 9436        editor_width: Pixels,
 9437        window: &mut Window,
 9438        cx: &mut App,
 9439    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9440        if target_display_point.row().as_f64() < scroll_top {
 9441            let mut element = self
 9442                .render_edit_prediction_line_popover(
 9443                    "Jump to Edit",
 9444                    Some(IconName::ArrowUp),
 9445                    window,
 9446                    cx,
 9447                )
 9448                .into_any();
 9449
 9450            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9451            let offset = point(
 9452                (text_bounds.size.width - size.width) / 2.,
 9453                Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9454            );
 9455
 9456            let origin = text_bounds.origin + offset;
 9457            element.prepaint_at(origin, window, cx);
 9458            Some((element, origin))
 9459        } else if (target_display_point.row().as_f64() + 1.) > scroll_bottom {
 9460            let mut element = self
 9461                .render_edit_prediction_line_popover(
 9462                    "Jump to Edit",
 9463                    Some(IconName::ArrowDown),
 9464                    window,
 9465                    cx,
 9466                )
 9467                .into_any();
 9468
 9469            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9470            let offset = point(
 9471                (text_bounds.size.width - size.width) / 2.,
 9472                text_bounds.size.height - size.height - Self::EDIT_PREDICTION_POPOVER_PADDING_Y,
 9473            );
 9474
 9475            let origin = text_bounds.origin + offset;
 9476            element.prepaint_at(origin, window, cx);
 9477            Some((element, origin))
 9478        } else {
 9479            self.render_edit_prediction_end_of_line_popover(
 9480                "Jump to Edit",
 9481                editor_snapshot,
 9482                visible_row_range,
 9483                target_display_point,
 9484                line_height,
 9485                scroll_pixel_position,
 9486                content_origin,
 9487                editor_width,
 9488                window,
 9489                cx,
 9490            )
 9491        }
 9492    }
 9493
 9494    fn render_edit_prediction_end_of_line_popover(
 9495        self: &mut Editor,
 9496        label: &'static str,
 9497        editor_snapshot: &EditorSnapshot,
 9498        visible_row_range: Range<DisplayRow>,
 9499        target_display_point: DisplayPoint,
 9500        line_height: Pixels,
 9501        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9502        content_origin: gpui::Point<Pixels>,
 9503        editor_width: Pixels,
 9504        window: &mut Window,
 9505        cx: &mut App,
 9506    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9507        let target_line_end = DisplayPoint::new(
 9508            target_display_point.row(),
 9509            editor_snapshot.line_len(target_display_point.row()),
 9510        );
 9511
 9512        let mut element = self
 9513            .render_edit_prediction_line_popover(label, None, window, cx)
 9514            .into_any();
 9515
 9516        let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9517
 9518        let line_origin =
 9519            self.display_to_pixel_point(target_line_end, editor_snapshot, window, cx)?;
 9520
 9521        let start_point = content_origin - point(scroll_pixel_position.x.into(), Pixels::ZERO);
 9522        let mut origin = start_point
 9523            + line_origin
 9524            + point(Self::EDIT_PREDICTION_POPOVER_PADDING_X, Pixels::ZERO);
 9525        origin.x = origin.x.max(content_origin.x);
 9526
 9527        let max_x = content_origin.x + editor_width - size.width;
 9528
 9529        if origin.x > max_x {
 9530            let offset = line_height + Self::EDIT_PREDICTION_POPOVER_PADDING_Y;
 9531
 9532            let icon = if visible_row_range.contains(&(target_display_point.row() + 2)) {
 9533                origin.y += offset;
 9534                IconName::ArrowUp
 9535            } else {
 9536                origin.y -= offset;
 9537                IconName::ArrowDown
 9538            };
 9539
 9540            element = self
 9541                .render_edit_prediction_line_popover(label, Some(icon), window, cx)
 9542                .into_any();
 9543
 9544            let size = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9545
 9546            origin.x = content_origin.x + editor_width - size.width - px(2.);
 9547        }
 9548
 9549        element.prepaint_at(origin, window, cx);
 9550        Some((element, origin))
 9551    }
 9552
 9553    fn render_edit_prediction_diff_popover(
 9554        self: &Editor,
 9555        text_bounds: &Bounds<Pixels>,
 9556        content_origin: gpui::Point<Pixels>,
 9557        right_margin: Pixels,
 9558        editor_snapshot: &EditorSnapshot,
 9559        visible_row_range: Range<DisplayRow>,
 9560        line_layouts: &[LineWithInvisibles],
 9561        line_height: Pixels,
 9562        scroll_position: gpui::Point<ScrollOffset>,
 9563        scroll_pixel_position: gpui::Point<ScrollPixelOffset>,
 9564        newest_selection_head: Option<DisplayPoint>,
 9565        editor_width: Pixels,
 9566        style: &EditorStyle,
 9567        edits: &Vec<(Range<Anchor>, Arc<str>)>,
 9568        edit_preview: &Option<language::EditPreview>,
 9569        snapshot: &language::BufferSnapshot,
 9570        window: &mut Window,
 9571        cx: &mut App,
 9572    ) -> Option<(AnyElement, gpui::Point<Pixels>)> {
 9573        let edit_start = edits
 9574            .first()
 9575            .unwrap()
 9576            .0
 9577            .start
 9578            .to_display_point(editor_snapshot);
 9579        let edit_end = edits
 9580            .last()
 9581            .unwrap()
 9582            .0
 9583            .end
 9584            .to_display_point(editor_snapshot);
 9585
 9586        let is_visible = visible_row_range.contains(&edit_start.row())
 9587            || visible_row_range.contains(&edit_end.row());
 9588        if !is_visible {
 9589            return None;
 9590        }
 9591
 9592        let highlighted_edits = if let Some(edit_preview) = edit_preview.as_ref() {
 9593            crate::edit_prediction_edit_text(snapshot, edits, edit_preview, false, cx)
 9594        } else {
 9595            // Fallback for providers without edit_preview
 9596            crate::edit_prediction_fallback_text(edits, cx)
 9597        };
 9598
 9599        let styled_text = highlighted_edits.to_styled_text(&style.text);
 9600        let line_count = highlighted_edits.text.lines().count();
 9601
 9602        const BORDER_WIDTH: Pixels = px(1.);
 9603
 9604        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9605        let has_keybind = keybind.is_some();
 9606
 9607        let mut element = h_flex()
 9608            .items_start()
 9609            .child(
 9610                h_flex()
 9611                    .bg(cx.theme().colors().editor_background)
 9612                    .border(BORDER_WIDTH)
 9613                    .shadow_xs()
 9614                    .border_color(cx.theme().colors().border)
 9615                    .rounded_l_lg()
 9616                    .when(line_count > 1, |el| el.rounded_br_lg())
 9617                    .pr_1()
 9618                    .child(styled_text),
 9619            )
 9620            .child(
 9621                h_flex()
 9622                    .h(line_height + BORDER_WIDTH * 2.)
 9623                    .px_1p5()
 9624                    .gap_1()
 9625                    // Workaround: For some reason, there's a gap if we don't do this
 9626                    .ml(-BORDER_WIDTH)
 9627                    .shadow(vec![gpui::BoxShadow {
 9628                        color: gpui::black().opacity(0.05),
 9629                        offset: point(px(1.), px(1.)),
 9630                        blur_radius: px(2.),
 9631                        spread_radius: px(0.),
 9632                    }])
 9633                    .bg(Editor::edit_prediction_line_popover_bg_color(cx))
 9634                    .border(BORDER_WIDTH)
 9635                    .border_color(cx.theme().colors().border)
 9636                    .rounded_r_lg()
 9637                    .id("edit_prediction_diff_popover_keybind")
 9638                    .when(!has_keybind, |el| {
 9639                        let status_colors = cx.theme().status();
 9640
 9641                        el.bg(status_colors.error_background)
 9642                            .border_color(status_colors.error.opacity(0.6))
 9643                            .child(Icon::new(IconName::Info).color(Color::Error))
 9644                            .cursor_default()
 9645                            .hoverable_tooltip(move |_window, cx| {
 9646                                cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9647                            })
 9648                    })
 9649                    .children(keybind),
 9650            )
 9651            .into_any();
 9652
 9653        let longest_row =
 9654            editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1);
 9655        let longest_line_width = if visible_row_range.contains(&longest_row) {
 9656            line_layouts[(longest_row.0 - visible_row_range.start.0) as usize].width
 9657        } else {
 9658            layout_line(
 9659                longest_row,
 9660                editor_snapshot,
 9661                style,
 9662                editor_width,
 9663                |_| false,
 9664                window,
 9665                cx,
 9666            )
 9667            .width
 9668        };
 9669
 9670        let viewport_bounds =
 9671            Bounds::new(Default::default(), window.viewport_size()).extend(Edges {
 9672                right: -right_margin,
 9673                ..Default::default()
 9674            });
 9675
 9676        let x_after_longest = Pixels::from(
 9677            ScrollPixelOffset::from(
 9678                text_bounds.origin.x + longest_line_width + Self::EDIT_PREDICTION_POPOVER_PADDING_X,
 9679            ) - scroll_pixel_position.x,
 9680        );
 9681
 9682        let element_bounds = element.layout_as_root(AvailableSpace::min_size(), window, cx);
 9683
 9684        // Fully visible if it can be displayed within the window (allow overlapping other
 9685        // panes). However, this is only allowed if the popover starts within text_bounds.
 9686        let can_position_to_the_right = x_after_longest < text_bounds.right()
 9687            && x_after_longest + element_bounds.width < viewport_bounds.right();
 9688
 9689        let mut origin = if can_position_to_the_right {
 9690            point(
 9691                x_after_longest,
 9692                text_bounds.origin.y
 9693                    + Pixels::from(
 9694                        edit_start.row().as_f64() * ScrollPixelOffset::from(line_height)
 9695                            - scroll_pixel_position.y,
 9696                    ),
 9697            )
 9698        } else {
 9699            let cursor_row = newest_selection_head.map(|head| head.row());
 9700            let above_edit = edit_start
 9701                .row()
 9702                .0
 9703                .checked_sub(line_count as u32)
 9704                .map(DisplayRow);
 9705            let below_edit = Some(edit_end.row() + 1);
 9706            let above_cursor =
 9707                cursor_row.and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow));
 9708            let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1);
 9709
 9710            // Place the edit popover adjacent to the edit if there is a location
 9711            // available that is onscreen and does not obscure the cursor. Otherwise,
 9712            // place it adjacent to the cursor.
 9713            let row_target = [above_edit, below_edit, above_cursor, below_cursor]
 9714                .into_iter()
 9715                .flatten()
 9716                .find(|&start_row| {
 9717                    let end_row = start_row + line_count as u32;
 9718                    visible_row_range.contains(&start_row)
 9719                        && visible_row_range.contains(&end_row)
 9720                        && cursor_row
 9721                            .is_none_or(|cursor_row| !((start_row..end_row).contains(&cursor_row)))
 9722                })?;
 9723
 9724            content_origin
 9725                + point(
 9726                    Pixels::from(-scroll_pixel_position.x),
 9727                    Pixels::from(
 9728                        (row_target.as_f64() - scroll_position.y) * f64::from(line_height),
 9729                    ),
 9730                )
 9731        };
 9732
 9733        origin.x -= BORDER_WIDTH;
 9734
 9735        window.with_content_mask(
 9736            Some(gpui::ContentMask {
 9737                bounds: *text_bounds,
 9738            }),
 9739            |window| {
 9740                window.defer_draw(element, origin, 1, Some(window.content_mask()));
 9741            },
 9742        );
 9743
 9744        // Do not return an element, since it will already be drawn due to defer_draw.
 9745        None
 9746    }
 9747
 9748    fn edit_prediction_cursor_popover_height(&self) -> Pixels {
 9749        px(30.)
 9750    }
 9751
 9752    fn current_user_player_color(&self, cx: &mut App) -> PlayerColor {
 9753        if self.read_only(cx) {
 9754            cx.theme().players().read_only()
 9755        } else {
 9756            self.style.as_ref().unwrap().local_player
 9757        }
 9758    }
 9759
 9760    fn render_edit_prediction_accept_keybind(
 9761        &self,
 9762        window: &mut Window,
 9763        cx: &mut App,
 9764    ) -> Option<AnyElement> {
 9765        let accept_binding =
 9766            self.accept_edit_prediction_keybind(EditPredictionGranularity::Full, window, cx);
 9767        let accept_keystroke = accept_binding.keystroke()?;
 9768
 9769        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
 9770
 9771        let modifiers_color = if *accept_keystroke.modifiers() == window.modifiers() {
 9772            Color::Accent
 9773        } else {
 9774            Color::Muted
 9775        };
 9776
 9777        h_flex()
 9778            .px_0p5()
 9779            .when(is_platform_style_mac, |parent| parent.gap_0p5())
 9780            .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
 9781            .text_size(TextSize::XSmall.rems(cx))
 9782            .child(h_flex().children(ui::render_modifiers(
 9783                accept_keystroke.modifiers(),
 9784                PlatformStyle::platform(),
 9785                Some(modifiers_color),
 9786                Some(IconSize::XSmall.rems().into()),
 9787                true,
 9788            )))
 9789            .when(is_platform_style_mac, |parent| {
 9790                parent.child(accept_keystroke.key().to_string())
 9791            })
 9792            .when(!is_platform_style_mac, |parent| {
 9793                parent.child(
 9794                    Key::new(
 9795                        util::capitalize(accept_keystroke.key()),
 9796                        Some(Color::Default),
 9797                    )
 9798                    .size(Some(IconSize::XSmall.rems().into())),
 9799                )
 9800            })
 9801            .into_any()
 9802            .into()
 9803    }
 9804
 9805    fn render_edit_prediction_line_popover(
 9806        &self,
 9807        label: impl Into<SharedString>,
 9808        icon: Option<IconName>,
 9809        window: &mut Window,
 9810        cx: &mut App,
 9811    ) -> Stateful<Div> {
 9812        let padding_right = if icon.is_some() { px(4.) } else { px(8.) };
 9813
 9814        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9815        let has_keybind = keybind.is_some();
 9816        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
 9817
 9818        h_flex()
 9819            .id("ep-line-popover")
 9820            .py_0p5()
 9821            .pl_1()
 9822            .pr(padding_right)
 9823            .gap_1()
 9824            .rounded_md()
 9825            .border_1()
 9826            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9827            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9828            .shadow_xs()
 9829            .when(!has_keybind, |el| {
 9830                let status_colors = cx.theme().status();
 9831
 9832                el.bg(status_colors.error_background)
 9833                    .border_color(status_colors.error.opacity(0.6))
 9834                    .pl_2()
 9835                    .child(Icon::new(icons.error).color(Color::Error))
 9836                    .cursor_default()
 9837                    .hoverable_tooltip(move |_window, cx| {
 9838                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9839                    })
 9840            })
 9841            .children(keybind)
 9842            .child(
 9843                Label::new(label)
 9844                    .size(LabelSize::Small)
 9845                    .when(!has_keybind, |el| {
 9846                        el.color(cx.theme().status().error.into()).strikethrough()
 9847                    }),
 9848            )
 9849            .when(!has_keybind, |el| {
 9850                el.child(
 9851                    h_flex().ml_1().child(
 9852                        Icon::new(IconName::Info)
 9853                            .size(IconSize::Small)
 9854                            .color(cx.theme().status().error.into()),
 9855                    ),
 9856                )
 9857            })
 9858            .when_some(icon, |element, icon| {
 9859                element.child(
 9860                    div()
 9861                        .mt(px(1.5))
 9862                        .child(Icon::new(icon).size(IconSize::Small)),
 9863                )
 9864            })
 9865    }
 9866
 9867    fn render_edit_prediction_jump_outside_popover(
 9868        &self,
 9869        snapshot: &BufferSnapshot,
 9870        window: &mut Window,
 9871        cx: &mut App,
 9872    ) -> Stateful<Div> {
 9873        let keybind = self.render_edit_prediction_accept_keybind(window, cx);
 9874        let has_keybind = keybind.is_some();
 9875        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
 9876
 9877        let file_name = snapshot
 9878            .file()
 9879            .map(|file| SharedString::new(file.file_name(cx)))
 9880            .unwrap_or(SharedString::new_static("untitled"));
 9881
 9882        h_flex()
 9883            .id("ep-jump-outside-popover")
 9884            .py_1()
 9885            .px_2()
 9886            .gap_1()
 9887            .rounded_md()
 9888            .border_1()
 9889            .bg(Self::edit_prediction_line_popover_bg_color(cx))
 9890            .border_color(Self::edit_prediction_callout_popover_border_color(cx))
 9891            .shadow_xs()
 9892            .when(!has_keybind, |el| {
 9893                let status_colors = cx.theme().status();
 9894
 9895                el.bg(status_colors.error_background)
 9896                    .border_color(status_colors.error.opacity(0.6))
 9897                    .pl_2()
 9898                    .child(Icon::new(icons.error).color(Color::Error))
 9899                    .cursor_default()
 9900                    .hoverable_tooltip(move |_window, cx| {
 9901                        cx.new(|_| MissingEditPredictionKeybindingTooltip).into()
 9902                    })
 9903            })
 9904            .children(keybind)
 9905            .child(
 9906                Label::new(file_name)
 9907                    .size(LabelSize::Small)
 9908                    .buffer_font(cx)
 9909                    .when(!has_keybind, |el| {
 9910                        el.color(cx.theme().status().error.into()).strikethrough()
 9911                    }),
 9912            )
 9913            .when(!has_keybind, |el| {
 9914                el.child(
 9915                    h_flex().ml_1().child(
 9916                        Icon::new(IconName::Info)
 9917                            .size(IconSize::Small)
 9918                            .color(cx.theme().status().error.into()),
 9919                    ),
 9920                )
 9921            })
 9922            .child(
 9923                div()
 9924                    .mt(px(1.5))
 9925                    .child(Icon::new(IconName::ArrowUpRight).size(IconSize::Small)),
 9926            )
 9927    }
 9928
 9929    fn edit_prediction_line_popover_bg_color(cx: &App) -> Hsla {
 9930        let accent_color = cx.theme().colors().text_accent;
 9931        let editor_bg_color = cx.theme().colors().editor_background;
 9932        editor_bg_color.blend(accent_color.opacity(0.1))
 9933    }
 9934
 9935    fn edit_prediction_callout_popover_border_color(cx: &App) -> Hsla {
 9936        let accent_color = cx.theme().colors().text_accent;
 9937        let editor_bg_color = cx.theme().colors().editor_background;
 9938        editor_bg_color.blend(accent_color.opacity(0.6))
 9939    }
 9940    fn get_prediction_provider_icons(
 9941        provider: &Option<RegisteredEditPredictionDelegate>,
 9942        cx: &App,
 9943    ) -> edit_prediction_types::EditPredictionIconSet {
 9944        match provider {
 9945            Some(provider) => provider.provider.icons(cx),
 9946            None => edit_prediction_types::EditPredictionIconSet::new(IconName::ZedPredict),
 9947        }
 9948    }
 9949
 9950    fn render_edit_prediction_cursor_popover(
 9951        &self,
 9952        min_width: Pixels,
 9953        max_width: Pixels,
 9954        cursor_point: Point,
 9955        style: &EditorStyle,
 9956        accept_keystroke: Option<&gpui::KeybindingKeystroke>,
 9957        _window: &Window,
 9958        cx: &mut Context<Editor>,
 9959    ) -> Option<AnyElement> {
 9960        let provider = self.edit_prediction_provider.as_ref()?;
 9961        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
 9962
 9963        let is_refreshing = provider.provider.is_refreshing(cx);
 9964
 9965        fn pending_completion_container(icon: IconName) -> Div {
 9966            h_flex().h_full().flex_1().gap_2().child(Icon::new(icon))
 9967        }
 9968
 9969        let completion = match &self.active_edit_prediction {
 9970            Some(prediction) => {
 9971                if !self.has_visible_completions_menu() {
 9972                    const RADIUS: Pixels = px(6.);
 9973                    const BORDER_WIDTH: Pixels = px(1.);
 9974
 9975                    return Some(
 9976                        h_flex()
 9977                            .elevation_2(cx)
 9978                            .border(BORDER_WIDTH)
 9979                            .border_color(cx.theme().colors().border)
 9980                            .when(accept_keystroke.is_none(), |el| {
 9981                                el.border_color(cx.theme().status().error)
 9982                            })
 9983                            .rounded(RADIUS)
 9984                            .rounded_tl(px(0.))
 9985                            .overflow_hidden()
 9986                            .child(div().px_1p5().child(match &prediction.completion {
 9987                                EditPrediction::MoveWithin { target, snapshot } => {
 9988                                    use text::ToPoint as _;
 9989                                    if target.text_anchor.to_point(snapshot).row > cursor_point.row
 9990                                    {
 9991                                        Icon::new(icons.down)
 9992                                    } else {
 9993                                        Icon::new(icons.up)
 9994                                    }
 9995                                }
 9996                                EditPrediction::MoveOutside { .. } => {
 9997                                    // TODO [zeta2] custom icon for external jump?
 9998                                    Icon::new(icons.base)
 9999                                }
10000                                EditPrediction::Edit { .. } => Icon::new(icons.base),
10001                            }))
10002                            .child(
10003                                h_flex()
10004                                    .gap_1()
10005                                    .py_1()
10006                                    .px_2()
10007                                    .rounded_r(RADIUS - BORDER_WIDTH)
10008                                    .border_l_1()
10009                                    .border_color(cx.theme().colors().border)
10010                                    .bg(Self::edit_prediction_line_popover_bg_color(cx))
10011                                    .when(self.edit_prediction_preview.released_too_fast(), |el| {
10012                                        el.child(
10013                                            Label::new("Hold")
10014                                                .size(LabelSize::Small)
10015                                                .when(accept_keystroke.is_none(), |el| {
10016                                                    el.strikethrough()
10017                                                })
10018                                                .line_height_style(LineHeightStyle::UiLabel),
10019                                        )
10020                                    })
10021                                    .id("edit_prediction_cursor_popover_keybind")
10022                                    .when(accept_keystroke.is_none(), |el| {
10023                                        let status_colors = cx.theme().status();
10024
10025                                        el.bg(status_colors.error_background)
10026                                            .border_color(status_colors.error.opacity(0.6))
10027                                            .child(Icon::new(IconName::Info).color(Color::Error))
10028                                            .cursor_default()
10029                                            .hoverable_tooltip(move |_window, cx| {
10030                                                cx.new(|_| MissingEditPredictionKeybindingTooltip)
10031                                                    .into()
10032                                            })
10033                                    })
10034                                    .when_some(
10035                                        accept_keystroke.as_ref(),
10036                                        |el, accept_keystroke| {
10037                                            el.child(h_flex().children(ui::render_modifiers(
10038                                                accept_keystroke.modifiers(),
10039                                                PlatformStyle::platform(),
10040                                                Some(Color::Default),
10041                                                Some(IconSize::XSmall.rems().into()),
10042                                                false,
10043                                            )))
10044                                        },
10045                                    ),
10046                            )
10047                            .into_any(),
10048                    );
10049                }
10050
10051                self.render_edit_prediction_cursor_popover_preview(
10052                    prediction,
10053                    cursor_point,
10054                    style,
10055                    cx,
10056                )?
10057            }
10058
10059            None if is_refreshing => match &self.stale_edit_prediction_in_menu {
10060                Some(stale_completion) => self.render_edit_prediction_cursor_popover_preview(
10061                    stale_completion,
10062                    cursor_point,
10063                    style,
10064                    cx,
10065                )?,
10066
10067                None => pending_completion_container(icons.base)
10068                    .child(Label::new("...").size(LabelSize::Small)),
10069            },
10070
10071            None => pending_completion_container(icons.base)
10072                .child(Label::new("...").size(LabelSize::Small)),
10073        };
10074
10075        let completion = if is_refreshing || self.active_edit_prediction.is_none() {
10076            completion
10077                .with_animation(
10078                    "loading-completion",
10079                    Animation::new(Duration::from_secs(2))
10080                        .repeat()
10081                        .with_easing(pulsating_between(0.4, 0.8)),
10082                    |label, delta| label.opacity(delta),
10083                )
10084                .into_any_element()
10085        } else {
10086            completion.into_any_element()
10087        };
10088
10089        let has_completion = self.active_edit_prediction.is_some();
10090
10091        let is_platform_style_mac = PlatformStyle::platform() == PlatformStyle::Mac;
10092        Some(
10093            h_flex()
10094                .min_w(min_width)
10095                .max_w(max_width)
10096                .flex_1()
10097                .elevation_2(cx)
10098                .border_color(cx.theme().colors().border)
10099                .child(
10100                    div()
10101                        .flex_1()
10102                        .py_1()
10103                        .px_2()
10104                        .overflow_hidden()
10105                        .child(completion),
10106                )
10107                .when_some(accept_keystroke, |el, accept_keystroke| {
10108                    if !accept_keystroke.modifiers().modified() {
10109                        return el;
10110                    }
10111
10112                    el.child(
10113                        h_flex()
10114                            .h_full()
10115                            .border_l_1()
10116                            .rounded_r_lg()
10117                            .border_color(cx.theme().colors().border)
10118                            .bg(Self::edit_prediction_line_popover_bg_color(cx))
10119                            .gap_1()
10120                            .py_1()
10121                            .px_2()
10122                            .child(
10123                                h_flex()
10124                                    .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10125                                    .when(is_platform_style_mac, |parent| parent.gap_1())
10126                                    .child(h_flex().children(ui::render_modifiers(
10127                                        accept_keystroke.modifiers(),
10128                                        PlatformStyle::platform(),
10129                                        Some(if !has_completion {
10130                                            Color::Muted
10131                                        } else {
10132                                            Color::Default
10133                                        }),
10134                                        None,
10135                                        false,
10136                                    ))),
10137                            )
10138                            .child(Label::new("Preview").into_any_element())
10139                            .opacity(if has_completion { 1.0 } else { 0.4 }),
10140                    )
10141                })
10142                .into_any(),
10143        )
10144    }
10145
10146    fn render_edit_prediction_cursor_popover_preview(
10147        &self,
10148        completion: &EditPredictionState,
10149        cursor_point: Point,
10150        style: &EditorStyle,
10151        cx: &mut Context<Editor>,
10152    ) -> Option<Div> {
10153        use text::ToPoint as _;
10154
10155        fn render_relative_row_jump(
10156            prefix: impl Into<String>,
10157            current_row: u32,
10158            target_row: u32,
10159        ) -> Div {
10160            let (row_diff, arrow) = if target_row < current_row {
10161                (current_row - target_row, IconName::ArrowUp)
10162            } else {
10163                (target_row - current_row, IconName::ArrowDown)
10164            };
10165
10166            h_flex()
10167                .child(
10168                    Label::new(format!("{}{}", prefix.into(), row_diff))
10169                        .color(Color::Muted)
10170                        .size(LabelSize::Small),
10171                )
10172                .child(Icon::new(arrow).color(Color::Muted).size(IconSize::Small))
10173        }
10174
10175        let supports_jump = self
10176            .edit_prediction_provider
10177            .as_ref()
10178            .map(|provider| provider.provider.supports_jump_to_edit())
10179            .unwrap_or(true);
10180
10181        let icons = Self::get_prediction_provider_icons(&self.edit_prediction_provider, cx);
10182
10183        match &completion.completion {
10184            EditPrediction::MoveWithin {
10185                target, snapshot, ..
10186            } => {
10187                if !supports_jump {
10188                    return None;
10189                }
10190
10191                Some(
10192                    h_flex()
10193                        .px_2()
10194                        .gap_2()
10195                        .flex_1()
10196                        .child(
10197                            if target.text_anchor.to_point(snapshot).row > cursor_point.row {
10198                                Icon::new(icons.down)
10199                            } else {
10200                                Icon::new(icons.up)
10201                            },
10202                        )
10203                        .child(Label::new("Jump to Edit")),
10204                )
10205            }
10206            EditPrediction::MoveOutside { snapshot, .. } => {
10207                let file_name = snapshot
10208                    .file()
10209                    .map(|file| file.file_name(cx))
10210                    .unwrap_or("untitled");
10211                Some(
10212                    h_flex()
10213                        .px_2()
10214                        .gap_2()
10215                        .flex_1()
10216                        .child(Icon::new(icons.base))
10217                        .child(Label::new(format!("Jump to {file_name}"))),
10218                )
10219            }
10220            EditPrediction::Edit {
10221                edits,
10222                edit_preview,
10223                snapshot,
10224                ..
10225            } => {
10226                let first_edit_row = edits.first()?.0.start.text_anchor.to_point(snapshot).row;
10227
10228                let (highlighted_edits, has_more_lines) =
10229                    if let Some(edit_preview) = edit_preview.as_ref() {
10230                        crate::edit_prediction_edit_text(snapshot, edits, edit_preview, true, cx)
10231                            .first_line_preview()
10232                    } else {
10233                        crate::edit_prediction_fallback_text(edits, cx).first_line_preview()
10234                    };
10235
10236                let styled_text = gpui::StyledText::new(highlighted_edits.text)
10237                    .with_default_highlights(&style.text, highlighted_edits.highlights);
10238
10239                let preview = h_flex()
10240                    .gap_1()
10241                    .min_w_16()
10242                    .child(styled_text)
10243                    .when(has_more_lines, |parent| parent.child(""));
10244
10245                let left = if supports_jump && first_edit_row != cursor_point.row {
10246                    render_relative_row_jump("", cursor_point.row, first_edit_row)
10247                        .into_any_element()
10248                } else {
10249                    Icon::new(icons.base).into_any_element()
10250                };
10251
10252                Some(
10253                    h_flex()
10254                        .h_full()
10255                        .flex_1()
10256                        .gap_2()
10257                        .pr_1()
10258                        .overflow_x_hidden()
10259                        .font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
10260                        .child(left)
10261                        .child(preview),
10262                )
10263            }
10264        }
10265    }
10266
10267    pub fn render_context_menu(
10268        &mut self,
10269        max_height_in_lines: u32,
10270        window: &mut Window,
10271        cx: &mut Context<Editor>,
10272    ) -> Option<AnyElement> {
10273        let menu = self.context_menu.borrow();
10274        let menu = menu.as_ref()?;
10275        if !menu.visible() {
10276            return None;
10277        };
10278        self.style
10279            .as_ref()
10280            .map(|style| menu.render(style, max_height_in_lines, window, cx))
10281    }
10282
10283    fn render_context_menu_aside(
10284        &mut self,
10285        max_size: Size<Pixels>,
10286        window: &mut Window,
10287        cx: &mut Context<Editor>,
10288    ) -> Option<AnyElement> {
10289        self.context_menu.borrow_mut().as_mut().and_then(|menu| {
10290            if menu.visible() {
10291                menu.render_aside(max_size, window, cx)
10292            } else {
10293                None
10294            }
10295        })
10296    }
10297
10298    fn hide_context_menu(
10299        &mut self,
10300        window: &mut Window,
10301        cx: &mut Context<Self>,
10302    ) -> Option<CodeContextMenu> {
10303        cx.notify();
10304        self.completion_tasks.clear();
10305        let context_menu = self.context_menu.borrow_mut().take();
10306        self.stale_edit_prediction_in_menu.take();
10307        self.update_visible_edit_prediction(window, cx);
10308        if let Some(CodeContextMenu::Completions(_)) = &context_menu
10309            && let Some(completion_provider) = &self.completion_provider
10310        {
10311            completion_provider.selection_changed(None, window, cx);
10312        }
10313        context_menu
10314    }
10315
10316    fn show_snippet_choices(
10317        &mut self,
10318        choices: &Vec<String>,
10319        selection: Range<Anchor>,
10320        cx: &mut Context<Self>,
10321    ) {
10322        let Some((_, buffer, _)) = self
10323            .buffer()
10324            .read(cx)
10325            .excerpt_containing(selection.start, cx)
10326        else {
10327            return;
10328        };
10329        let Some((_, end_buffer, _)) = self.buffer().read(cx).excerpt_containing(selection.end, cx)
10330        else {
10331            return;
10332        };
10333        if buffer != end_buffer {
10334            log::error!("expected anchor range to have matching buffer IDs");
10335            return;
10336        }
10337
10338        let id = post_inc(&mut self.next_completion_id);
10339        let snippet_sort_order = EditorSettings::get_global(cx).snippet_sort_order;
10340        let mut context_menu = self.context_menu.borrow_mut();
10341        let old_menu = context_menu.take();
10342        *context_menu = Some(CodeContextMenu::Completions(
10343            CompletionsMenu::new_snippet_choices(
10344                id,
10345                true,
10346                choices,
10347                selection,
10348                buffer,
10349                old_menu.map(|menu| menu.primary_scroll_handle()),
10350                snippet_sort_order,
10351            ),
10352        ));
10353    }
10354
10355    pub fn insert_snippet(
10356        &mut self,
10357        insertion_ranges: &[Range<MultiBufferOffset>],
10358        snippet: Snippet,
10359        window: &mut Window,
10360        cx: &mut Context<Self>,
10361    ) -> Result<()> {
10362        struct Tabstop<T> {
10363            is_end_tabstop: bool,
10364            ranges: Vec<Range<T>>,
10365            choices: Option<Vec<String>>,
10366        }
10367
10368        let tabstops = self.buffer.update(cx, |buffer, cx| {
10369            let snippet_text: Arc<str> = snippet.text.clone().into();
10370            let edits = insertion_ranges
10371                .iter()
10372                .cloned()
10373                .map(|range| (range, snippet_text.clone()));
10374            let autoindent_mode = AutoindentMode::Block {
10375                original_indent_columns: Vec::new(),
10376            };
10377            buffer.edit(edits, Some(autoindent_mode), cx);
10378
10379            let snapshot = &*buffer.read(cx);
10380            let snippet = &snippet;
10381            snippet
10382                .tabstops
10383                .iter()
10384                .map(|tabstop| {
10385                    let is_end_tabstop = tabstop.ranges.first().is_some_and(|tabstop| {
10386                        tabstop.is_empty() && tabstop.start == snippet.text.len() as isize
10387                    });
10388                    let mut tabstop_ranges = tabstop
10389                        .ranges
10390                        .iter()
10391                        .flat_map(|tabstop_range| {
10392                            let mut delta = 0_isize;
10393                            insertion_ranges.iter().map(move |insertion_range| {
10394                                let insertion_start = insertion_range.start + delta;
10395                                delta += snippet.text.len() as isize
10396                                    - (insertion_range.end - insertion_range.start) as isize;
10397
10398                                let start =
10399                                    (insertion_start + tabstop_range.start).min(snapshot.len());
10400                                let end = (insertion_start + tabstop_range.end).min(snapshot.len());
10401                                snapshot.anchor_before(start)..snapshot.anchor_after(end)
10402                            })
10403                        })
10404                        .collect::<Vec<_>>();
10405                    tabstop_ranges.sort_unstable_by(|a, b| a.start.cmp(&b.start, snapshot));
10406
10407                    Tabstop {
10408                        is_end_tabstop,
10409                        ranges: tabstop_ranges,
10410                        choices: tabstop.choices.clone(),
10411                    }
10412                })
10413                .collect::<Vec<_>>()
10414        });
10415        if let Some(tabstop) = tabstops.first() {
10416            self.change_selections(Default::default(), window, cx, |s| {
10417                // Reverse order so that the first range is the newest created selection.
10418                // Completions will use it and autoscroll will prioritize it.
10419                s.select_ranges(tabstop.ranges.iter().rev().cloned());
10420            });
10421
10422            if let Some(choices) = &tabstop.choices
10423                && let Some(selection) = tabstop.ranges.first()
10424            {
10425                self.show_snippet_choices(choices, selection.clone(), cx)
10426            }
10427
10428            // If we're already at the last tabstop and it's at the end of the snippet,
10429            // we're done, we don't need to keep the state around.
10430            if !tabstop.is_end_tabstop {
10431                let choices = tabstops
10432                    .iter()
10433                    .map(|tabstop| tabstop.choices.clone())
10434                    .collect();
10435
10436                let ranges = tabstops
10437                    .into_iter()
10438                    .map(|tabstop| tabstop.ranges)
10439                    .collect::<Vec<_>>();
10440
10441                self.snippet_stack.push(SnippetState {
10442                    active_index: 0,
10443                    ranges,
10444                    choices,
10445                });
10446            }
10447
10448            // Check whether the just-entered snippet ends with an auto-closable bracket.
10449            if self.autoclose_regions.is_empty() {
10450                let snapshot = self.buffer.read(cx).snapshot(cx);
10451                for selection in &mut self.selections.all::<Point>(&self.display_snapshot(cx)) {
10452                    let selection_head = selection.head();
10453                    let Some(scope) = snapshot.language_scope_at(selection_head) else {
10454                        continue;
10455                    };
10456
10457                    let mut bracket_pair = None;
10458                    let max_lookup_length = scope
10459                        .brackets()
10460                        .map(|(pair, _)| {
10461                            pair.start
10462                                .as_str()
10463                                .chars()
10464                                .count()
10465                                .max(pair.end.as_str().chars().count())
10466                        })
10467                        .max();
10468                    if let Some(max_lookup_length) = max_lookup_length {
10469                        let next_text = snapshot
10470                            .chars_at(selection_head)
10471                            .take(max_lookup_length)
10472                            .collect::<String>();
10473                        let prev_text = snapshot
10474                            .reversed_chars_at(selection_head)
10475                            .take(max_lookup_length)
10476                            .collect::<String>();
10477
10478                        for (pair, enabled) in scope.brackets() {
10479                            if enabled
10480                                && pair.close
10481                                && prev_text.starts_with(pair.start.as_str())
10482                                && next_text.starts_with(pair.end.as_str())
10483                            {
10484                                bracket_pair = Some(pair.clone());
10485                                break;
10486                            }
10487                        }
10488                    }
10489
10490                    if let Some(pair) = bracket_pair {
10491                        let snapshot_settings = snapshot.language_settings_at(selection_head, cx);
10492                        let autoclose_enabled =
10493                            self.use_autoclose && snapshot_settings.use_autoclose;
10494                        if autoclose_enabled {
10495                            let start = snapshot.anchor_after(selection_head);
10496                            let end = snapshot.anchor_after(selection_head);
10497                            self.autoclose_regions.push(AutocloseRegion {
10498                                selection_id: selection.id,
10499                                range: start..end,
10500                                pair,
10501                            });
10502                        }
10503                    }
10504                }
10505            }
10506        }
10507        Ok(())
10508    }
10509
10510    pub fn move_to_next_snippet_tabstop(
10511        &mut self,
10512        window: &mut Window,
10513        cx: &mut Context<Self>,
10514    ) -> bool {
10515        self.move_to_snippet_tabstop(Bias::Right, window, cx)
10516    }
10517
10518    pub fn move_to_prev_snippet_tabstop(
10519        &mut self,
10520        window: &mut Window,
10521        cx: &mut Context<Self>,
10522    ) -> bool {
10523        self.move_to_snippet_tabstop(Bias::Left, window, cx)
10524    }
10525
10526    pub fn move_to_snippet_tabstop(
10527        &mut self,
10528        bias: Bias,
10529        window: &mut Window,
10530        cx: &mut Context<Self>,
10531    ) -> bool {
10532        if let Some(mut snippet) = self.snippet_stack.pop() {
10533            match bias {
10534                Bias::Left => {
10535                    if snippet.active_index > 0 {
10536                        snippet.active_index -= 1;
10537                    } else {
10538                        self.snippet_stack.push(snippet);
10539                        return false;
10540                    }
10541                }
10542                Bias::Right => {
10543                    if snippet.active_index + 1 < snippet.ranges.len() {
10544                        snippet.active_index += 1;
10545                    } else {
10546                        self.snippet_stack.push(snippet);
10547                        return false;
10548                    }
10549                }
10550            }
10551            if let Some(current_ranges) = snippet.ranges.get(snippet.active_index) {
10552                self.change_selections(Default::default(), window, cx, |s| {
10553                    // Reverse order so that the first range is the newest created selection.
10554                    // Completions will use it and autoscroll will prioritize it.
10555                    s.select_ranges(current_ranges.iter().rev().cloned())
10556                });
10557
10558                if let Some(choices) = &snippet.choices[snippet.active_index]
10559                    && let Some(selection) = current_ranges.first()
10560                {
10561                    self.show_snippet_choices(choices, selection.clone(), cx);
10562                }
10563
10564                // If snippet state is not at the last tabstop, push it back on the stack
10565                if snippet.active_index + 1 < snippet.ranges.len() {
10566                    self.snippet_stack.push(snippet);
10567                }
10568                return true;
10569            }
10570        }
10571
10572        false
10573    }
10574
10575    pub fn clear(&mut self, window: &mut Window, cx: &mut Context<Self>) {
10576        self.transact(window, cx, |this, window, cx| {
10577            this.select_all(&SelectAll, window, cx);
10578            this.insert("", window, cx);
10579        });
10580    }
10581
10582    pub fn backspace(&mut self, _: &Backspace, window: &mut Window, cx: &mut Context<Self>) {
10583        if self.read_only(cx) {
10584            return;
10585        }
10586        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10587        self.transact(window, cx, |this, window, cx| {
10588            this.select_autoclose_pair(window, cx);
10589
10590            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10591
10592            let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
10593            let mut selections = this.selections.all::<MultiBufferPoint>(&display_map);
10594            for selection in &mut selections {
10595                if selection.is_empty() {
10596                    let old_head = selection.head();
10597                    let mut new_head =
10598                        movement::left(&display_map, old_head.to_display_point(&display_map))
10599                            .to_point(&display_map);
10600                    if let Some((buffer, line_buffer_range)) = display_map
10601                        .buffer_snapshot()
10602                        .buffer_line_for_row(MultiBufferRow(old_head.row))
10603                    {
10604                        let indent_size = buffer.indent_size_for_line(line_buffer_range.start.row);
10605                        let indent_len = match indent_size.kind {
10606                            IndentKind::Space => {
10607                                buffer.settings_at(line_buffer_range.start, cx).tab_size
10608                            }
10609                            IndentKind::Tab => NonZeroU32::new(1).unwrap(),
10610                        };
10611                        if old_head.column <= indent_size.len && old_head.column > 0 {
10612                            let indent_len = indent_len.get();
10613                            new_head = cmp::min(
10614                                new_head,
10615                                MultiBufferPoint::new(
10616                                    old_head.row,
10617                                    ((old_head.column - 1) / indent_len) * indent_len,
10618                                ),
10619                            );
10620                        }
10621                    }
10622
10623                    selection.set_head(new_head, SelectionGoal::None);
10624                }
10625            }
10626
10627            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10628            this.insert("", window, cx);
10629            linked_edits.apply_with_left_expansion(cx);
10630            this.refresh_edit_prediction(true, false, window, cx);
10631            refresh_linked_ranges(this, window, cx);
10632        });
10633    }
10634
10635    pub fn delete(&mut self, _: &Delete, window: &mut Window, cx: &mut Context<Self>) {
10636        if self.read_only(cx) {
10637            return;
10638        }
10639        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10640        self.transact(window, cx, |this, window, cx| {
10641            this.change_selections(Default::default(), window, cx, |s| {
10642                s.move_with(&mut |map, selection| {
10643                    if selection.is_empty() {
10644                        let cursor = movement::right(map, selection.head());
10645                        selection.end = cursor;
10646                        selection.reversed = true;
10647                        selection.goal = SelectionGoal::None;
10648                    }
10649                })
10650            });
10651            let linked_edits = this.linked_edits_for_selections(Arc::from(""), cx);
10652            this.insert("", window, cx);
10653            linked_edits.apply(cx);
10654            this.refresh_edit_prediction(true, false, window, cx);
10655            refresh_linked_ranges(this, window, cx);
10656        });
10657    }
10658
10659    pub fn backtab(&mut self, _: &Backtab, window: &mut Window, cx: &mut Context<Self>) {
10660        if self.mode.is_single_line() {
10661            cx.propagate();
10662            return;
10663        }
10664
10665        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10666        if self.move_to_prev_snippet_tabstop(window, cx) {
10667            return;
10668        }
10669        self.outdent(&Outdent, window, cx);
10670    }
10671
10672    pub fn next_snippet_tabstop(
10673        &mut self,
10674        _: &NextSnippetTabstop,
10675        window: &mut Window,
10676        cx: &mut Context<Self>,
10677    ) {
10678        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10679            cx.propagate();
10680            return;
10681        }
10682
10683        if self.move_to_next_snippet_tabstop(window, cx) {
10684            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10685            return;
10686        }
10687        cx.propagate();
10688    }
10689
10690    pub fn previous_snippet_tabstop(
10691        &mut self,
10692        _: &PreviousSnippetTabstop,
10693        window: &mut Window,
10694        cx: &mut Context<Self>,
10695    ) {
10696        if self.mode.is_single_line() || self.snippet_stack.is_empty() {
10697            cx.propagate();
10698            return;
10699        }
10700
10701        if self.move_to_prev_snippet_tabstop(window, cx) {
10702            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10703            return;
10704        }
10705        cx.propagate();
10706    }
10707
10708    pub fn tab(&mut self, _: &Tab, window: &mut Window, cx: &mut Context<Self>) {
10709        if self.mode.is_single_line() {
10710            cx.propagate();
10711            return;
10712        }
10713
10714        if self.move_to_next_snippet_tabstop(window, cx) {
10715            self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10716            return;
10717        }
10718        if self.read_only(cx) {
10719            return;
10720        }
10721        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10722        let mut selections = self.selections.all_adjusted(&self.display_snapshot(cx));
10723        let buffer = self.buffer.read(cx);
10724        let snapshot = buffer.snapshot(cx);
10725        let rows_iter = selections.iter().map(|s| s.head().row);
10726        let suggested_indents = snapshot.suggested_indents(rows_iter, cx);
10727
10728        let has_some_cursor_in_whitespace = selections
10729            .iter()
10730            .filter(|selection| selection.is_empty())
10731            .any(|selection| {
10732                let cursor = selection.head();
10733                let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10734                cursor.column < current_indent.len
10735            });
10736
10737        let mut edits = Vec::new();
10738        let mut prev_edited_row = 0;
10739        let mut row_delta = 0;
10740        for selection in &mut selections {
10741            if selection.start.row != prev_edited_row {
10742                row_delta = 0;
10743            }
10744            prev_edited_row = selection.end.row;
10745
10746            // If cursor is after a list prefix, make selection non-empty to trigger line indent
10747            if selection.is_empty() {
10748                let cursor = selection.head();
10749                let settings = buffer.language_settings_at(cursor, cx);
10750                if settings.indent_list_on_tab {
10751                    if let Some(language) = snapshot.language_scope_at(Point::new(cursor.row, 0)) {
10752                        if is_list_prefix_row(MultiBufferRow(cursor.row), &snapshot, &language) {
10753                            row_delta = Self::indent_selection(
10754                                buffer, &snapshot, selection, &mut edits, row_delta, cx,
10755                            );
10756                            continue;
10757                        }
10758                    }
10759                }
10760            }
10761
10762            // If the selection is non-empty, then increase the indentation of the selected lines.
10763            if !selection.is_empty() {
10764                row_delta =
10765                    Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10766                continue;
10767            }
10768
10769            let cursor = selection.head();
10770            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(cursor.row));
10771            if let Some(suggested_indent) =
10772                suggested_indents.get(&MultiBufferRow(cursor.row)).copied()
10773            {
10774                // Don't do anything if already at suggested indent
10775                // and there is any other cursor which is not
10776                if has_some_cursor_in_whitespace
10777                    && cursor.column == current_indent.len
10778                    && current_indent.len == suggested_indent.len
10779                {
10780                    continue;
10781                }
10782
10783                // Adjust line and move cursor to suggested indent
10784                // if cursor is not at suggested indent
10785                if cursor.column < suggested_indent.len
10786                    && cursor.column <= current_indent.len
10787                    && current_indent.len <= suggested_indent.len
10788                {
10789                    selection.start = Point::new(cursor.row, suggested_indent.len);
10790                    selection.end = selection.start;
10791                    if row_delta == 0 {
10792                        edits.extend(Buffer::edit_for_indent_size_adjustment(
10793                            cursor.row,
10794                            current_indent,
10795                            suggested_indent,
10796                        ));
10797                        row_delta = suggested_indent.len - current_indent.len;
10798                    }
10799                    continue;
10800                }
10801
10802                // If current indent is more than suggested indent
10803                // only move cursor to current indent and skip indent
10804                if cursor.column < current_indent.len && current_indent.len > suggested_indent.len {
10805                    selection.start = Point::new(cursor.row, current_indent.len);
10806                    selection.end = selection.start;
10807                    continue;
10808                }
10809            }
10810
10811            // Otherwise, insert a hard or soft tab.
10812            let settings = buffer.language_settings_at(cursor, cx);
10813            let tab_size = if settings.hard_tabs {
10814                IndentSize::tab()
10815            } else {
10816                let tab_size = settings.tab_size.get();
10817                let indent_remainder = snapshot
10818                    .text_for_range(Point::new(cursor.row, 0)..cursor)
10819                    .flat_map(str::chars)
10820                    .fold(row_delta % tab_size, |counter: u32, c| {
10821                        if c == '\t' {
10822                            0
10823                        } else {
10824                            (counter + 1) % tab_size
10825                        }
10826                    });
10827
10828                let chars_to_next_tab_stop = tab_size - indent_remainder;
10829                IndentSize::spaces(chars_to_next_tab_stop)
10830            };
10831            selection.start = Point::new(cursor.row, cursor.column + row_delta + tab_size.len);
10832            selection.end = selection.start;
10833            edits.push((cursor..cursor, tab_size.chars().collect::<String>()));
10834            row_delta += tab_size.len;
10835        }
10836
10837        self.transact(window, cx, |this, window, cx| {
10838            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10839            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10840            this.refresh_edit_prediction(true, false, window, cx);
10841        });
10842    }
10843
10844    pub fn indent(&mut self, _: &Indent, window: &mut Window, cx: &mut Context<Self>) {
10845        if self.read_only(cx) {
10846            return;
10847        }
10848        if self.mode.is_single_line() {
10849            cx.propagate();
10850            return;
10851        }
10852
10853        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10854        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
10855        let mut prev_edited_row = 0;
10856        let mut row_delta = 0;
10857        let mut edits = Vec::new();
10858        let buffer = self.buffer.read(cx);
10859        let snapshot = buffer.snapshot(cx);
10860        for selection in &mut selections {
10861            if selection.start.row != prev_edited_row {
10862                row_delta = 0;
10863            }
10864            prev_edited_row = selection.end.row;
10865
10866            row_delta =
10867                Self::indent_selection(buffer, &snapshot, selection, &mut edits, row_delta, cx);
10868        }
10869
10870        self.transact(window, cx, |this, window, cx| {
10871            this.buffer.update(cx, |b, cx| b.edit(edits, None, cx));
10872            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
10873        });
10874    }
10875
10876    fn indent_selection(
10877        buffer: &MultiBuffer,
10878        snapshot: &MultiBufferSnapshot,
10879        selection: &mut Selection<Point>,
10880        edits: &mut Vec<(Range<Point>, String)>,
10881        delta_for_start_row: u32,
10882        cx: &App,
10883    ) -> u32 {
10884        let settings = buffer.language_settings_at(selection.start, cx);
10885        let tab_size = settings.tab_size.get();
10886        let indent_kind = if settings.hard_tabs {
10887            IndentKind::Tab
10888        } else {
10889            IndentKind::Space
10890        };
10891        let mut start_row = selection.start.row;
10892        let mut end_row = selection.end.row + 1;
10893
10894        // If a selection ends at the beginning of a line, don't indent
10895        // that last line.
10896        if selection.end.column == 0 && selection.end.row > selection.start.row {
10897            end_row -= 1;
10898        }
10899
10900        // Avoid re-indenting a row that has already been indented by a
10901        // previous selection, but still update this selection's column
10902        // to reflect that indentation.
10903        if delta_for_start_row > 0 {
10904            start_row += 1;
10905            selection.start.column += delta_for_start_row;
10906            if selection.end.row == selection.start.row {
10907                selection.end.column += delta_for_start_row;
10908            }
10909        }
10910
10911        let mut delta_for_end_row = 0;
10912        let has_multiple_rows = start_row + 1 != end_row;
10913        for row in start_row..end_row {
10914            let current_indent = snapshot.indent_size_for_line(MultiBufferRow(row));
10915            let indent_delta = match (current_indent.kind, indent_kind) {
10916                (IndentKind::Space, IndentKind::Space) => {
10917                    let columns_to_next_tab_stop = tab_size - (current_indent.len % tab_size);
10918                    IndentSize::spaces(columns_to_next_tab_stop)
10919                }
10920                (IndentKind::Tab, IndentKind::Space) => IndentSize::spaces(tab_size),
10921                (_, IndentKind::Tab) => IndentSize::tab(),
10922            };
10923
10924            let start = if has_multiple_rows || current_indent.len < selection.start.column {
10925                0
10926            } else {
10927                selection.start.column
10928            };
10929            let row_start = Point::new(row, start);
10930            edits.push((
10931                row_start..row_start,
10932                indent_delta.chars().collect::<String>(),
10933            ));
10934
10935            // Update this selection's endpoints to reflect the indentation.
10936            if row == selection.start.row {
10937                selection.start.column += indent_delta.len;
10938            }
10939            if row == selection.end.row {
10940                selection.end.column += indent_delta.len;
10941                delta_for_end_row = indent_delta.len;
10942            }
10943        }
10944
10945        if selection.start.row == selection.end.row {
10946            delta_for_start_row + delta_for_end_row
10947        } else {
10948            delta_for_end_row
10949        }
10950    }
10951
10952    pub fn outdent(&mut self, _: &Outdent, window: &mut Window, cx: &mut Context<Self>) {
10953        if self.read_only(cx) {
10954            return;
10955        }
10956        if self.mode.is_single_line() {
10957            cx.propagate();
10958            return;
10959        }
10960
10961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
10962        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
10963        let selections = self.selections.all::<Point>(&display_map);
10964        let mut deletion_ranges = Vec::new();
10965        let mut last_outdent = None;
10966        {
10967            let buffer = self.buffer.read(cx);
10968            let snapshot = buffer.snapshot(cx);
10969            for selection in &selections {
10970                let settings = buffer.language_settings_at(selection.start, cx);
10971                let tab_size = settings.tab_size.get();
10972                let mut rows = selection.spanned_rows(false, &display_map);
10973
10974                // Avoid re-outdenting a row that has already been outdented by a
10975                // previous selection.
10976                if let Some(last_row) = last_outdent
10977                    && last_row == rows.start
10978                {
10979                    rows.start = rows.start.next_row();
10980                }
10981                let has_multiple_rows = rows.len() > 1;
10982                for row in rows.iter_rows() {
10983                    let indent_size = snapshot.indent_size_for_line(row);
10984                    if indent_size.len > 0 {
10985                        let deletion_len = match indent_size.kind {
10986                            IndentKind::Space => {
10987                                let columns_to_prev_tab_stop = indent_size.len % tab_size;
10988                                if columns_to_prev_tab_stop == 0 {
10989                                    tab_size
10990                                } else {
10991                                    columns_to_prev_tab_stop
10992                                }
10993                            }
10994                            IndentKind::Tab => 1,
10995                        };
10996                        let start = if has_multiple_rows
10997                            || deletion_len > selection.start.column
10998                            || indent_size.len < selection.start.column
10999                        {
11000                            0
11001                        } else {
11002                            selection.start.column - deletion_len
11003                        };
11004                        deletion_ranges.push(
11005                            Point::new(row.0, start)..Point::new(row.0, start + deletion_len),
11006                        );
11007                        last_outdent = Some(row);
11008                    }
11009                }
11010            }
11011        }
11012
11013        self.transact(window, cx, |this, window, cx| {
11014            this.buffer.update(cx, |buffer, cx| {
11015                let empty_str: Arc<str> = Arc::default();
11016                buffer.edit(
11017                    deletion_ranges
11018                        .into_iter()
11019                        .map(|range| (range, empty_str.clone())),
11020                    None,
11021                    cx,
11022                );
11023            });
11024            let selections = this
11025                .selections
11026                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11027            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11028        });
11029    }
11030
11031    pub fn autoindent(&mut self, _: &AutoIndent, window: &mut Window, cx: &mut Context<Self>) {
11032        if self.read_only(cx) {
11033            return;
11034        }
11035        if self.mode.is_single_line() {
11036            cx.propagate();
11037            return;
11038        }
11039
11040        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11041        let selections = self
11042            .selections
11043            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11044            .into_iter()
11045            .map(|s| s.range());
11046
11047        self.transact(window, cx, |this, window, cx| {
11048            this.buffer.update(cx, |buffer, cx| {
11049                buffer.autoindent_ranges(selections, cx);
11050            });
11051            let selections = this
11052                .selections
11053                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
11054            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
11055        });
11056    }
11057
11058    pub fn delete_line(&mut self, _: &DeleteLine, window: &mut Window, cx: &mut Context<Self>) {
11059        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11060        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
11061        let selections = self.selections.all::<Point>(&display_map);
11062
11063        let mut new_cursors = Vec::new();
11064        let mut edit_ranges = Vec::new();
11065        let mut selections = selections.iter().peekable();
11066        while let Some(selection) = selections.next() {
11067            let mut rows = selection.spanned_rows(false, &display_map);
11068
11069            // Accumulate contiguous regions of rows that we want to delete.
11070            while let Some(next_selection) = selections.peek() {
11071                let next_rows = next_selection.spanned_rows(false, &display_map);
11072                if next_rows.start <= rows.end {
11073                    rows.end = next_rows.end;
11074                    selections.next().unwrap();
11075                } else {
11076                    break;
11077                }
11078            }
11079
11080            let buffer = display_map.buffer_snapshot();
11081            let mut edit_start = ToOffset::to_offset(&Point::new(rows.start.0, 0), buffer);
11082            let (edit_end, target_row) = if buffer.max_point().row >= rows.end.0 {
11083                // If there's a line after the range, delete the \n from the end of the row range
11084                (
11085                    ToOffset::to_offset(&Point::new(rows.end.0, 0), buffer),
11086                    rows.end,
11087                )
11088            } else {
11089                // If there isn't a line after the range, delete the \n from the line before the
11090                // start of the row range
11091                edit_start = edit_start.saturating_sub_usize(1);
11092                (buffer.len(), rows.start.previous_row())
11093            };
11094
11095            let text_layout_details = self.text_layout_details(window, cx);
11096            let x = display_map.x_for_display_point(
11097                selection.head().to_display_point(&display_map),
11098                &text_layout_details,
11099            );
11100            let row = Point::new(target_row.0, 0)
11101                .to_display_point(&display_map)
11102                .row();
11103            let column = display_map.display_column_for_x(row, x, &text_layout_details);
11104
11105            new_cursors.push((
11106                selection.id,
11107                buffer.anchor_after(DisplayPoint::new(row, column).to_point(&display_map)),
11108                SelectionGoal::None,
11109            ));
11110            edit_ranges.push(edit_start..edit_end);
11111        }
11112
11113        self.transact(window, cx, |this, window, cx| {
11114            let buffer = this.buffer.update(cx, |buffer, cx| {
11115                let empty_str: Arc<str> = Arc::default();
11116                buffer.edit(
11117                    edit_ranges
11118                        .into_iter()
11119                        .map(|range| (range, empty_str.clone())),
11120                    None,
11121                    cx,
11122                );
11123                buffer.snapshot(cx)
11124            });
11125            let new_selections = new_cursors
11126                .into_iter()
11127                .map(|(id, cursor, goal)| {
11128                    let cursor = cursor.to_point(&buffer);
11129                    Selection {
11130                        id,
11131                        start: cursor,
11132                        end: cursor,
11133                        reversed: false,
11134                        goal,
11135                    }
11136                })
11137                .collect();
11138
11139            this.change_selections(Default::default(), window, cx, |s| {
11140                s.select(new_selections);
11141            });
11142        });
11143    }
11144
11145    pub fn join_lines_impl(
11146        &mut self,
11147        insert_whitespace: bool,
11148        window: &mut Window,
11149        cx: &mut Context<Self>,
11150    ) {
11151        if self.read_only(cx) {
11152            return;
11153        }
11154        let mut row_ranges = Vec::<Range<MultiBufferRow>>::new();
11155        for selection in self.selections.all::<Point>(&self.display_snapshot(cx)) {
11156            let start = MultiBufferRow(selection.start.row);
11157            // Treat single line selections as if they include the next line. Otherwise this action
11158            // would do nothing for single line selections individual cursors.
11159            let end = if selection.start.row == selection.end.row {
11160                MultiBufferRow(selection.start.row + 1)
11161            } else if selection.end.column == 0 {
11162                // If the selection ends at the start of a line, it's logically at the end of the
11163                // previous line (plus its newline).
11164                // Don't include the end line unless there's only one line selected.
11165                if selection.start.row + 1 == selection.end.row {
11166                    MultiBufferRow(selection.end.row)
11167                } else {
11168                    MultiBufferRow(selection.end.row - 1)
11169                }
11170            } else {
11171                MultiBufferRow(selection.end.row)
11172            };
11173
11174            if let Some(last_row_range) = row_ranges.last_mut()
11175                && start <= last_row_range.end
11176            {
11177                last_row_range.end = end;
11178                continue;
11179            }
11180            row_ranges.push(start..end);
11181        }
11182
11183        let snapshot = self.buffer.read(cx).snapshot(cx);
11184        let mut cursor_positions = Vec::new();
11185        for row_range in &row_ranges {
11186            let anchor = snapshot.anchor_before(Point::new(
11187                row_range.end.previous_row().0,
11188                snapshot.line_len(row_range.end.previous_row()),
11189            ));
11190            cursor_positions.push(anchor..anchor);
11191        }
11192
11193        self.transact(window, cx, |this, window, cx| {
11194            for row_range in row_ranges.into_iter().rev() {
11195                for row in row_range.iter_rows().rev() {
11196                    let end_of_line = Point::new(row.0, snapshot.line_len(row));
11197                    let next_line_row = row.next_row();
11198                    let indent = snapshot.indent_size_for_line(next_line_row);
11199                    let mut join_start_column = indent.len;
11200
11201                    if let Some(language_scope) =
11202                        snapshot.language_scope_at(Point::new(next_line_row.0, indent.len))
11203                    {
11204                        let line_end =
11205                            Point::new(next_line_row.0, snapshot.line_len(next_line_row));
11206                        let line_text_after_indent = snapshot
11207                            .text_for_range(Point::new(next_line_row.0, indent.len)..line_end)
11208                            .collect::<String>();
11209
11210                        if !line_text_after_indent.is_empty() {
11211                            let block_prefix = language_scope
11212                                .block_comment()
11213                                .map(|c| c.prefix.as_ref())
11214                                .filter(|p| !p.is_empty());
11215                            let doc_prefix = language_scope
11216                                .documentation_comment()
11217                                .map(|c| c.prefix.as_ref())
11218                                .filter(|p| !p.is_empty());
11219                            let all_prefixes = language_scope
11220                                .line_comment_prefixes()
11221                                .iter()
11222                                .map(|p| p.as_ref())
11223                                .chain(block_prefix)
11224                                .chain(doc_prefix)
11225                                .chain(language_scope.unordered_list().iter().map(|p| p.as_ref()));
11226
11227                            let mut longest_prefix_len = None;
11228                            for prefix in all_prefixes {
11229                                let trimmed = prefix.trim_end();
11230                                if line_text_after_indent.starts_with(trimmed) {
11231                                    let candidate_len =
11232                                        if line_text_after_indent.starts_with(prefix) {
11233                                            prefix.len()
11234                                        } else {
11235                                            trimmed.len()
11236                                        };
11237                                    if longest_prefix_len.map_or(true, |len| candidate_len > len) {
11238                                        longest_prefix_len = Some(candidate_len);
11239                                    }
11240                                }
11241                            }
11242
11243                            if let Some(prefix_len) = longest_prefix_len {
11244                                join_start_column =
11245                                    join_start_column.saturating_add(prefix_len as u32);
11246                            }
11247                        }
11248                    }
11249
11250                    let start_of_next_line = Point::new(next_line_row.0, join_start_column);
11251
11252                    let replace = if snapshot.line_len(next_line_row) > join_start_column
11253                        && insert_whitespace
11254                    {
11255                        " "
11256                    } else {
11257                        ""
11258                    };
11259
11260                    this.buffer.update(cx, |buffer, cx| {
11261                        buffer.edit([(end_of_line..start_of_next_line, replace)], None, cx)
11262                    });
11263                }
11264            }
11265
11266            this.change_selections(Default::default(), window, cx, |s| {
11267                s.select_anchor_ranges(cursor_positions)
11268            });
11269        });
11270    }
11271
11272    pub fn join_lines(&mut self, _: &JoinLines, window: &mut Window, cx: &mut Context<Self>) {
11273        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11274        self.join_lines_impl(true, window, cx);
11275    }
11276
11277    pub fn sort_lines_case_sensitive(
11278        &mut self,
11279        _: &SortLinesCaseSensitive,
11280        window: &mut Window,
11281        cx: &mut Context<Self>,
11282    ) {
11283        self.manipulate_immutable_lines(window, cx, |lines| lines.sort())
11284    }
11285
11286    pub fn sort_lines_by_length(
11287        &mut self,
11288        _: &SortLinesByLength,
11289        window: &mut Window,
11290        cx: &mut Context<Self>,
11291    ) {
11292        self.manipulate_immutable_lines(window, cx, |lines| {
11293            lines.sort_by_key(|&line| line.chars().count())
11294        })
11295    }
11296
11297    pub fn sort_lines_case_insensitive(
11298        &mut self,
11299        _: &SortLinesCaseInsensitive,
11300        window: &mut Window,
11301        cx: &mut Context<Self>,
11302    ) {
11303        self.manipulate_immutable_lines(window, cx, |lines| {
11304            lines.sort_by_key(|line| line.to_lowercase())
11305        })
11306    }
11307
11308    pub fn unique_lines_case_insensitive(
11309        &mut self,
11310        _: &UniqueLinesCaseInsensitive,
11311        window: &mut Window,
11312        cx: &mut Context<Self>,
11313    ) {
11314        self.manipulate_immutable_lines(window, cx, |lines| {
11315            let mut seen = HashSet::default();
11316            lines.retain(|line| seen.insert(line.to_lowercase()));
11317        })
11318    }
11319
11320    pub fn unique_lines_case_sensitive(
11321        &mut self,
11322        _: &UniqueLinesCaseSensitive,
11323        window: &mut Window,
11324        cx: &mut Context<Self>,
11325    ) {
11326        self.manipulate_immutable_lines(window, cx, |lines| {
11327            let mut seen = HashSet::default();
11328            lines.retain(|line| seen.insert(*line));
11329        })
11330    }
11331
11332    fn enable_wrap_selections_in_tag(&self, cx: &App) -> bool {
11333        let snapshot = self.buffer.read(cx).snapshot(cx);
11334        for selection in self.selections.disjoint_anchors_arc().iter() {
11335            if snapshot
11336                .language_at(selection.start)
11337                .and_then(|lang| lang.config().wrap_characters.as_ref())
11338                .is_some()
11339            {
11340                return true;
11341            }
11342        }
11343        false
11344    }
11345
11346    fn wrap_selections_in_tag(
11347        &mut self,
11348        _: &WrapSelectionsInTag,
11349        window: &mut Window,
11350        cx: &mut Context<Self>,
11351    ) {
11352        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11353
11354        let snapshot = self.buffer.read(cx).snapshot(cx);
11355
11356        let mut edits = Vec::new();
11357        let mut boundaries = Vec::new();
11358
11359        for selection in self
11360            .selections
11361            .all_adjusted(&self.display_snapshot(cx))
11362            .iter()
11363        {
11364            let Some(wrap_config) = snapshot
11365                .language_at(selection.start)
11366                .and_then(|lang| lang.config().wrap_characters.clone())
11367            else {
11368                continue;
11369            };
11370
11371            let open_tag = format!("{}{}", wrap_config.start_prefix, wrap_config.start_suffix);
11372            let close_tag = format!("{}{}", wrap_config.end_prefix, wrap_config.end_suffix);
11373
11374            let start_before = snapshot.anchor_before(selection.start);
11375            let end_after = snapshot.anchor_after(selection.end);
11376
11377            edits.push((start_before..start_before, open_tag));
11378            edits.push((end_after..end_after, close_tag));
11379
11380            boundaries.push((
11381                start_before,
11382                end_after,
11383                wrap_config.start_prefix.len(),
11384                wrap_config.end_suffix.len(),
11385            ));
11386        }
11387
11388        if edits.is_empty() {
11389            return;
11390        }
11391
11392        self.transact(window, cx, |this, window, cx| {
11393            let buffer = this.buffer.update(cx, |buffer, cx| {
11394                buffer.edit(edits, None, cx);
11395                buffer.snapshot(cx)
11396            });
11397
11398            let mut new_selections = Vec::with_capacity(boundaries.len() * 2);
11399            for (start_before, end_after, start_prefix_len, end_suffix_len) in
11400                boundaries.into_iter()
11401            {
11402                let open_offset = start_before.to_offset(&buffer) + start_prefix_len;
11403                let close_offset = end_after
11404                    .to_offset(&buffer)
11405                    .saturating_sub_usize(end_suffix_len);
11406                new_selections.push(open_offset..open_offset);
11407                new_selections.push(close_offset..close_offset);
11408            }
11409
11410            this.change_selections(Default::default(), window, cx, |s| {
11411                s.select_ranges(new_selections);
11412            });
11413
11414            this.request_autoscroll(Autoscroll::fit(), cx);
11415        });
11416    }
11417
11418    pub fn toggle_read_only(
11419        &mut self,
11420        _: &workspace::ToggleReadOnlyFile,
11421        _: &mut Window,
11422        cx: &mut Context<Self>,
11423    ) {
11424        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
11425            buffer.update(cx, |buffer, cx| {
11426                buffer.set_capability(
11427                    match buffer.capability() {
11428                        Capability::ReadWrite => Capability::Read,
11429                        Capability::Read => Capability::ReadWrite,
11430                        Capability::ReadOnly => Capability::ReadOnly,
11431                    },
11432                    cx,
11433                );
11434            })
11435        }
11436    }
11437
11438    pub fn reload_file(&mut self, _: &ReloadFile, window: &mut Window, cx: &mut Context<Self>) {
11439        let Some(project) = self.project.clone() else {
11440            return;
11441        };
11442        let task = self.reload(project, window, cx);
11443        self.detach_and_notify_err(task, window, cx);
11444    }
11445
11446    pub fn restore_file(
11447        &mut self,
11448        _: &::git::RestoreFile,
11449        window: &mut Window,
11450        cx: &mut Context<Self>,
11451    ) {
11452        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11453        let mut buffer_ids = HashSet::default();
11454        let snapshot = self.buffer().read(cx).snapshot(cx);
11455        for selection in self
11456            .selections
11457            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
11458        {
11459            buffer_ids.extend(snapshot.buffer_ids_for_range(selection.range()))
11460        }
11461
11462        let buffer = self.buffer().read(cx);
11463        let ranges = buffer_ids
11464            .into_iter()
11465            .flat_map(|buffer_id| buffer.excerpt_ranges_for_buffer(buffer_id, cx))
11466            .collect::<Vec<_>>();
11467
11468        self.restore_hunks_in_ranges(ranges, window, cx);
11469    }
11470
11471    pub fn git_restore(&mut self, _: &Restore, window: &mut Window, cx: &mut Context<Self>) {
11472        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11473        let selections = self
11474            .selections
11475            .all(&self.display_snapshot(cx))
11476            .into_iter()
11477            .map(|s| s.range())
11478            .collect();
11479        self.restore_hunks_in_ranges(selections, window, cx);
11480    }
11481
11482    /// Restores the diff hunks in the editor's selections and moves the cursor
11483    /// to the next diff hunk. Wraps around to the beginning of the buffer if
11484    /// not all diff hunks are expanded.
11485    pub fn restore_and_next(
11486        &mut self,
11487        _: &::git::RestoreAndNext,
11488        window: &mut Window,
11489        cx: &mut Context<Self>,
11490    ) {
11491        let selections = self
11492            .selections
11493            .all(&self.display_snapshot(cx))
11494            .into_iter()
11495            .map(|selection| selection.range())
11496            .collect();
11497
11498        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
11499        self.restore_hunks_in_ranges(selections, window, cx);
11500
11501        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
11502        let wrap_around = !all_diff_hunks_expanded;
11503        let snapshot = self.snapshot(window, cx);
11504        let position = self
11505            .selections
11506            .newest::<Point>(&snapshot.display_snapshot)
11507            .head();
11508
11509        self.go_to_hunk_before_or_after_position(
11510            &snapshot,
11511            position,
11512            Direction::Next,
11513            wrap_around,
11514            window,
11515            cx,
11516        );
11517    }
11518
11519    pub fn restore_hunks_in_ranges(
11520        &mut self,
11521        ranges: Vec<Range<Point>>,
11522        window: &mut Window,
11523        cx: &mut Context<Editor>,
11524    ) {
11525        if self.delegate_stage_and_restore {
11526            let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11527            if !hunks.is_empty() {
11528                cx.emit(EditorEvent::RestoreRequested { hunks });
11529            }
11530            return;
11531        }
11532        let hunks = self.snapshot(window, cx).hunks_for_ranges(ranges);
11533        self.transact(window, cx, |editor, window, cx| {
11534            editor.restore_diff_hunks(hunks, cx);
11535            editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
11536                selections.refresh()
11537            });
11538        });
11539    }
11540
11541    pub(crate) fn restore_diff_hunks(&self, hunks: Vec<MultiBufferDiffHunk>, cx: &mut App) {
11542        let mut revert_changes = HashMap::default();
11543        let chunk_by = hunks.into_iter().chunk_by(|hunk| hunk.buffer_id);
11544        for (buffer_id, hunks) in &chunk_by {
11545            let hunks = hunks.collect::<Vec<_>>();
11546            for hunk in &hunks {
11547                self.prepare_restore_change(&mut revert_changes, hunk, cx);
11548            }
11549            self.do_stage_or_unstage(false, buffer_id, hunks.into_iter(), cx);
11550        }
11551        if !revert_changes.is_empty() {
11552            self.buffer().update(cx, |multi_buffer, cx| {
11553                for (buffer_id, changes) in revert_changes {
11554                    if let Some(buffer) = multi_buffer.buffer(buffer_id) {
11555                        buffer.update(cx, |buffer, cx| {
11556                            buffer.edit(
11557                                changes
11558                                    .into_iter()
11559                                    .map(|(range, text)| (range, text.to_string())),
11560                                None,
11561                                cx,
11562                            );
11563                        });
11564                    }
11565                }
11566            });
11567        }
11568    }
11569
11570    pub fn status_for_buffer_id(&self, buffer_id: BufferId, cx: &App) -> Option<FileStatus> {
11571        if let Some(status) = self
11572            .addons
11573            .iter()
11574            .find_map(|(_, addon)| addon.override_status_for_buffer_id(buffer_id, cx))
11575        {
11576            return Some(status);
11577        }
11578        self.project
11579            .as_ref()?
11580            .read(cx)
11581            .status_for_buffer_id(buffer_id, cx)
11582    }
11583
11584    pub fn open_active_item_in_terminal(
11585        &mut self,
11586        _: &OpenInTerminal,
11587        window: &mut Window,
11588        cx: &mut Context<Self>,
11589    ) {
11590        if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
11591            let project_path = buffer.read(cx).project_path(cx)?;
11592            let project = self.project()?.read(cx);
11593            let entry = project.entry_for_path(&project_path, cx)?;
11594            let parent = match &entry.canonical_path {
11595                Some(canonical_path) => canonical_path.to_path_buf(),
11596                None => project.absolute_path(&project_path, cx)?,
11597            }
11598            .parent()?
11599            .to_path_buf();
11600            Some(parent)
11601        }) {
11602            window.dispatch_action(
11603                OpenTerminal {
11604                    working_directory,
11605                    local: false,
11606                }
11607                .boxed_clone(),
11608                cx,
11609            );
11610        }
11611    }
11612
11613    fn set_breakpoint_context_menu(
11614        &mut self,
11615        display_row: DisplayRow,
11616        position: Option<Anchor>,
11617        clicked_point: gpui::Point<Pixels>,
11618        window: &mut Window,
11619        cx: &mut Context<Self>,
11620    ) {
11621        let source = self
11622            .buffer
11623            .read(cx)
11624            .snapshot(cx)
11625            .anchor_before(Point::new(display_row.0, 0u32));
11626
11627        let context_menu = self.breakpoint_context_menu(position.unwrap_or(source), window, cx);
11628
11629        self.mouse_context_menu = MouseContextMenu::pinned_to_editor(
11630            self,
11631            source,
11632            clicked_point,
11633            context_menu,
11634            window,
11635            cx,
11636        );
11637    }
11638
11639    fn add_edit_breakpoint_block(
11640        &mut self,
11641        anchor: Anchor,
11642        breakpoint: &Breakpoint,
11643        edit_action: BreakpointPromptEditAction,
11644        window: &mut Window,
11645        cx: &mut Context<Self>,
11646    ) {
11647        let weak_editor = cx.weak_entity();
11648        let bp_prompt = cx.new(|cx| {
11649            BreakpointPromptEditor::new(
11650                weak_editor,
11651                anchor,
11652                breakpoint.clone(),
11653                edit_action,
11654                window,
11655                cx,
11656            )
11657        });
11658
11659        let height = bp_prompt.update(cx, |this, cx| {
11660            this.prompt
11661                .update(cx, |prompt, cx| prompt.max_point(cx).row().0 + 1 + 2)
11662        });
11663        let cloned_prompt = bp_prompt.clone();
11664        let blocks = vec![BlockProperties {
11665            style: BlockStyle::Sticky,
11666            placement: BlockPlacement::Above(anchor),
11667            height: Some(height),
11668            render: Arc::new(move |cx| {
11669                *cloned_prompt.read(cx).editor_margins.lock() = *cx.margins;
11670                cloned_prompt.clone().into_any_element()
11671            }),
11672            priority: 0,
11673        }];
11674
11675        let focus_handle = bp_prompt.focus_handle(cx);
11676        window.focus(&focus_handle, cx);
11677
11678        let block_ids = self.insert_blocks(blocks, None, cx);
11679        bp_prompt.update(cx, |prompt, _| {
11680            prompt.add_block_ids(block_ids);
11681        });
11682    }
11683
11684    pub(crate) fn breakpoint_at_row(
11685        &self,
11686        row: u32,
11687        window: &mut Window,
11688        cx: &mut Context<Self>,
11689    ) -> Option<(Anchor, Breakpoint)> {
11690        let snapshot = self.snapshot(window, cx);
11691        let breakpoint_position = snapshot.buffer_snapshot().anchor_before(Point::new(row, 0));
11692
11693        self.breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11694    }
11695
11696    pub(crate) fn breakpoint_at_anchor(
11697        &self,
11698        breakpoint_position: Anchor,
11699        snapshot: &EditorSnapshot,
11700        cx: &mut Context<Self>,
11701    ) -> Option<(Anchor, Breakpoint)> {
11702        let buffer = self
11703            .buffer
11704            .read(cx)
11705            .buffer_for_anchor(breakpoint_position, cx)?;
11706
11707        let enclosing_excerpt = breakpoint_position.excerpt_id;
11708        let buffer_snapshot = buffer.read(cx).snapshot();
11709
11710        let row = buffer_snapshot
11711            .summary_for_anchor::<text::PointUtf16>(&breakpoint_position.text_anchor)
11712            .row;
11713
11714        let line_len = snapshot.buffer_snapshot().line_len(MultiBufferRow(row));
11715        let anchor_end = snapshot
11716            .buffer_snapshot()
11717            .anchor_after(Point::new(row, line_len));
11718
11719        self.breakpoint_store
11720            .as_ref()?
11721            .read_with(cx, |breakpoint_store, cx| {
11722                breakpoint_store
11723                    .breakpoints(
11724                        &buffer,
11725                        Some(breakpoint_position.text_anchor..anchor_end.text_anchor),
11726                        &buffer_snapshot,
11727                        cx,
11728                    )
11729                    .next()
11730                    .and_then(|(bp, _)| {
11731                        let breakpoint_row = buffer_snapshot
11732                            .summary_for_anchor::<text::PointUtf16>(&bp.position)
11733                            .row;
11734
11735                        if breakpoint_row == row {
11736                            snapshot
11737                                .buffer_snapshot()
11738                                .anchor_in_excerpt(enclosing_excerpt, bp.position)
11739                                .map(|position| (position, bp.bp.clone()))
11740                        } else {
11741                            None
11742                        }
11743                    })
11744            })
11745    }
11746
11747    pub fn edit_log_breakpoint(
11748        &mut self,
11749        _: &EditLogBreakpoint,
11750        window: &mut Window,
11751        cx: &mut Context<Self>,
11752    ) {
11753        if self.breakpoint_store.is_none() {
11754            return;
11755        }
11756
11757        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11758            let breakpoint = breakpoint.unwrap_or_else(|| Breakpoint {
11759                message: None,
11760                state: BreakpointState::Enabled,
11761                condition: None,
11762                hit_condition: None,
11763            });
11764
11765            self.add_edit_breakpoint_block(
11766                anchor,
11767                &breakpoint,
11768                BreakpointPromptEditAction::Log,
11769                window,
11770                cx,
11771            );
11772        }
11773    }
11774
11775    fn breakpoints_at_cursors(
11776        &self,
11777        window: &mut Window,
11778        cx: &mut Context<Self>,
11779    ) -> Vec<(Anchor, Option<Breakpoint>)> {
11780        let snapshot = self.snapshot(window, cx);
11781        let cursors = self
11782            .selections
11783            .disjoint_anchors_arc()
11784            .iter()
11785            .map(|selection| {
11786                let cursor_position: Point = selection.head().to_point(&snapshot.buffer_snapshot());
11787
11788                let breakpoint_position = self
11789                    .breakpoint_at_row(cursor_position.row, window, cx)
11790                    .map(|bp| bp.0)
11791                    .unwrap_or_else(|| {
11792                        snapshot
11793                            .display_snapshot
11794                            .buffer_snapshot()
11795                            .anchor_after(Point::new(cursor_position.row, 0))
11796                    });
11797
11798                let breakpoint = self
11799                    .breakpoint_at_anchor(breakpoint_position, &snapshot, cx)
11800                    .map(|(anchor, breakpoint)| (anchor, Some(breakpoint)));
11801
11802                breakpoint.unwrap_or_else(|| (breakpoint_position, None))
11803            })
11804            // 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.
11805            .collect::<HashMap<Anchor, _>>();
11806
11807        cursors.into_iter().collect()
11808    }
11809
11810    pub fn enable_breakpoint(
11811        &mut self,
11812        _: &crate::actions::EnableBreakpoint,
11813        window: &mut Window,
11814        cx: &mut Context<Self>,
11815    ) {
11816        if self.breakpoint_store.is_none() {
11817            return;
11818        }
11819
11820        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11821            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_disabled()) else {
11822                continue;
11823            };
11824            self.edit_breakpoint_at_anchor(
11825                anchor,
11826                breakpoint,
11827                BreakpointEditAction::InvertState,
11828                cx,
11829            );
11830        }
11831    }
11832
11833    pub fn disable_breakpoint(
11834        &mut self,
11835        _: &crate::actions::DisableBreakpoint,
11836        window: &mut Window,
11837        cx: &mut Context<Self>,
11838    ) {
11839        if self.breakpoint_store.is_none() {
11840            return;
11841        }
11842
11843        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11844            let Some(breakpoint) = breakpoint.filter(|breakpoint| breakpoint.is_enabled()) else {
11845                continue;
11846            };
11847            self.edit_breakpoint_at_anchor(
11848                anchor,
11849                breakpoint,
11850                BreakpointEditAction::InvertState,
11851                cx,
11852            );
11853        }
11854    }
11855
11856    pub fn toggle_breakpoint(
11857        &mut self,
11858        _: &crate::actions::ToggleBreakpoint,
11859        window: &mut Window,
11860        cx: &mut Context<Self>,
11861    ) {
11862        if self.breakpoint_store.is_none() {
11863            return;
11864        }
11865
11866        let snapshot = self.snapshot(window, cx);
11867        for (anchor, breakpoint) in self.breakpoints_at_cursors(window, cx) {
11868            if self.gutter_breakpoint_indicator.0.is_some() {
11869                let display_row = anchor
11870                    .to_point(snapshot.buffer_snapshot())
11871                    .to_display_point(&snapshot.display_snapshot)
11872                    .row();
11873                self.update_breakpoint_collision_on_toggle(
11874                    display_row,
11875                    &BreakpointEditAction::Toggle,
11876                );
11877            }
11878
11879            if let Some(breakpoint) = breakpoint {
11880                self.edit_breakpoint_at_anchor(
11881                    anchor,
11882                    breakpoint,
11883                    BreakpointEditAction::Toggle,
11884                    cx,
11885                );
11886            } else {
11887                self.edit_breakpoint_at_anchor(
11888                    anchor,
11889                    Breakpoint::new_standard(),
11890                    BreakpointEditAction::Toggle,
11891                    cx,
11892                );
11893            }
11894        }
11895    }
11896
11897    fn update_breakpoint_collision_on_toggle(
11898        &mut self,
11899        display_row: DisplayRow,
11900        edit_action: &BreakpointEditAction,
11901    ) {
11902        if let Some(ref mut breakpoint_indicator) = self.gutter_breakpoint_indicator.0 {
11903            if breakpoint_indicator.display_row == display_row
11904                && matches!(edit_action, BreakpointEditAction::Toggle)
11905            {
11906                breakpoint_indicator.collides_with_existing_breakpoint =
11907                    !breakpoint_indicator.collides_with_existing_breakpoint;
11908            }
11909        }
11910    }
11911
11912    pub fn edit_breakpoint_at_anchor(
11913        &mut self,
11914        breakpoint_position: Anchor,
11915        breakpoint: Breakpoint,
11916        edit_action: BreakpointEditAction,
11917        cx: &mut Context<Self>,
11918    ) {
11919        let Some(breakpoint_store) = &self.breakpoint_store else {
11920            return;
11921        };
11922
11923        let Some(buffer) = self
11924            .buffer
11925            .read(cx)
11926            .buffer_for_anchor(breakpoint_position, cx)
11927        else {
11928            return;
11929        };
11930
11931        breakpoint_store.update(cx, |breakpoint_store, cx| {
11932            breakpoint_store.toggle_breakpoint(
11933                buffer,
11934                BreakpointWithPosition {
11935                    position: breakpoint_position.text_anchor,
11936                    bp: breakpoint,
11937                },
11938                edit_action,
11939                cx,
11940            );
11941        });
11942
11943        cx.notify();
11944    }
11945
11946    #[cfg(any(test, feature = "test-support"))]
11947    pub fn breakpoint_store(&self) -> Option<Entity<BreakpointStore>> {
11948        self.breakpoint_store.clone()
11949    }
11950
11951    pub fn prepare_restore_change(
11952        &self,
11953        revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
11954        hunk: &MultiBufferDiffHunk,
11955        cx: &mut App,
11956    ) -> Option<()> {
11957        if hunk.is_created_file() {
11958            return None;
11959        }
11960        let buffer = self.buffer.read(cx);
11961        let diff = buffer.diff_for(hunk.buffer_id)?;
11962        let buffer = buffer.buffer(hunk.buffer_id)?;
11963        let buffer = buffer.read(cx);
11964        let original_text = diff
11965            .read(cx)
11966            .base_text(cx)
11967            .as_rope()
11968            .slice(hunk.diff_base_byte_range.start.0..hunk.diff_base_byte_range.end.0);
11969        let buffer_snapshot = buffer.snapshot();
11970        let buffer_revert_changes = revert_changes.entry(buffer.remote_id()).or_default();
11971        if let Err(i) = buffer_revert_changes.binary_search_by(|probe| {
11972            probe
11973                .0
11974                .start
11975                .cmp(&hunk.buffer_range.start, &buffer_snapshot)
11976                .then(probe.0.end.cmp(&hunk.buffer_range.end, &buffer_snapshot))
11977        }) {
11978            buffer_revert_changes.insert(i, (hunk.buffer_range.clone(), original_text));
11979            Some(())
11980        } else {
11981            None
11982        }
11983    }
11984
11985    pub fn reverse_lines(&mut self, _: &ReverseLines, window: &mut Window, cx: &mut Context<Self>) {
11986        self.manipulate_immutable_lines(window, cx, |lines| lines.reverse())
11987    }
11988
11989    pub fn shuffle_lines(&mut self, _: &ShuffleLines, window: &mut Window, cx: &mut Context<Self>) {
11990        self.manipulate_immutable_lines(window, cx, |lines| lines.shuffle(&mut rand::rng()))
11991    }
11992
11993    pub fn rotate_selections_forward(
11994        &mut self,
11995        _: &RotateSelectionsForward,
11996        window: &mut Window,
11997        cx: &mut Context<Self>,
11998    ) {
11999        self.rotate_selections(window, cx, false)
12000    }
12001
12002    pub fn rotate_selections_backward(
12003        &mut self,
12004        _: &RotateSelectionsBackward,
12005        window: &mut Window,
12006        cx: &mut Context<Self>,
12007    ) {
12008        self.rotate_selections(window, cx, true)
12009    }
12010
12011    fn rotate_selections(&mut self, window: &mut Window, cx: &mut Context<Self>, reverse: bool) {
12012        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12013        let display_snapshot = self.display_snapshot(cx);
12014        let selections = self.selections.all::<MultiBufferOffset>(&display_snapshot);
12015
12016        if selections.len() < 2 {
12017            return;
12018        }
12019
12020        let (edits, new_selections) = {
12021            let buffer = self.buffer.read(cx).read(cx);
12022            let has_selections = selections.iter().any(|s| !s.is_empty());
12023            if has_selections {
12024                let mut selected_texts: Vec<String> = selections
12025                    .iter()
12026                    .map(|selection| {
12027                        buffer
12028                            .text_for_range(selection.start..selection.end)
12029                            .collect()
12030                    })
12031                    .collect();
12032
12033                if reverse {
12034                    selected_texts.rotate_left(1);
12035                } else {
12036                    selected_texts.rotate_right(1);
12037                }
12038
12039                let mut offset_delta: i64 = 0;
12040                let mut new_selections = Vec::new();
12041                let edits: Vec<_> = selections
12042                    .iter()
12043                    .zip(selected_texts.iter())
12044                    .map(|(selection, new_text)| {
12045                        let old_len = (selection.end.0 - selection.start.0) as i64;
12046                        let new_len = new_text.len() as i64;
12047                        let adjusted_start =
12048                            MultiBufferOffset((selection.start.0 as i64 + offset_delta) as usize);
12049                        let adjusted_end =
12050                            MultiBufferOffset((adjusted_start.0 as i64 + new_len) as usize);
12051
12052                        new_selections.push(Selection {
12053                            id: selection.id,
12054                            start: adjusted_start,
12055                            end: adjusted_end,
12056                            reversed: selection.reversed,
12057                            goal: selection.goal,
12058                        });
12059
12060                        offset_delta += new_len - old_len;
12061                        (selection.start..selection.end, new_text.clone())
12062                    })
12063                    .collect();
12064                (edits, new_selections)
12065            } else {
12066                let mut all_rows: Vec<u32> = selections
12067                    .iter()
12068                    .map(|selection| buffer.offset_to_point(selection.start).row)
12069                    .collect();
12070                all_rows.sort_unstable();
12071                all_rows.dedup();
12072
12073                if all_rows.len() < 2 {
12074                    return;
12075                }
12076
12077                let line_ranges: Vec<Range<MultiBufferOffset>> = all_rows
12078                    .iter()
12079                    .map(|&row| {
12080                        let start = Point::new(row, 0);
12081                        let end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
12082                        buffer.point_to_offset(start)..buffer.point_to_offset(end)
12083                    })
12084                    .collect();
12085
12086                let mut line_texts: Vec<String> = line_ranges
12087                    .iter()
12088                    .map(|range| buffer.text_for_range(range.clone()).collect())
12089                    .collect();
12090
12091                if reverse {
12092                    line_texts.rotate_left(1);
12093                } else {
12094                    line_texts.rotate_right(1);
12095                }
12096
12097                let edits = line_ranges
12098                    .iter()
12099                    .zip(line_texts.iter())
12100                    .map(|(range, new_text)| (range.clone(), new_text.clone()))
12101                    .collect();
12102
12103                let num_rows = all_rows.len();
12104                let row_to_index: std::collections::HashMap<u32, usize> = all_rows
12105                    .iter()
12106                    .enumerate()
12107                    .map(|(i, &row)| (row, i))
12108                    .collect();
12109
12110                // Compute new line start offsets after rotation (handles CRLF)
12111                let newline_len = line_ranges[1].start.0 - line_ranges[0].end.0;
12112                let first_line_start = line_ranges[0].start.0;
12113                let mut new_line_starts: Vec<usize> = vec![first_line_start];
12114                for text in line_texts.iter().take(num_rows - 1) {
12115                    let prev_start = *new_line_starts.last().unwrap();
12116                    new_line_starts.push(prev_start + text.len() + newline_len);
12117                }
12118
12119                let new_selections = selections
12120                    .iter()
12121                    .map(|selection| {
12122                        let point = buffer.offset_to_point(selection.start);
12123                        let old_index = row_to_index[&point.row];
12124                        let new_index = if reverse {
12125                            (old_index + num_rows - 1) % num_rows
12126                        } else {
12127                            (old_index + 1) % num_rows
12128                        };
12129                        let new_offset =
12130                            MultiBufferOffset(new_line_starts[new_index] + point.column as usize);
12131                        Selection {
12132                            id: selection.id,
12133                            start: new_offset,
12134                            end: new_offset,
12135                            reversed: selection.reversed,
12136                            goal: selection.goal,
12137                        }
12138                    })
12139                    .collect();
12140
12141                (edits, new_selections)
12142            }
12143        };
12144
12145        self.transact(window, cx, |this, window, cx| {
12146            this.buffer.update(cx, |buffer, cx| {
12147                buffer.edit(edits, None, cx);
12148            });
12149            this.change_selections(Default::default(), window, cx, |s| {
12150                s.select(new_selections);
12151            });
12152        });
12153    }
12154
12155    fn manipulate_lines<M>(
12156        &mut self,
12157        window: &mut Window,
12158        cx: &mut Context<Self>,
12159        mut manipulate: M,
12160    ) where
12161        M: FnMut(&str) -> LineManipulationResult,
12162    {
12163        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12164
12165        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12166        let buffer = self.buffer.read(cx).snapshot(cx);
12167
12168        let mut edits = Vec::new();
12169
12170        let selections = self.selections.all::<Point>(&display_map);
12171        let mut selections = selections.iter().peekable();
12172        let mut contiguous_row_selections = Vec::new();
12173        let mut new_selections = Vec::new();
12174        let mut added_lines = 0;
12175        let mut removed_lines = 0;
12176
12177        while let Some(selection) = selections.next() {
12178            let (start_row, end_row) = consume_contiguous_rows(
12179                &mut contiguous_row_selections,
12180                selection,
12181                &display_map,
12182                &mut selections,
12183            );
12184
12185            let start_point = Point::new(start_row.0, 0);
12186            let end_point = Point::new(
12187                end_row.previous_row().0,
12188                buffer.line_len(end_row.previous_row()),
12189            );
12190            let text = buffer
12191                .text_for_range(start_point..end_point)
12192                .collect::<String>();
12193
12194            let LineManipulationResult {
12195                new_text,
12196                line_count_before,
12197                line_count_after,
12198            } = manipulate(&text);
12199
12200            edits.push((start_point..end_point, new_text));
12201
12202            // Selections must change based on added and removed line count
12203            let start_row =
12204                MultiBufferRow(start_point.row + added_lines as u32 - removed_lines as u32);
12205            let end_row = MultiBufferRow(start_row.0 + line_count_after.saturating_sub(1) as u32);
12206            new_selections.push(Selection {
12207                id: selection.id,
12208                start: start_row,
12209                end: end_row,
12210                goal: SelectionGoal::None,
12211                reversed: selection.reversed,
12212            });
12213
12214            if line_count_after > line_count_before {
12215                added_lines += line_count_after - line_count_before;
12216            } else if line_count_before > line_count_after {
12217                removed_lines += line_count_before - line_count_after;
12218            }
12219        }
12220
12221        self.transact(window, cx, |this, window, cx| {
12222            let buffer = this.buffer.update(cx, |buffer, cx| {
12223                buffer.edit(edits, None, cx);
12224                buffer.snapshot(cx)
12225            });
12226
12227            // Recalculate offsets on newly edited buffer
12228            let new_selections = new_selections
12229                .iter()
12230                .map(|s| {
12231                    let start_point = Point::new(s.start.0, 0);
12232                    let end_point = Point::new(s.end.0, buffer.line_len(s.end));
12233                    Selection {
12234                        id: s.id,
12235                        start: buffer.point_to_offset(start_point),
12236                        end: buffer.point_to_offset(end_point),
12237                        goal: s.goal,
12238                        reversed: s.reversed,
12239                    }
12240                })
12241                .collect();
12242
12243            this.change_selections(Default::default(), window, cx, |s| {
12244                s.select(new_selections);
12245            });
12246
12247            this.request_autoscroll(Autoscroll::fit(), cx);
12248        });
12249    }
12250
12251    fn manipulate_immutable_lines<Fn>(
12252        &mut self,
12253        window: &mut Window,
12254        cx: &mut Context<Self>,
12255        mut callback: Fn,
12256    ) where
12257        Fn: FnMut(&mut Vec<&str>),
12258    {
12259        self.manipulate_lines(window, cx, |text| {
12260            let mut lines: Vec<&str> = text.split('\n').collect();
12261            let line_count_before = lines.len();
12262
12263            callback(&mut lines);
12264
12265            LineManipulationResult {
12266                new_text: lines.join("\n"),
12267                line_count_before,
12268                line_count_after: lines.len(),
12269            }
12270        });
12271    }
12272
12273    fn manipulate_mutable_lines<Fn>(
12274        &mut self,
12275        window: &mut Window,
12276        cx: &mut Context<Self>,
12277        mut callback: Fn,
12278    ) where
12279        Fn: FnMut(&mut Vec<Cow<'_, str>>),
12280    {
12281        self.manipulate_lines(window, cx, |text| {
12282            let mut lines: Vec<Cow<str>> = text.split('\n').map(Cow::from).collect();
12283            let line_count_before = lines.len();
12284
12285            callback(&mut lines);
12286
12287            LineManipulationResult {
12288                new_text: lines.join("\n"),
12289                line_count_before,
12290                line_count_after: lines.len(),
12291            }
12292        });
12293    }
12294
12295    pub fn convert_indentation_to_spaces(
12296        &mut self,
12297        _: &ConvertIndentationToSpaces,
12298        window: &mut Window,
12299        cx: &mut Context<Self>,
12300    ) {
12301        let settings = self.buffer.read(cx).language_settings(cx);
12302        let tab_size = settings.tab_size.get() as usize;
12303
12304        self.manipulate_mutable_lines(window, cx, |lines| {
12305            // Allocates a reasonably sized scratch buffer once for the whole loop
12306            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12307            // Avoids recomputing spaces that could be inserted many times
12308            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12309                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12310                .collect();
12311
12312            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12313                let mut chars = line.as_ref().chars();
12314                let mut col = 0;
12315                let mut changed = false;
12316
12317                for ch in chars.by_ref() {
12318                    match ch {
12319                        ' ' => {
12320                            reindented_line.push(' ');
12321                            col += 1;
12322                        }
12323                        '\t' => {
12324                            // \t are converted to spaces depending on the current column
12325                            let spaces_len = tab_size - (col % tab_size);
12326                            reindented_line.extend(&space_cache[spaces_len - 1]);
12327                            col += spaces_len;
12328                            changed = true;
12329                        }
12330                        _ => {
12331                            // If we dont append before break, the character is consumed
12332                            reindented_line.push(ch);
12333                            break;
12334                        }
12335                    }
12336                }
12337
12338                if !changed {
12339                    reindented_line.clear();
12340                    continue;
12341                }
12342                // Append the rest of the line and replace old reference with new one
12343                reindented_line.extend(chars);
12344                *line = Cow::Owned(reindented_line.clone());
12345                reindented_line.clear();
12346            }
12347        });
12348    }
12349
12350    pub fn convert_indentation_to_tabs(
12351        &mut self,
12352        _: &ConvertIndentationToTabs,
12353        window: &mut Window,
12354        cx: &mut Context<Self>,
12355    ) {
12356        let settings = self.buffer.read(cx).language_settings(cx);
12357        let tab_size = settings.tab_size.get() as usize;
12358
12359        self.manipulate_mutable_lines(window, cx, |lines| {
12360            // Allocates a reasonably sized buffer once for the whole loop
12361            let mut reindented_line = String::with_capacity(MAX_LINE_LEN);
12362            // Avoids recomputing spaces that could be inserted many times
12363            let space_cache: Vec<Vec<char>> = (1..=tab_size)
12364                .map(|n| IndentSize::spaces(n as u32).chars().collect())
12365                .collect();
12366
12367            for line in lines.iter_mut().filter(|line| !line.is_empty()) {
12368                let mut chars = line.chars();
12369                let mut spaces_count = 0;
12370                let mut first_non_indent_char = None;
12371                let mut changed = false;
12372
12373                for ch in chars.by_ref() {
12374                    match ch {
12375                        ' ' => {
12376                            // Keep track of spaces. Append \t when we reach tab_size
12377                            spaces_count += 1;
12378                            changed = true;
12379                            if spaces_count == tab_size {
12380                                reindented_line.push('\t');
12381                                spaces_count = 0;
12382                            }
12383                        }
12384                        '\t' => {
12385                            reindented_line.push('\t');
12386                            spaces_count = 0;
12387                        }
12388                        _ => {
12389                            // Dont append it yet, we might have remaining spaces
12390                            first_non_indent_char = Some(ch);
12391                            break;
12392                        }
12393                    }
12394                }
12395
12396                if !changed {
12397                    reindented_line.clear();
12398                    continue;
12399                }
12400                // Remaining spaces that didn't make a full tab stop
12401                if spaces_count > 0 {
12402                    reindented_line.extend(&space_cache[spaces_count - 1]);
12403                }
12404                // If we consume an extra character that was not indentation, add it back
12405                if let Some(extra_char) = first_non_indent_char {
12406                    reindented_line.push(extra_char);
12407                }
12408                // Append the rest of the line and replace old reference with new one
12409                reindented_line.extend(chars);
12410                *line = Cow::Owned(reindented_line.clone());
12411                reindented_line.clear();
12412            }
12413        });
12414    }
12415
12416    pub fn convert_to_upper_case(
12417        &mut self,
12418        _: &ConvertToUpperCase,
12419        window: &mut Window,
12420        cx: &mut Context<Self>,
12421    ) {
12422        self.manipulate_text(window, cx, |text| text.to_uppercase())
12423    }
12424
12425    pub fn convert_to_lower_case(
12426        &mut self,
12427        _: &ConvertToLowerCase,
12428        window: &mut Window,
12429        cx: &mut Context<Self>,
12430    ) {
12431        self.manipulate_text(window, cx, |text| text.to_lowercase())
12432    }
12433
12434    pub fn convert_to_title_case(
12435        &mut self,
12436        _: &ConvertToTitleCase,
12437        window: &mut Window,
12438        cx: &mut Context<Self>,
12439    ) {
12440        self.manipulate_text(window, cx, |text| {
12441            Self::convert_text_case(text, Case::Title)
12442        })
12443    }
12444
12445    pub fn convert_to_snake_case(
12446        &mut self,
12447        _: &ConvertToSnakeCase,
12448        window: &mut Window,
12449        cx: &mut Context<Self>,
12450    ) {
12451        self.manipulate_text(window, cx, |text| {
12452            Self::convert_text_case(text, Case::Snake)
12453        })
12454    }
12455
12456    pub fn convert_to_kebab_case(
12457        &mut self,
12458        _: &ConvertToKebabCase,
12459        window: &mut Window,
12460        cx: &mut Context<Self>,
12461    ) {
12462        self.manipulate_text(window, cx, |text| {
12463            Self::convert_text_case(text, Case::Kebab)
12464        })
12465    }
12466
12467    pub fn convert_to_upper_camel_case(
12468        &mut self,
12469        _: &ConvertToUpperCamelCase,
12470        window: &mut Window,
12471        cx: &mut Context<Self>,
12472    ) {
12473        self.manipulate_text(window, cx, |text| {
12474            Self::convert_text_case(text, Case::UpperCamel)
12475        })
12476    }
12477
12478    pub fn convert_to_lower_camel_case(
12479        &mut self,
12480        _: &ConvertToLowerCamelCase,
12481        window: &mut Window,
12482        cx: &mut Context<Self>,
12483    ) {
12484        self.manipulate_text(window, cx, |text| {
12485            Self::convert_text_case(text, Case::Camel)
12486        })
12487    }
12488
12489    pub fn convert_to_opposite_case(
12490        &mut self,
12491        _: &ConvertToOppositeCase,
12492        window: &mut Window,
12493        cx: &mut Context<Self>,
12494    ) {
12495        self.manipulate_text(window, cx, |text| {
12496            text.chars()
12497                .fold(String::with_capacity(text.len()), |mut t, c| {
12498                    if c.is_uppercase() {
12499                        t.extend(c.to_lowercase());
12500                    } else {
12501                        t.extend(c.to_uppercase());
12502                    }
12503                    t
12504                })
12505        })
12506    }
12507
12508    pub fn convert_to_sentence_case(
12509        &mut self,
12510        _: &ConvertToSentenceCase,
12511        window: &mut Window,
12512        cx: &mut Context<Self>,
12513    ) {
12514        self.manipulate_text(window, cx, |text| {
12515            Self::convert_text_case(text, Case::Sentence)
12516        })
12517    }
12518
12519    pub fn toggle_case(&mut self, _: &ToggleCase, window: &mut Window, cx: &mut Context<Self>) {
12520        self.manipulate_text(window, cx, |text| {
12521            let has_upper_case_characters = text.chars().any(|c| c.is_uppercase());
12522            if has_upper_case_characters {
12523                text.to_lowercase()
12524            } else {
12525                text.to_uppercase()
12526            }
12527        })
12528    }
12529
12530    pub fn convert_to_rot13(
12531        &mut self,
12532        _: &ConvertToRot13,
12533        window: &mut Window,
12534        cx: &mut Context<Self>,
12535    ) {
12536        self.manipulate_text(window, cx, |text| {
12537            text.chars()
12538                .map(|c| match c {
12539                    'A'..='M' | 'a'..='m' => ((c as u8) + 13) as char,
12540                    'N'..='Z' | 'n'..='z' => ((c as u8) - 13) as char,
12541                    _ => c,
12542                })
12543                .collect()
12544        })
12545    }
12546
12547    fn convert_text_case(text: &str, case: Case) -> String {
12548        text.lines()
12549            .map(|line| {
12550                let trimmed_start = line.trim_start();
12551                let leading = &line[..line.len() - trimmed_start.len()];
12552                let trimmed = trimmed_start.trim_end();
12553                let trailing = &trimmed_start[trimmed.len()..];
12554                format!("{}{}{}", leading, trimmed.to_case(case), trailing)
12555            })
12556            .join("\n")
12557    }
12558
12559    pub fn convert_to_rot47(
12560        &mut self,
12561        _: &ConvertToRot47,
12562        window: &mut Window,
12563        cx: &mut Context<Self>,
12564    ) {
12565        self.manipulate_text(window, cx, |text| {
12566            text.chars()
12567                .map(|c| {
12568                    let code_point = c as u32;
12569                    if code_point >= 33 && code_point <= 126 {
12570                        return char::from_u32(33 + ((code_point + 14) % 94)).unwrap();
12571                    }
12572                    c
12573                })
12574                .collect()
12575        })
12576    }
12577
12578    fn manipulate_text<Fn>(&mut self, window: &mut Window, cx: &mut Context<Self>, mut callback: Fn)
12579    where
12580        Fn: FnMut(&str) -> String,
12581    {
12582        let buffer = self.buffer.read(cx).snapshot(cx);
12583
12584        let mut new_selections = Vec::new();
12585        let mut edits = Vec::new();
12586        let mut selection_adjustment = 0isize;
12587
12588        for selection in self.selections.all_adjusted(&self.display_snapshot(cx)) {
12589            let selection_is_empty = selection.is_empty();
12590
12591            let (start, end) = if selection_is_empty {
12592                let (word_range, _) = buffer.surrounding_word(selection.start, None);
12593                (word_range.start, word_range.end)
12594            } else {
12595                (
12596                    buffer.point_to_offset(selection.start),
12597                    buffer.point_to_offset(selection.end),
12598                )
12599            };
12600
12601            let text = buffer.text_for_range(start..end).collect::<String>();
12602            let old_length = text.len() as isize;
12603            let text = callback(&text);
12604
12605            new_selections.push(Selection {
12606                start: MultiBufferOffset((start.0 as isize - selection_adjustment) as usize),
12607                end: MultiBufferOffset(
12608                    ((start.0 + text.len()) as isize - selection_adjustment) as usize,
12609                ),
12610                goal: SelectionGoal::None,
12611                id: selection.id,
12612                reversed: selection.reversed,
12613            });
12614
12615            selection_adjustment += old_length - text.len() as isize;
12616
12617            edits.push((start..end, text));
12618        }
12619
12620        self.transact(window, cx, |this, window, cx| {
12621            this.buffer.update(cx, |buffer, cx| {
12622                buffer.edit(edits, None, cx);
12623            });
12624
12625            this.change_selections(Default::default(), window, cx, |s| {
12626                s.select(new_selections);
12627            });
12628
12629            this.request_autoscroll(Autoscroll::fit(), cx);
12630        });
12631    }
12632
12633    pub fn move_selection_on_drop(
12634        &mut self,
12635        selection: &Selection<Anchor>,
12636        target: DisplayPoint,
12637        is_cut: bool,
12638        window: &mut Window,
12639        cx: &mut Context<Self>,
12640    ) {
12641        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12642        let buffer = display_map.buffer_snapshot();
12643        let mut edits = Vec::new();
12644        let insert_point = display_map
12645            .clip_point(target, Bias::Left)
12646            .to_point(&display_map);
12647        let text = buffer
12648            .text_for_range(selection.start..selection.end)
12649            .collect::<String>();
12650        if is_cut {
12651            edits.push(((selection.start..selection.end), String::new()));
12652        }
12653        let insert_anchor = buffer.anchor_before(insert_point);
12654        edits.push(((insert_anchor..insert_anchor), text));
12655        let last_edit_start = insert_anchor.bias_left(buffer);
12656        let last_edit_end = insert_anchor.bias_right(buffer);
12657        self.transact(window, cx, |this, window, cx| {
12658            this.buffer.update(cx, |buffer, cx| {
12659                buffer.edit(edits, None, cx);
12660            });
12661            this.change_selections(Default::default(), window, cx, |s| {
12662                s.select_anchor_ranges([last_edit_start..last_edit_end]);
12663            });
12664        });
12665    }
12666
12667    pub fn clear_selection_drag_state(&mut self) {
12668        self.selection_drag_state = SelectionDragState::None;
12669    }
12670
12671    pub fn duplicate(
12672        &mut self,
12673        upwards: bool,
12674        whole_lines: bool,
12675        window: &mut Window,
12676        cx: &mut Context<Self>,
12677    ) {
12678        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12679
12680        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12681        let buffer = display_map.buffer_snapshot();
12682        let selections = self.selections.all::<Point>(&display_map);
12683
12684        let mut edits = Vec::new();
12685        let mut selections_iter = selections.iter().peekable();
12686        while let Some(selection) = selections_iter.next() {
12687            let mut rows = selection.spanned_rows(false, &display_map);
12688            // duplicate line-wise
12689            if whole_lines || selection.start == selection.end {
12690                // Avoid duplicating the same lines twice.
12691                while let Some(next_selection) = selections_iter.peek() {
12692                    let next_rows = next_selection.spanned_rows(false, &display_map);
12693                    if next_rows.start < rows.end {
12694                        rows.end = next_rows.end;
12695                        selections_iter.next().unwrap();
12696                    } else {
12697                        break;
12698                    }
12699                }
12700
12701                // Copy the text from the selected row region and splice it either at the start
12702                // or end of the region.
12703                let start = Point::new(rows.start.0, 0);
12704                let end = Point::new(
12705                    rows.end.previous_row().0,
12706                    buffer.line_len(rows.end.previous_row()),
12707                );
12708
12709                let mut text = buffer.text_for_range(start..end).collect::<String>();
12710
12711                let insert_location = if upwards {
12712                    // When duplicating upward, we need to insert before the current line.
12713                    // If we're on the last line and it doesn't end with a newline,
12714                    // we need to add a newline before the duplicated content.
12715                    let needs_leading_newline = rows.end.0 >= buffer.max_point().row
12716                        && buffer.max_point().column > 0
12717                        && !text.ends_with('\n');
12718
12719                    if needs_leading_newline {
12720                        text.insert(0, '\n');
12721                        end
12722                    } else {
12723                        text.push('\n');
12724                        Point::new(rows.start.0, 0)
12725                    }
12726                } else {
12727                    text.push('\n');
12728                    start
12729                };
12730                edits.push((insert_location..insert_location, text));
12731            } else {
12732                // duplicate character-wise
12733                let start = selection.start;
12734                let end = selection.end;
12735                let text = buffer.text_for_range(start..end).collect::<String>();
12736                edits.push((selection.end..selection.end, text));
12737            }
12738        }
12739
12740        self.transact(window, cx, |this, window, cx| {
12741            this.buffer.update(cx, |buffer, cx| {
12742                buffer.edit(edits, None, cx);
12743            });
12744
12745            // When duplicating upward with whole lines, move the cursor to the duplicated line
12746            if upwards && whole_lines {
12747                let display_map = this.display_map.update(cx, |map, cx| map.snapshot(cx));
12748
12749                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
12750                    let mut new_ranges = Vec::new();
12751                    let selections = s.all::<Point>(&display_map);
12752                    let mut selections_iter = selections.iter().peekable();
12753
12754                    while let Some(first_selection) = selections_iter.next() {
12755                        // Group contiguous selections together to find the total row span
12756                        let mut group_selections = vec![first_selection];
12757                        let mut rows = first_selection.spanned_rows(false, &display_map);
12758
12759                        while let Some(next_selection) = selections_iter.peek() {
12760                            let next_rows = next_selection.spanned_rows(false, &display_map);
12761                            if next_rows.start < rows.end {
12762                                rows.end = next_rows.end;
12763                                group_selections.push(selections_iter.next().unwrap());
12764                            } else {
12765                                break;
12766                            }
12767                        }
12768
12769                        let row_count = rows.end.0 - rows.start.0;
12770
12771                        // Move all selections in this group up by the total number of duplicated rows
12772                        for selection in group_selections {
12773                            let new_start = Point::new(
12774                                selection.start.row.saturating_sub(row_count),
12775                                selection.start.column,
12776                            );
12777
12778                            let new_end = Point::new(
12779                                selection.end.row.saturating_sub(row_count),
12780                                selection.end.column,
12781                            );
12782
12783                            new_ranges.push(new_start..new_end);
12784                        }
12785                    }
12786
12787                    s.select_ranges(new_ranges);
12788                });
12789            }
12790
12791            this.request_autoscroll(Autoscroll::fit(), cx);
12792        });
12793    }
12794
12795    pub fn duplicate_line_up(
12796        &mut self,
12797        _: &DuplicateLineUp,
12798        window: &mut Window,
12799        cx: &mut Context<Self>,
12800    ) {
12801        self.duplicate(true, true, window, cx);
12802    }
12803
12804    pub fn duplicate_line_down(
12805        &mut self,
12806        _: &DuplicateLineDown,
12807        window: &mut Window,
12808        cx: &mut Context<Self>,
12809    ) {
12810        self.duplicate(false, true, window, cx);
12811    }
12812
12813    pub fn duplicate_selection(
12814        &mut self,
12815        _: &DuplicateSelection,
12816        window: &mut Window,
12817        cx: &mut Context<Self>,
12818    ) {
12819        self.duplicate(false, false, window, cx);
12820    }
12821
12822    pub fn move_line_up(&mut self, _: &MoveLineUp, window: &mut Window, cx: &mut Context<Self>) {
12823        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12824        if self.mode.is_single_line() {
12825            cx.propagate();
12826            return;
12827        }
12828
12829        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12830        let buffer = self.buffer.read(cx).snapshot(cx);
12831
12832        let mut edits = Vec::new();
12833        let mut unfold_ranges = Vec::new();
12834        let mut refold_creases = Vec::new();
12835
12836        let selections = self.selections.all::<Point>(&display_map);
12837        let mut selections = selections.iter().peekable();
12838        let mut contiguous_row_selections = Vec::new();
12839        let mut new_selections = Vec::new();
12840
12841        while let Some(selection) = selections.next() {
12842            // Find all the selections that span a contiguous row range
12843            let (start_row, end_row) = consume_contiguous_rows(
12844                &mut contiguous_row_selections,
12845                selection,
12846                &display_map,
12847                &mut selections,
12848            );
12849
12850            // Move the text spanned by the row range to be before the line preceding the row range
12851            if start_row.0 > 0 {
12852                let range_to_move = Point::new(
12853                    start_row.previous_row().0,
12854                    buffer.line_len(start_row.previous_row()),
12855                )
12856                    ..Point::new(
12857                        end_row.previous_row().0,
12858                        buffer.line_len(end_row.previous_row()),
12859                    );
12860                let insertion_point = display_map
12861                    .prev_line_boundary(Point::new(start_row.previous_row().0, 0))
12862                    .0;
12863
12864                // Don't move lines across excerpts
12865                if buffer
12866                    .excerpt_containing(insertion_point..range_to_move.end)
12867                    .is_some()
12868                {
12869                    let text = buffer
12870                        .text_for_range(range_to_move.clone())
12871                        .flat_map(|s| s.chars())
12872                        .skip(1)
12873                        .chain(['\n'])
12874                        .collect::<String>();
12875
12876                    edits.push((
12877                        buffer.anchor_after(range_to_move.start)
12878                            ..buffer.anchor_before(range_to_move.end),
12879                        String::new(),
12880                    ));
12881                    let insertion_anchor = buffer.anchor_after(insertion_point);
12882                    edits.push((insertion_anchor..insertion_anchor, text));
12883
12884                    let row_delta = range_to_move.start.row - insertion_point.row + 1;
12885
12886                    // Move selections up
12887                    new_selections.extend(contiguous_row_selections.drain(..).map(
12888                        |mut selection| {
12889                            selection.start.row -= row_delta;
12890                            selection.end.row -= row_delta;
12891                            selection
12892                        },
12893                    ));
12894
12895                    // Move folds up
12896                    unfold_ranges.push(range_to_move.clone());
12897                    for fold in display_map.folds_in_range(
12898                        buffer.anchor_before(range_to_move.start)
12899                            ..buffer.anchor_after(range_to_move.end),
12900                    ) {
12901                        let mut start = fold.range.start.to_point(&buffer);
12902                        let mut end = fold.range.end.to_point(&buffer);
12903                        start.row -= row_delta;
12904                        end.row -= row_delta;
12905                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
12906                    }
12907                }
12908            }
12909
12910            // If we didn't move line(s), preserve the existing selections
12911            new_selections.append(&mut contiguous_row_selections);
12912        }
12913
12914        self.transact(window, cx, |this, window, cx| {
12915            this.unfold_ranges(&unfold_ranges, true, true, cx);
12916            this.buffer.update(cx, |buffer, cx| {
12917                for (range, text) in edits {
12918                    buffer.edit([(range, text)], None, cx);
12919                }
12920            });
12921            this.fold_creases(refold_creases, true, window, cx);
12922            this.change_selections(Default::default(), window, cx, |s| {
12923                s.select(new_selections);
12924            })
12925        });
12926    }
12927
12928    pub fn move_line_down(
12929        &mut self,
12930        _: &MoveLineDown,
12931        window: &mut Window,
12932        cx: &mut Context<Self>,
12933    ) {
12934        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
12935        if self.mode.is_single_line() {
12936            cx.propagate();
12937            return;
12938        }
12939
12940        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
12941        let buffer = self.buffer.read(cx).snapshot(cx);
12942
12943        let mut edits = Vec::new();
12944        let mut unfold_ranges = Vec::new();
12945        let mut refold_creases = Vec::new();
12946
12947        let selections = self.selections.all::<Point>(&display_map);
12948        let mut selections = selections.iter().peekable();
12949        let mut contiguous_row_selections = Vec::new();
12950        let mut new_selections = Vec::new();
12951
12952        while let Some(selection) = selections.next() {
12953            // Find all the selections that span a contiguous row range
12954            let (start_row, end_row) = consume_contiguous_rows(
12955                &mut contiguous_row_selections,
12956                selection,
12957                &display_map,
12958                &mut selections,
12959            );
12960
12961            // Move the text spanned by the row range to be after the last line of the row range
12962            if end_row.0 <= buffer.max_point().row {
12963                let range_to_move =
12964                    MultiBufferPoint::new(start_row.0, 0)..MultiBufferPoint::new(end_row.0, 0);
12965                let insertion_point = display_map
12966                    .next_line_boundary(MultiBufferPoint::new(end_row.0, 0))
12967                    .0;
12968
12969                // Don't move lines across excerpt boundaries
12970                if buffer
12971                    .excerpt_containing(range_to_move.start..insertion_point)
12972                    .is_some()
12973                {
12974                    let mut text = String::from("\n");
12975                    text.extend(buffer.text_for_range(range_to_move.clone()));
12976                    text.pop(); // Drop trailing newline
12977                    edits.push((
12978                        buffer.anchor_after(range_to_move.start)
12979                            ..buffer.anchor_before(range_to_move.end),
12980                        String::new(),
12981                    ));
12982                    let insertion_anchor = buffer.anchor_after(insertion_point);
12983                    edits.push((insertion_anchor..insertion_anchor, text));
12984
12985                    let row_delta = insertion_point.row - range_to_move.end.row + 1;
12986
12987                    // Move selections down
12988                    new_selections.extend(contiguous_row_selections.drain(..).map(
12989                        |mut selection| {
12990                            selection.start.row += row_delta;
12991                            selection.end.row += row_delta;
12992                            selection
12993                        },
12994                    ));
12995
12996                    // Move folds down
12997                    unfold_ranges.push(range_to_move.clone());
12998                    for fold in display_map.folds_in_range(
12999                        buffer.anchor_before(range_to_move.start)
13000                            ..buffer.anchor_after(range_to_move.end),
13001                    ) {
13002                        let mut start = fold.range.start.to_point(&buffer);
13003                        let mut end = fold.range.end.to_point(&buffer);
13004                        start.row += row_delta;
13005                        end.row += row_delta;
13006                        refold_creases.push(Crease::simple(start..end, fold.placeholder.clone()));
13007                    }
13008                }
13009            }
13010
13011            // If we didn't move line(s), preserve the existing selections
13012            new_selections.append(&mut contiguous_row_selections);
13013        }
13014
13015        self.transact(window, cx, |this, window, cx| {
13016            this.unfold_ranges(&unfold_ranges, true, true, cx);
13017            this.buffer.update(cx, |buffer, cx| {
13018                for (range, text) in edits {
13019                    buffer.edit([(range, text)], None, cx);
13020                }
13021            });
13022            this.fold_creases(refold_creases, true, window, cx);
13023            this.change_selections(Default::default(), window, cx, |s| s.select(new_selections));
13024        });
13025    }
13026
13027    pub fn transpose(&mut self, _: &Transpose, window: &mut Window, cx: &mut Context<Self>) {
13028        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13029        let text_layout_details = &self.text_layout_details(window, cx);
13030        self.transact(window, cx, |this, window, cx| {
13031            let edits = this.change_selections(Default::default(), window, cx, |s| {
13032                let mut edits: Vec<(Range<MultiBufferOffset>, String)> = Default::default();
13033                s.move_with(&mut |display_map, selection| {
13034                    if !selection.is_empty() {
13035                        return;
13036                    }
13037
13038                    let mut head = selection.head();
13039                    let mut transpose_offset = head.to_offset(display_map, Bias::Right);
13040                    if head.column() == display_map.line_len(head.row()) {
13041                        transpose_offset = display_map
13042                            .buffer_snapshot()
13043                            .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13044                    }
13045
13046                    if transpose_offset == MultiBufferOffset(0) {
13047                        return;
13048                    }
13049
13050                    *head.column_mut() += 1;
13051                    head = display_map.clip_point(head, Bias::Right);
13052                    let goal = SelectionGoal::HorizontalPosition(
13053                        display_map
13054                            .x_for_display_point(head, text_layout_details)
13055                            .into(),
13056                    );
13057                    selection.collapse_to(head, goal);
13058
13059                    let transpose_start = display_map
13060                        .buffer_snapshot()
13061                        .clip_offset(transpose_offset.saturating_sub_usize(1), Bias::Left);
13062                    if edits.last().is_none_or(|e| e.0.end <= transpose_start) {
13063                        let transpose_end = display_map
13064                            .buffer_snapshot()
13065                            .clip_offset(transpose_offset + 1usize, Bias::Right);
13066                        if let Some(ch) = display_map
13067                            .buffer_snapshot()
13068                            .chars_at(transpose_start)
13069                            .next()
13070                        {
13071                            edits.push((transpose_start..transpose_offset, String::new()));
13072                            edits.push((transpose_end..transpose_end, ch.to_string()));
13073                        }
13074                    }
13075                });
13076                edits
13077            });
13078            this.buffer
13079                .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13080            let selections = this
13081                .selections
13082                .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13083            this.change_selections(Default::default(), window, cx, |s| {
13084                s.select(selections);
13085            });
13086        });
13087    }
13088
13089    pub fn rewrap(&mut self, _: &Rewrap, _: &mut Window, cx: &mut Context<Self>) {
13090        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13091        if self.mode.is_single_line() {
13092            cx.propagate();
13093            return;
13094        }
13095
13096        self.rewrap_impl(RewrapOptions::default(), cx)
13097    }
13098
13099    pub fn rewrap_impl(&mut self, options: RewrapOptions, cx: &mut Context<Self>) {
13100        let buffer = self.buffer.read(cx).snapshot(cx);
13101        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13102
13103        #[derive(Clone, Debug, PartialEq)]
13104        enum CommentFormat {
13105            /// single line comment, with prefix for line
13106            Line(String),
13107            /// single line within a block comment, with prefix for line
13108            BlockLine(String),
13109            /// a single line of a block comment that includes the initial delimiter
13110            BlockCommentWithStart(BlockCommentConfig),
13111            /// a single line of a block comment that includes the ending delimiter
13112            BlockCommentWithEnd(BlockCommentConfig),
13113        }
13114
13115        // Split selections to respect paragraph, indent, and comment prefix boundaries.
13116        let wrap_ranges = selections.into_iter().flat_map(|selection| {
13117            let mut non_blank_rows_iter = (selection.start.row..=selection.end.row)
13118                .filter(|row| !buffer.is_line_blank(MultiBufferRow(*row)))
13119                .peekable();
13120
13121            let first_row = if let Some(&row) = non_blank_rows_iter.peek() {
13122                row
13123            } else {
13124                return Vec::new();
13125            };
13126
13127            let language_settings = buffer.language_settings_at(selection.head(), cx);
13128            let language_scope = buffer.language_scope_at(selection.head());
13129
13130            let indent_and_prefix_for_row =
13131                |row: u32| -> (IndentSize, Option<CommentFormat>, Option<String>) {
13132                    let indent = buffer.indent_size_for_line(MultiBufferRow(row));
13133                    let (comment_prefix, rewrap_prefix) = if let Some(language_scope) =
13134                        &language_scope
13135                    {
13136                        let indent_end = Point::new(row, indent.len);
13137                        let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
13138                        let line_text_after_indent = buffer
13139                            .text_for_range(indent_end..line_end)
13140                            .collect::<String>();
13141
13142                        let is_within_comment_override = buffer
13143                            .language_scope_at(indent_end)
13144                            .is_some_and(|scope| scope.override_name() == Some("comment"));
13145                        let comment_delimiters = if is_within_comment_override {
13146                            // we are within a comment syntax node, but we don't
13147                            // yet know what kind of comment: block, doc or line
13148                            match (
13149                                language_scope.documentation_comment(),
13150                                language_scope.block_comment(),
13151                            ) {
13152                                (Some(config), _) | (_, Some(config))
13153                                    if buffer.contains_str_at(indent_end, &config.start) =>
13154                                {
13155                                    Some(CommentFormat::BlockCommentWithStart(config.clone()))
13156                                }
13157                                (Some(config), _) | (_, Some(config))
13158                                    if line_text_after_indent.ends_with(config.end.as_ref()) =>
13159                                {
13160                                    Some(CommentFormat::BlockCommentWithEnd(config.clone()))
13161                                }
13162                                (Some(config), _) | (_, Some(config))
13163                                    if buffer.contains_str_at(indent_end, &config.prefix) =>
13164                                {
13165                                    Some(CommentFormat::BlockLine(config.prefix.to_string()))
13166                                }
13167                                (_, _) => language_scope
13168                                    .line_comment_prefixes()
13169                                    .iter()
13170                                    .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13171                                    .map(|prefix| CommentFormat::Line(prefix.to_string())),
13172                            }
13173                        } else {
13174                            // we not in an overridden comment node, but we may
13175                            // be within a non-overridden line comment node
13176                            language_scope
13177                                .line_comment_prefixes()
13178                                .iter()
13179                                .find(|prefix| buffer.contains_str_at(indent_end, prefix))
13180                                .map(|prefix| CommentFormat::Line(prefix.to_string()))
13181                        };
13182
13183                        let rewrap_prefix = language_scope
13184                            .rewrap_prefixes()
13185                            .iter()
13186                            .find_map(|prefix_regex| {
13187                                prefix_regex.find(&line_text_after_indent).map(|mat| {
13188                                    if mat.start() == 0 {
13189                                        Some(mat.as_str().to_string())
13190                                    } else {
13191                                        None
13192                                    }
13193                                })
13194                            })
13195                            .flatten();
13196                        (comment_delimiters, rewrap_prefix)
13197                    } else {
13198                        (None, None)
13199                    };
13200                    (indent, comment_prefix, rewrap_prefix)
13201                };
13202
13203            let mut ranges = Vec::new();
13204            let from_empty_selection = selection.is_empty();
13205
13206            let mut current_range_start = first_row;
13207            let mut prev_row = first_row;
13208            let (
13209                mut current_range_indent,
13210                mut current_range_comment_delimiters,
13211                mut current_range_rewrap_prefix,
13212            ) = indent_and_prefix_for_row(first_row);
13213
13214            for row in non_blank_rows_iter.skip(1) {
13215                let has_paragraph_break = row > prev_row + 1;
13216
13217                let (row_indent, row_comment_delimiters, row_rewrap_prefix) =
13218                    indent_and_prefix_for_row(row);
13219
13220                let has_indent_change = row_indent != current_range_indent;
13221                let has_comment_change = row_comment_delimiters != current_range_comment_delimiters;
13222
13223                let has_boundary_change = has_comment_change
13224                    || row_rewrap_prefix.is_some()
13225                    || (has_indent_change && current_range_comment_delimiters.is_some());
13226
13227                if has_paragraph_break || has_boundary_change {
13228                    ranges.push((
13229                        language_settings.clone(),
13230                        Point::new(current_range_start, 0)
13231                            ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13232                        current_range_indent,
13233                        current_range_comment_delimiters.clone(),
13234                        current_range_rewrap_prefix.clone(),
13235                        from_empty_selection,
13236                    ));
13237                    current_range_start = row;
13238                    current_range_indent = row_indent;
13239                    current_range_comment_delimiters = row_comment_delimiters;
13240                    current_range_rewrap_prefix = row_rewrap_prefix;
13241                }
13242                prev_row = row;
13243            }
13244
13245            ranges.push((
13246                language_settings.clone(),
13247                Point::new(current_range_start, 0)
13248                    ..Point::new(prev_row, buffer.line_len(MultiBufferRow(prev_row))),
13249                current_range_indent,
13250                current_range_comment_delimiters,
13251                current_range_rewrap_prefix,
13252                from_empty_selection,
13253            ));
13254
13255            ranges
13256        });
13257
13258        let mut edits = Vec::new();
13259        let mut rewrapped_row_ranges = Vec::<RangeInclusive<u32>>::new();
13260
13261        for (
13262            language_settings,
13263            wrap_range,
13264            mut indent_size,
13265            comment_prefix,
13266            rewrap_prefix,
13267            from_empty_selection,
13268        ) in wrap_ranges
13269        {
13270            let mut start_row = wrap_range.start.row;
13271            let mut end_row = wrap_range.end.row;
13272
13273            // Skip selections that overlap with a range that has already been rewrapped.
13274            let selection_range = start_row..end_row;
13275            if rewrapped_row_ranges
13276                .iter()
13277                .any(|range| range.overlaps(&selection_range))
13278            {
13279                continue;
13280            }
13281
13282            let tab_size = language_settings.tab_size;
13283
13284            let (line_prefix, inside_comment) = match &comment_prefix {
13285                Some(CommentFormat::Line(prefix) | CommentFormat::BlockLine(prefix)) => {
13286                    (Some(prefix.as_str()), true)
13287                }
13288                Some(CommentFormat::BlockCommentWithEnd(BlockCommentConfig { prefix, .. })) => {
13289                    (Some(prefix.as_ref()), true)
13290                }
13291                Some(CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13292                    start: _,
13293                    end: _,
13294                    prefix,
13295                    tab_size,
13296                })) => {
13297                    indent_size.len += tab_size;
13298                    (Some(prefix.as_ref()), true)
13299                }
13300                None => (None, false),
13301            };
13302            let indent_prefix = indent_size.chars().collect::<String>();
13303            let line_prefix = format!("{indent_prefix}{}", line_prefix.unwrap_or(""));
13304
13305            let allow_rewrap_based_on_language = match language_settings.allow_rewrap {
13306                RewrapBehavior::InComments => inside_comment,
13307                RewrapBehavior::InSelections => !wrap_range.is_empty(),
13308                RewrapBehavior::Anywhere => true,
13309            };
13310
13311            let should_rewrap = options.override_language_settings
13312                || allow_rewrap_based_on_language
13313                || self.hard_wrap.is_some();
13314            if !should_rewrap {
13315                continue;
13316            }
13317
13318            if from_empty_selection {
13319                'expand_upwards: while start_row > 0 {
13320                    let prev_row = start_row - 1;
13321                    if buffer.contains_str_at(Point::new(prev_row, 0), &line_prefix)
13322                        && buffer.line_len(MultiBufferRow(prev_row)) as usize > line_prefix.len()
13323                        && !buffer.is_line_blank(MultiBufferRow(prev_row))
13324                    {
13325                        start_row = prev_row;
13326                    } else {
13327                        break 'expand_upwards;
13328                    }
13329                }
13330
13331                'expand_downwards: while end_row < buffer.max_point().row {
13332                    let next_row = end_row + 1;
13333                    if buffer.contains_str_at(Point::new(next_row, 0), &line_prefix)
13334                        && buffer.line_len(MultiBufferRow(next_row)) as usize > line_prefix.len()
13335                        && !buffer.is_line_blank(MultiBufferRow(next_row))
13336                    {
13337                        end_row = next_row;
13338                    } else {
13339                        break 'expand_downwards;
13340                    }
13341                }
13342            }
13343
13344            let start = Point::new(start_row, 0);
13345            let start_offset = ToOffset::to_offset(&start, &buffer);
13346            let end = Point::new(end_row, buffer.line_len(MultiBufferRow(end_row)));
13347            let selection_text = buffer.text_for_range(start..end).collect::<String>();
13348            let mut first_line_delimiter = None;
13349            let mut last_line_delimiter = None;
13350            let Some(lines_without_prefixes) = selection_text
13351                .lines()
13352                .enumerate()
13353                .map(|(ix, line)| {
13354                    let line_trimmed = line.trim_start();
13355                    if rewrap_prefix.is_some() && ix > 0 {
13356                        Ok(line_trimmed)
13357                    } else if let Some(
13358                        CommentFormat::BlockCommentWithStart(BlockCommentConfig {
13359                            start,
13360                            prefix,
13361                            end,
13362                            tab_size,
13363                        })
13364                        | CommentFormat::BlockCommentWithEnd(BlockCommentConfig {
13365                            start,
13366                            prefix,
13367                            end,
13368                            tab_size,
13369                        }),
13370                    ) = &comment_prefix
13371                    {
13372                        let line_trimmed = line_trimmed
13373                            .strip_prefix(start.as_ref())
13374                            .map(|s| {
13375                                let mut indent_size = indent_size;
13376                                indent_size.len -= tab_size;
13377                                let indent_prefix: String = indent_size.chars().collect();
13378                                first_line_delimiter = Some((indent_prefix, start));
13379                                s.trim_start()
13380                            })
13381                            .unwrap_or(line_trimmed);
13382                        let line_trimmed = line_trimmed
13383                            .strip_suffix(end.as_ref())
13384                            .map(|s| {
13385                                last_line_delimiter = Some(end);
13386                                s.trim_end()
13387                            })
13388                            .unwrap_or(line_trimmed);
13389                        let line_trimmed = line_trimmed
13390                            .strip_prefix(prefix.as_ref())
13391                            .unwrap_or(line_trimmed);
13392                        Ok(line_trimmed)
13393                    } else if let Some(CommentFormat::BlockLine(prefix)) = &comment_prefix {
13394                        line_trimmed.strip_prefix(prefix).with_context(|| {
13395                            format!("line did not start with prefix {prefix:?}: {line:?}")
13396                        })
13397                    } else {
13398                        line_trimmed
13399                            .strip_prefix(&line_prefix.trim_start())
13400                            .with_context(|| {
13401                                format!("line did not start with prefix {line_prefix:?}: {line:?}")
13402                            })
13403                    }
13404                })
13405                .collect::<Result<Vec<_>, _>>()
13406                .log_err()
13407            else {
13408                continue;
13409            };
13410
13411            let wrap_column = self.hard_wrap.unwrap_or_else(|| {
13412                buffer
13413                    .language_settings_at(Point::new(start_row, 0), cx)
13414                    .preferred_line_length as usize
13415            });
13416
13417            let subsequent_lines_prefix = if let Some(rewrap_prefix_str) = &rewrap_prefix {
13418                format!("{}{}", indent_prefix, " ".repeat(rewrap_prefix_str.len()))
13419            } else {
13420                line_prefix.clone()
13421            };
13422
13423            let wrapped_text = {
13424                let mut wrapped_text = wrap_with_prefix(
13425                    line_prefix,
13426                    subsequent_lines_prefix,
13427                    lines_without_prefixes.join("\n"),
13428                    wrap_column,
13429                    tab_size,
13430                    options.preserve_existing_whitespace,
13431                );
13432
13433                if let Some((indent, delimiter)) = first_line_delimiter {
13434                    wrapped_text = format!("{indent}{delimiter}\n{wrapped_text}");
13435                }
13436                if let Some(last_line) = last_line_delimiter {
13437                    wrapped_text = format!("{wrapped_text}\n{indent_prefix}{last_line}");
13438                }
13439
13440                wrapped_text
13441            };
13442
13443            // TODO: should always use char-based diff while still supporting cursor behavior that
13444            // matches vim.
13445            let mut diff_options = DiffOptions::default();
13446            if options.override_language_settings {
13447                diff_options.max_word_diff_len = 0;
13448                diff_options.max_word_diff_line_count = 0;
13449            } else {
13450                diff_options.max_word_diff_len = usize::MAX;
13451                diff_options.max_word_diff_line_count = usize::MAX;
13452            }
13453
13454            for (old_range, new_text) in
13455                text_diff_with_options(&selection_text, &wrapped_text, diff_options)
13456            {
13457                let edit_start = buffer.anchor_after(start_offset + old_range.start);
13458                let edit_end = buffer.anchor_after(start_offset + old_range.end);
13459                edits.push((edit_start..edit_end, new_text));
13460            }
13461
13462            rewrapped_row_ranges.push(start_row..=end_row);
13463        }
13464
13465        self.buffer
13466            .update(cx, |buffer, cx| buffer.edit(edits, None, cx));
13467    }
13468
13469    pub fn cut_common(
13470        &mut self,
13471        cut_no_selection_line: bool,
13472        window: &mut Window,
13473        cx: &mut Context<Self>,
13474    ) -> ClipboardItem {
13475        let mut text = String::new();
13476        let buffer = self.buffer.read(cx).snapshot(cx);
13477        let mut selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13478        let mut clipboard_selections = Vec::with_capacity(selections.len());
13479        {
13480            let max_point = buffer.max_point();
13481            let mut is_first = true;
13482            let mut prev_selection_was_entire_line = false;
13483            for selection in &mut selections {
13484                let is_entire_line =
13485                    (selection.is_empty() && cut_no_selection_line) || self.selections.line_mode();
13486                if is_entire_line {
13487                    selection.start = Point::new(selection.start.row, 0);
13488                    if !selection.is_empty() && selection.end.column == 0 {
13489                        selection.end = cmp::min(max_point, selection.end);
13490                    } else {
13491                        selection.end = cmp::min(max_point, Point::new(selection.end.row + 1, 0));
13492                    }
13493                    selection.goal = SelectionGoal::None;
13494                }
13495                if is_first {
13496                    is_first = false;
13497                } else if !prev_selection_was_entire_line {
13498                    text += "\n";
13499                }
13500                prev_selection_was_entire_line = is_entire_line;
13501                let mut len = 0;
13502                for chunk in buffer.text_for_range(selection.start..selection.end) {
13503                    text.push_str(chunk);
13504                    len += chunk.len();
13505                }
13506
13507                clipboard_selections.push(ClipboardSelection::for_buffer(
13508                    len,
13509                    is_entire_line,
13510                    selection.range(),
13511                    &buffer,
13512                    self.project.as_ref(),
13513                    cx,
13514                ));
13515            }
13516        }
13517
13518        self.transact(window, cx, |this, window, cx| {
13519            this.change_selections(Default::default(), window, cx, |s| {
13520                s.select(selections);
13521            });
13522            this.insert("", window, cx);
13523        });
13524        ClipboardItem::new_string_with_json_metadata(text, clipboard_selections)
13525    }
13526
13527    pub fn cut(&mut self, _: &Cut, window: &mut Window, cx: &mut Context<Self>) {
13528        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13529        let item = self.cut_common(true, window, cx);
13530        cx.write_to_clipboard(item);
13531    }
13532
13533    pub fn kill_ring_cut(&mut self, _: &KillRingCut, window: &mut Window, cx: &mut Context<Self>) {
13534        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13535        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13536            s.move_with(&mut |snapshot, sel| {
13537                if sel.is_empty() {
13538                    sel.end = DisplayPoint::new(sel.end.row(), snapshot.line_len(sel.end.row()));
13539                }
13540                if sel.is_empty() {
13541                    sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
13542                }
13543            });
13544        });
13545        let item = self.cut_common(false, window, cx);
13546        cx.set_global(KillRing(item))
13547    }
13548
13549    pub fn kill_ring_yank(
13550        &mut self,
13551        _: &KillRingYank,
13552        window: &mut Window,
13553        cx: &mut Context<Self>,
13554    ) {
13555        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13556        let (text, metadata) = if let Some(KillRing(item)) = cx.try_global() {
13557            if let Some(ClipboardEntry::String(kill_ring)) = item.entries().first() {
13558                (kill_ring.text().to_string(), kill_ring.metadata_json())
13559            } else {
13560                return;
13561            }
13562        } else {
13563            return;
13564        };
13565        self.do_paste(&text, metadata, false, window, cx);
13566    }
13567
13568    pub fn copy_and_trim(&mut self, _: &CopyAndTrim, _: &mut Window, cx: &mut Context<Self>) {
13569        self.do_copy(true, cx);
13570    }
13571
13572    pub fn copy(&mut self, _: &Copy, _: &mut Window, cx: &mut Context<Self>) {
13573        self.do_copy(false, cx);
13574    }
13575
13576    fn do_copy(&self, strip_leading_indents: bool, cx: &mut Context<Self>) {
13577        let selections = self.selections.all::<Point>(&self.display_snapshot(cx));
13578        let buffer = self.buffer.read(cx).read(cx);
13579        let mut text = String::new();
13580        let mut clipboard_selections = Vec::with_capacity(selections.len());
13581
13582        let max_point = buffer.max_point();
13583        let mut is_first = true;
13584        for selection in &selections {
13585            let mut start = selection.start;
13586            let mut end = selection.end;
13587            let is_entire_line = selection.is_empty() || self.selections.line_mode();
13588            let mut add_trailing_newline = false;
13589            if is_entire_line {
13590                start = Point::new(start.row, 0);
13591                let next_line_start = Point::new(end.row + 1, 0);
13592                if next_line_start <= max_point {
13593                    end = next_line_start;
13594                } else {
13595                    // We're on the last line without a trailing newline.
13596                    // Copy to the end of the line and add a newline afterwards.
13597                    end = Point::new(end.row, buffer.line_len(MultiBufferRow(end.row)));
13598                    add_trailing_newline = true;
13599                }
13600            }
13601
13602            let mut trimmed_selections = Vec::new();
13603            if strip_leading_indents && end.row.saturating_sub(start.row) > 0 {
13604                let row = MultiBufferRow(start.row);
13605                let first_indent = buffer.indent_size_for_line(row);
13606                if first_indent.len == 0 || start.column > first_indent.len {
13607                    trimmed_selections.push(start..end);
13608                } else {
13609                    trimmed_selections.push(
13610                        Point::new(row.0, first_indent.len)
13611                            ..Point::new(row.0, buffer.line_len(row)),
13612                    );
13613                    for row in start.row + 1..=end.row {
13614                        let mut line_len = buffer.line_len(MultiBufferRow(row));
13615                        if row == end.row {
13616                            line_len = end.column;
13617                        }
13618                        if line_len == 0 {
13619                            trimmed_selections.push(Point::new(row, 0)..Point::new(row, line_len));
13620                            continue;
13621                        }
13622                        let row_indent_size = buffer.indent_size_for_line(MultiBufferRow(row));
13623                        if row_indent_size.len >= first_indent.len {
13624                            trimmed_selections
13625                                .push(Point::new(row, first_indent.len)..Point::new(row, line_len));
13626                        } else {
13627                            trimmed_selections.clear();
13628                            trimmed_selections.push(start..end);
13629                            break;
13630                        }
13631                    }
13632                }
13633            } else {
13634                trimmed_selections.push(start..end);
13635            }
13636
13637            let is_multiline_trim = trimmed_selections.len() > 1;
13638            let mut selection_len: usize = 0;
13639            let prev_selection_was_entire_line = is_entire_line && !is_multiline_trim;
13640
13641            for trimmed_range in trimmed_selections {
13642                if is_first {
13643                    is_first = false;
13644                } else if is_multiline_trim || !prev_selection_was_entire_line {
13645                    text.push('\n');
13646                    if is_multiline_trim {
13647                        selection_len += 1;
13648                    }
13649                }
13650                for chunk in buffer.text_for_range(trimmed_range.start..trimmed_range.end) {
13651                    text.push_str(chunk);
13652                    selection_len += chunk.len();
13653                }
13654                if add_trailing_newline {
13655                    text.push('\n');
13656                    selection_len += 1;
13657                }
13658            }
13659
13660            clipboard_selections.push(ClipboardSelection::for_buffer(
13661                selection_len,
13662                is_entire_line,
13663                start..end,
13664                &buffer,
13665                self.project.as_ref(),
13666                cx,
13667            ));
13668        }
13669
13670        cx.write_to_clipboard(ClipboardItem::new_string_with_json_metadata(
13671            text,
13672            clipboard_selections,
13673        ));
13674    }
13675
13676    pub fn do_paste(
13677        &mut self,
13678        text: &String,
13679        clipboard_selections: Option<Vec<ClipboardSelection>>,
13680        handle_entire_lines: bool,
13681        window: &mut Window,
13682        cx: &mut Context<Self>,
13683    ) {
13684        if self.read_only(cx) {
13685            return;
13686        }
13687
13688        let clipboard_text = Cow::Borrowed(text.as_str());
13689
13690        self.transact(window, cx, |this, window, cx| {
13691            let had_active_edit_prediction = this.has_active_edit_prediction();
13692            let display_map = this.display_snapshot(cx);
13693            let old_selections = this.selections.all::<MultiBufferOffset>(&display_map);
13694            let cursor_offset = this
13695                .selections
13696                .last::<MultiBufferOffset>(&display_map)
13697                .head();
13698
13699            if let Some(mut clipboard_selections) = clipboard_selections {
13700                let all_selections_were_entire_line =
13701                    clipboard_selections.iter().all(|s| s.is_entire_line);
13702                let first_selection_indent_column =
13703                    clipboard_selections.first().map(|s| s.first_line_indent);
13704                if clipboard_selections.len() != old_selections.len() {
13705                    clipboard_selections.drain(..);
13706                }
13707                let mut auto_indent_on_paste = true;
13708
13709                this.buffer.update(cx, |buffer, cx| {
13710                    let snapshot = buffer.read(cx);
13711                    auto_indent_on_paste = snapshot
13712                        .language_settings_at(cursor_offset, cx)
13713                        .auto_indent_on_paste;
13714
13715                    let mut start_offset = 0;
13716                    let mut edits = Vec::new();
13717                    let mut original_indent_columns = Vec::new();
13718                    for (ix, selection) in old_selections.iter().enumerate() {
13719                        let to_insert;
13720                        let entire_line;
13721                        let original_indent_column;
13722                        if let Some(clipboard_selection) = clipboard_selections.get(ix) {
13723                            let end_offset = start_offset + clipboard_selection.len;
13724                            to_insert = &clipboard_text[start_offset..end_offset];
13725                            entire_line = clipboard_selection.is_entire_line;
13726                            start_offset = if entire_line {
13727                                end_offset
13728                            } else {
13729                                end_offset + 1
13730                            };
13731                            original_indent_column = Some(clipboard_selection.first_line_indent);
13732                        } else {
13733                            to_insert = &*clipboard_text;
13734                            entire_line = all_selections_were_entire_line;
13735                            original_indent_column = first_selection_indent_column
13736                        }
13737
13738                        let (range, to_insert) =
13739                            if selection.is_empty() && handle_entire_lines && entire_line {
13740                                // If the corresponding selection was empty when this slice of the
13741                                // clipboard text was written, then the entire line containing the
13742                                // selection was copied. If this selection is also currently empty,
13743                                // then paste the line before the current line of the buffer.
13744                                let column = selection.start.to_point(&snapshot).column as usize;
13745                                let line_start = selection.start - column;
13746                                (line_start..line_start, Cow::Borrowed(to_insert))
13747                            } else {
13748                                let language = snapshot.language_at(selection.head());
13749                                let range = selection.range();
13750                                if let Some(language) = language
13751                                    && language.name() == "Markdown"
13752                                {
13753                                    edit_for_markdown_paste(
13754                                        &snapshot,
13755                                        range,
13756                                        to_insert,
13757                                        url::Url::parse(to_insert).ok(),
13758                                    )
13759                                } else {
13760                                    (range, Cow::Borrowed(to_insert))
13761                                }
13762                            };
13763
13764                        edits.push((range, to_insert));
13765                        original_indent_columns.push(original_indent_column);
13766                    }
13767                    drop(snapshot);
13768
13769                    buffer.edit(
13770                        edits,
13771                        if auto_indent_on_paste {
13772                            Some(AutoindentMode::Block {
13773                                original_indent_columns,
13774                            })
13775                        } else {
13776                            None
13777                        },
13778                        cx,
13779                    );
13780                });
13781
13782                let selections = this
13783                    .selections
13784                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
13785                this.change_selections(Default::default(), window, cx, |s| s.select(selections));
13786            } else {
13787                let url = url::Url::parse(&clipboard_text).ok();
13788
13789                let auto_indent_mode = if !clipboard_text.is_empty() {
13790                    Some(AutoindentMode::Block {
13791                        original_indent_columns: Vec::new(),
13792                    })
13793                } else {
13794                    None
13795                };
13796
13797                let selection_anchors = this.buffer.update(cx, |buffer, cx| {
13798                    let snapshot = buffer.snapshot(cx);
13799
13800                    let anchors = old_selections
13801                        .iter()
13802                        .map(|s| {
13803                            let anchor = snapshot.anchor_after(s.head());
13804                            s.map(|_| anchor)
13805                        })
13806                        .collect::<Vec<_>>();
13807
13808                    let mut edits = Vec::new();
13809
13810                    // When pasting text without metadata (e.g. copied from an
13811                    // external editor using multiple cursors) and the number of
13812                    // lines matches the number of selections, distribute one
13813                    // line per cursor instead of pasting the whole text at each.
13814                    let lines: Vec<&str> = clipboard_text.split('\n').collect();
13815                    let distribute_lines =
13816                        old_selections.len() > 1 && lines.len() == old_selections.len();
13817
13818                    for (ix, selection) in old_selections.iter().enumerate() {
13819                        let language = snapshot.language_at(selection.head());
13820                        let range = selection.range();
13821
13822                        let text_for_cursor: &str = if distribute_lines {
13823                            lines[ix]
13824                        } else {
13825                            &clipboard_text
13826                        };
13827
13828                        let (edit_range, edit_text) = if let Some(language) = language
13829                            && language.name() == "Markdown"
13830                        {
13831                            edit_for_markdown_paste(&snapshot, range, text_for_cursor, url.clone())
13832                        } else {
13833                            (range, Cow::Borrowed(text_for_cursor))
13834                        };
13835
13836                        edits.push((edit_range, edit_text));
13837                    }
13838
13839                    drop(snapshot);
13840                    buffer.edit(edits, auto_indent_mode, cx);
13841
13842                    anchors
13843                });
13844
13845                this.change_selections(Default::default(), window, cx, |s| {
13846                    s.select_anchors(selection_anchors);
13847                });
13848            }
13849
13850            //   🤔                 |    ..     | show_in_menu |
13851            // | ..                  |   true        true
13852            // | had_edit_prediction |   false       true
13853
13854            let trigger_in_words =
13855                this.show_edit_predictions_in_menu() || !had_active_edit_prediction;
13856
13857            this.trigger_completion_on_input(text, trigger_in_words, window, cx);
13858        });
13859    }
13860
13861    pub fn diff_clipboard_with_selection(
13862        &mut self,
13863        _: &DiffClipboardWithSelection,
13864        window: &mut Window,
13865        cx: &mut Context<Self>,
13866    ) {
13867        let selections = self
13868            .selections
13869            .all::<MultiBufferOffset>(&self.display_snapshot(cx));
13870
13871        if selections.is_empty() {
13872            log::warn!("There should always be at least one selection in Zed. This is a bug.");
13873            return;
13874        };
13875
13876        let clipboard_text = match cx.read_from_clipboard() {
13877            Some(item) => match item.entries().first() {
13878                Some(ClipboardEntry::String(text)) => Some(text.text().to_string()),
13879                _ => None,
13880            },
13881            None => None,
13882        };
13883
13884        let Some(clipboard_text) = clipboard_text else {
13885            log::warn!("Clipboard doesn't contain text.");
13886            return;
13887        };
13888
13889        window.dispatch_action(
13890            Box::new(DiffClipboardWithSelectionData {
13891                clipboard_text,
13892                editor: cx.entity(),
13893            }),
13894            cx,
13895        );
13896    }
13897
13898    pub fn paste(&mut self, _: &Paste, window: &mut Window, cx: &mut Context<Self>) {
13899        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13900        if let Some(item) = cx.read_from_clipboard() {
13901            let entries = item.entries();
13902
13903            match entries.first() {
13904                // For now, we only support applying metadata if there's one string. In the future, we can incorporate all the selections
13905                // of all the pasted entries.
13906                Some(ClipboardEntry::String(clipboard_string)) if entries.len() == 1 => self
13907                    .do_paste(
13908                        clipboard_string.text(),
13909                        clipboard_string.metadata_json::<Vec<ClipboardSelection>>(),
13910                        true,
13911                        window,
13912                        cx,
13913                    ),
13914                _ => self.do_paste(&item.text().unwrap_or_default(), None, true, window, cx),
13915            }
13916        }
13917    }
13918
13919    pub fn undo(&mut self, _: &Undo, window: &mut Window, cx: &mut Context<Self>) {
13920        if self.read_only(cx) {
13921            return;
13922        }
13923
13924        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13925
13926        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.undo(cx)) {
13927            if let Some((selections, _)) =
13928                self.selection_history.transaction(transaction_id).cloned()
13929            {
13930                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13931                    s.select_anchors(selections.to_vec());
13932                });
13933            } else {
13934                log::error!(
13935                    "No entry in selection_history found for undo. \
13936                     This may correspond to a bug where undo does not update the selection. \
13937                     If this is occurring, please add details to \
13938                     https://github.com/zed-industries/zed/issues/22692"
13939                );
13940            }
13941            self.request_autoscroll(Autoscroll::fit(), cx);
13942            self.unmark_text(window, cx);
13943            self.refresh_edit_prediction(true, false, window, cx);
13944            cx.emit(EditorEvent::Edited { transaction_id });
13945            cx.emit(EditorEvent::TransactionUndone { transaction_id });
13946        }
13947    }
13948
13949    pub fn redo(&mut self, _: &Redo, window: &mut Window, cx: &mut Context<Self>) {
13950        if self.read_only(cx) {
13951            return;
13952        }
13953
13954        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
13955
13956        if let Some(transaction_id) = self.buffer.update(cx, |buffer, cx| buffer.redo(cx)) {
13957            if let Some((_, Some(selections))) =
13958                self.selection_history.transaction(transaction_id).cloned()
13959            {
13960                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
13961                    s.select_anchors(selections.to_vec());
13962                });
13963            } else {
13964                log::error!(
13965                    "No entry in selection_history found for redo. \
13966                     This may correspond to a bug where undo does not update the selection. \
13967                     If this is occurring, please add details to \
13968                     https://github.com/zed-industries/zed/issues/22692"
13969                );
13970            }
13971            self.request_autoscroll(Autoscroll::fit(), cx);
13972            self.unmark_text(window, cx);
13973            self.refresh_edit_prediction(true, false, window, cx);
13974            cx.emit(EditorEvent::Edited { transaction_id });
13975        }
13976    }
13977
13978    pub fn finalize_last_transaction(&mut self, cx: &mut Context<Self>) {
13979        self.buffer
13980            .update(cx, |buffer, cx| buffer.finalize_last_transaction(cx));
13981    }
13982
13983    pub fn group_until_transaction(&mut self, tx_id: TransactionId, cx: &mut Context<Self>) {
13984        self.buffer
13985            .update(cx, |buffer, cx| buffer.group_until_transaction(tx_id, cx));
13986    }
13987
13988    pub fn move_left(&mut self, _: &MoveLeft, window: &mut Window, cx: &mut Context<Self>) {
13989        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
13990        self.change_selections(Default::default(), window, cx, |s| {
13991            s.move_with(&mut |map, selection| {
13992                let cursor = if selection.is_empty() {
13993                    movement::left(map, selection.start)
13994                } else {
13995                    selection.start
13996                };
13997                selection.collapse_to(cursor, SelectionGoal::None);
13998            });
13999        })
14000    }
14001
14002    pub fn select_left(&mut self, _: &SelectLeft, window: &mut Window, cx: &mut Context<Self>) {
14003        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14004        self.change_selections(Default::default(), window, cx, |s| {
14005            s.move_heads_with(&mut |map, head, _| (movement::left(map, head), SelectionGoal::None));
14006        })
14007    }
14008
14009    pub fn move_right(&mut self, _: &MoveRight, window: &mut Window, cx: &mut Context<Self>) {
14010        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14011        self.change_selections(Default::default(), window, cx, |s| {
14012            s.move_with(&mut |map, selection| {
14013                let cursor = if selection.is_empty() {
14014                    movement::right(map, selection.end)
14015                } else {
14016                    selection.end
14017                };
14018                selection.collapse_to(cursor, SelectionGoal::None)
14019            });
14020        })
14021    }
14022
14023    pub fn select_right(&mut self, _: &SelectRight, window: &mut Window, cx: &mut Context<Self>) {
14024        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14025        self.change_selections(Default::default(), window, cx, |s| {
14026            s.move_heads_with(&mut |map, head, _| {
14027                (movement::right(map, head), SelectionGoal::None)
14028            });
14029        });
14030    }
14031
14032    pub fn move_up(&mut self, _: &MoveUp, window: &mut Window, cx: &mut Context<Self>) {
14033        if self.take_rename(true, window, cx).is_some() {
14034            return;
14035        }
14036
14037        if self.mode.is_single_line() {
14038            cx.propagate();
14039            return;
14040        }
14041
14042        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14043
14044        let text_layout_details = &self.text_layout_details(window, cx);
14045        let selection_count = self.selections.count();
14046        let first_selection = self.selections.first_anchor();
14047
14048        self.change_selections(Default::default(), window, cx, |s| {
14049            s.move_with(&mut |map, selection| {
14050                if !selection.is_empty() {
14051                    selection.goal = SelectionGoal::None;
14052                }
14053                let (cursor, goal) = movement::up(
14054                    map,
14055                    selection.start,
14056                    selection.goal,
14057                    false,
14058                    text_layout_details,
14059                );
14060                selection.collapse_to(cursor, goal);
14061            });
14062        });
14063
14064        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14065        {
14066            cx.propagate();
14067        }
14068    }
14069
14070    pub fn move_up_by_lines(
14071        &mut self,
14072        action: &MoveUpByLines,
14073        window: &mut Window,
14074        cx: &mut Context<Self>,
14075    ) {
14076        if self.take_rename(true, window, cx).is_some() {
14077            return;
14078        }
14079
14080        if self.mode.is_single_line() {
14081            cx.propagate();
14082            return;
14083        }
14084
14085        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14086
14087        let text_layout_details = &self.text_layout_details(window, cx);
14088
14089        self.change_selections(Default::default(), window, cx, |s| {
14090            s.move_with(&mut |map, selection| {
14091                if !selection.is_empty() {
14092                    selection.goal = SelectionGoal::None;
14093                }
14094                let (cursor, goal) = movement::up_by_rows(
14095                    map,
14096                    selection.start,
14097                    action.lines,
14098                    selection.goal,
14099                    false,
14100                    text_layout_details,
14101                );
14102                selection.collapse_to(cursor, goal);
14103            });
14104        })
14105    }
14106
14107    pub fn move_down_by_lines(
14108        &mut self,
14109        action: &MoveDownByLines,
14110        window: &mut Window,
14111        cx: &mut Context<Self>,
14112    ) {
14113        if self.take_rename(true, window, cx).is_some() {
14114            return;
14115        }
14116
14117        if self.mode.is_single_line() {
14118            cx.propagate();
14119            return;
14120        }
14121
14122        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14123
14124        let text_layout_details = &self.text_layout_details(window, cx);
14125
14126        self.change_selections(Default::default(), window, cx, |s| {
14127            s.move_with(&mut |map, selection| {
14128                if !selection.is_empty() {
14129                    selection.goal = SelectionGoal::None;
14130                }
14131                let (cursor, goal) = movement::down_by_rows(
14132                    map,
14133                    selection.start,
14134                    action.lines,
14135                    selection.goal,
14136                    false,
14137                    text_layout_details,
14138                );
14139                selection.collapse_to(cursor, goal);
14140            });
14141        })
14142    }
14143
14144    pub fn select_down_by_lines(
14145        &mut self,
14146        action: &SelectDownByLines,
14147        window: &mut Window,
14148        cx: &mut Context<Self>,
14149    ) {
14150        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14151        let text_layout_details = &self.text_layout_details(window, cx);
14152        self.change_selections(Default::default(), window, cx, |s| {
14153            s.move_heads_with(&mut |map, head, goal| {
14154                movement::down_by_rows(map, head, action.lines, goal, false, text_layout_details)
14155            })
14156        })
14157    }
14158
14159    pub fn select_up_by_lines(
14160        &mut self,
14161        action: &SelectUpByLines,
14162        window: &mut Window,
14163        cx: &mut Context<Self>,
14164    ) {
14165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14166        let text_layout_details = &self.text_layout_details(window, cx);
14167        self.change_selections(Default::default(), window, cx, |s| {
14168            s.move_heads_with(&mut |map, head, goal| {
14169                movement::up_by_rows(map, head, action.lines, goal, false, text_layout_details)
14170            })
14171        })
14172    }
14173
14174    pub fn select_page_up(
14175        &mut self,
14176        _: &SelectPageUp,
14177        window: &mut Window,
14178        cx: &mut Context<Self>,
14179    ) {
14180        let Some(row_count) = self.visible_row_count() else {
14181            return;
14182        };
14183
14184        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14185
14186        let text_layout_details = &self.text_layout_details(window, cx);
14187
14188        self.change_selections(Default::default(), window, cx, |s| {
14189            s.move_heads_with(&mut |map, head, goal| {
14190                movement::up_by_rows(map, head, row_count, goal, false, text_layout_details)
14191            })
14192        })
14193    }
14194
14195    pub fn move_page_up(
14196        &mut self,
14197        action: &MovePageUp,
14198        window: &mut Window,
14199        cx: &mut Context<Self>,
14200    ) {
14201        if self.take_rename(true, window, cx).is_some() {
14202            return;
14203        }
14204
14205        if self
14206            .context_menu
14207            .borrow_mut()
14208            .as_mut()
14209            .map(|menu| menu.select_first(self.completion_provider.as_deref(), window, cx))
14210            .unwrap_or(false)
14211        {
14212            return;
14213        }
14214
14215        if matches!(self.mode, EditorMode::SingleLine) {
14216            cx.propagate();
14217            return;
14218        }
14219
14220        let Some(row_count) = self.visible_row_count() else {
14221            return;
14222        };
14223
14224        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14225
14226        let effects = if action.center_cursor {
14227            SelectionEffects::scroll(Autoscroll::center())
14228        } else {
14229            SelectionEffects::default()
14230        };
14231
14232        let text_layout_details = &self.text_layout_details(window, cx);
14233
14234        self.change_selections(effects, window, cx, |s| {
14235            s.move_with(&mut |map, selection| {
14236                if !selection.is_empty() {
14237                    selection.goal = SelectionGoal::None;
14238                }
14239                let (cursor, goal) = movement::up_by_rows(
14240                    map,
14241                    selection.end,
14242                    row_count,
14243                    selection.goal,
14244                    false,
14245                    text_layout_details,
14246                );
14247                selection.collapse_to(cursor, goal);
14248            });
14249        });
14250    }
14251
14252    pub fn select_up(&mut self, _: &SelectUp, window: &mut Window, cx: &mut Context<Self>) {
14253        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14254        let text_layout_details = &self.text_layout_details(window, cx);
14255        self.change_selections(Default::default(), window, cx, |s| {
14256            s.move_heads_with(&mut |map, head, goal| {
14257                movement::up(map, head, goal, false, text_layout_details)
14258            })
14259        })
14260    }
14261
14262    pub fn move_down(&mut self, _: &MoveDown, window: &mut Window, cx: &mut Context<Self>) {
14263        self.take_rename(true, window, cx);
14264
14265        if self.mode.is_single_line() {
14266            cx.propagate();
14267            return;
14268        }
14269
14270        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14271
14272        let text_layout_details = &self.text_layout_details(window, cx);
14273        let selection_count = self.selections.count();
14274        let first_selection = self.selections.first_anchor();
14275
14276        self.change_selections(Default::default(), window, cx, |s| {
14277            s.move_with(&mut |map, selection| {
14278                if !selection.is_empty() {
14279                    selection.goal = SelectionGoal::None;
14280                }
14281                let (cursor, goal) = movement::down(
14282                    map,
14283                    selection.end,
14284                    selection.goal,
14285                    false,
14286                    text_layout_details,
14287                );
14288                selection.collapse_to(cursor, goal);
14289            });
14290        });
14291
14292        if selection_count == 1 && first_selection.range() == self.selections.first_anchor().range()
14293        {
14294            cx.propagate();
14295        }
14296    }
14297
14298    pub fn select_page_down(
14299        &mut self,
14300        _: &SelectPageDown,
14301        window: &mut Window,
14302        cx: &mut Context<Self>,
14303    ) {
14304        let Some(row_count) = self.visible_row_count() else {
14305            return;
14306        };
14307
14308        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14309
14310        let text_layout_details = &self.text_layout_details(window, cx);
14311
14312        self.change_selections(Default::default(), window, cx, |s| {
14313            s.move_heads_with(&mut |map, head, goal| {
14314                movement::down_by_rows(map, head, row_count, goal, false, text_layout_details)
14315            })
14316        })
14317    }
14318
14319    pub fn move_page_down(
14320        &mut self,
14321        action: &MovePageDown,
14322        window: &mut Window,
14323        cx: &mut Context<Self>,
14324    ) {
14325        if self.take_rename(true, window, cx).is_some() {
14326            return;
14327        }
14328
14329        if self
14330            .context_menu
14331            .borrow_mut()
14332            .as_mut()
14333            .map(|menu| menu.select_last(self.completion_provider.as_deref(), window, cx))
14334            .unwrap_or(false)
14335        {
14336            return;
14337        }
14338
14339        if matches!(self.mode, EditorMode::SingleLine) {
14340            cx.propagate();
14341            return;
14342        }
14343
14344        let Some(row_count) = self.visible_row_count() else {
14345            return;
14346        };
14347
14348        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14349
14350        let effects = if action.center_cursor {
14351            SelectionEffects::scroll(Autoscroll::center())
14352        } else {
14353            SelectionEffects::default()
14354        };
14355
14356        let text_layout_details = &self.text_layout_details(window, cx);
14357        self.change_selections(effects, window, cx, |s| {
14358            s.move_with(&mut |map, selection| {
14359                if !selection.is_empty() {
14360                    selection.goal = SelectionGoal::None;
14361                }
14362                let (cursor, goal) = movement::down_by_rows(
14363                    map,
14364                    selection.end,
14365                    row_count,
14366                    selection.goal,
14367                    false,
14368                    text_layout_details,
14369                );
14370                selection.collapse_to(cursor, goal);
14371            });
14372        });
14373    }
14374
14375    pub fn select_down(&mut self, _: &SelectDown, window: &mut Window, cx: &mut Context<Self>) {
14376        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14377        let text_layout_details = &self.text_layout_details(window, cx);
14378        self.change_selections(Default::default(), window, cx, |s| {
14379            s.move_heads_with(&mut |map, head, goal| {
14380                movement::down(map, head, goal, false, text_layout_details)
14381            })
14382        });
14383    }
14384
14385    pub fn context_menu_first(
14386        &mut self,
14387        _: &ContextMenuFirst,
14388        window: &mut Window,
14389        cx: &mut Context<Self>,
14390    ) {
14391        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14392            context_menu.select_first(self.completion_provider.as_deref(), window, cx);
14393        }
14394    }
14395
14396    pub fn context_menu_prev(
14397        &mut self,
14398        _: &ContextMenuPrevious,
14399        window: &mut Window,
14400        cx: &mut Context<Self>,
14401    ) {
14402        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14403            context_menu.select_prev(self.completion_provider.as_deref(), window, cx);
14404        }
14405    }
14406
14407    pub fn context_menu_next(
14408        &mut self,
14409        _: &ContextMenuNext,
14410        window: &mut Window,
14411        cx: &mut Context<Self>,
14412    ) {
14413        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14414            context_menu.select_next(self.completion_provider.as_deref(), window, cx);
14415        }
14416    }
14417
14418    pub fn context_menu_last(
14419        &mut self,
14420        _: &ContextMenuLast,
14421        window: &mut Window,
14422        cx: &mut Context<Self>,
14423    ) {
14424        if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
14425            context_menu.select_last(self.completion_provider.as_deref(), window, cx);
14426        }
14427    }
14428
14429    pub fn signature_help_prev(
14430        &mut self,
14431        _: &SignatureHelpPrevious,
14432        _: &mut Window,
14433        cx: &mut Context<Self>,
14434    ) {
14435        if let Some(popover) = self.signature_help_state.popover_mut() {
14436            if popover.current_signature == 0 {
14437                popover.current_signature = popover.signatures.len() - 1;
14438            } else {
14439                popover.current_signature -= 1;
14440            }
14441            cx.notify();
14442        }
14443    }
14444
14445    pub fn signature_help_next(
14446        &mut self,
14447        _: &SignatureHelpNext,
14448        _: &mut Window,
14449        cx: &mut Context<Self>,
14450    ) {
14451        if let Some(popover) = self.signature_help_state.popover_mut() {
14452            if popover.current_signature + 1 == popover.signatures.len() {
14453                popover.current_signature = 0;
14454            } else {
14455                popover.current_signature += 1;
14456            }
14457            cx.notify();
14458        }
14459    }
14460
14461    pub fn move_to_previous_word_start(
14462        &mut self,
14463        _: &MoveToPreviousWordStart,
14464        window: &mut Window,
14465        cx: &mut Context<Self>,
14466    ) {
14467        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14468        self.change_selections(Default::default(), window, cx, |s| {
14469            s.move_cursors_with(&mut |map, head, _| {
14470                (
14471                    movement::previous_word_start(map, head),
14472                    SelectionGoal::None,
14473                )
14474            });
14475        })
14476    }
14477
14478    pub fn move_to_previous_subword_start(
14479        &mut self,
14480        _: &MoveToPreviousSubwordStart,
14481        window: &mut Window,
14482        cx: &mut Context<Self>,
14483    ) {
14484        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14485        self.change_selections(Default::default(), window, cx, |s| {
14486            s.move_cursors_with(&mut |map, head, _| {
14487                (
14488                    movement::previous_subword_start(map, head),
14489                    SelectionGoal::None,
14490                )
14491            });
14492        })
14493    }
14494
14495    pub fn select_to_previous_word_start(
14496        &mut self,
14497        _: &SelectToPreviousWordStart,
14498        window: &mut Window,
14499        cx: &mut Context<Self>,
14500    ) {
14501        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14502        self.change_selections(Default::default(), window, cx, |s| {
14503            s.move_heads_with(&mut |map, head, _| {
14504                (
14505                    movement::previous_word_start(map, head),
14506                    SelectionGoal::None,
14507                )
14508            });
14509        })
14510    }
14511
14512    pub fn select_to_previous_subword_start(
14513        &mut self,
14514        _: &SelectToPreviousSubwordStart,
14515        window: &mut Window,
14516        cx: &mut Context<Self>,
14517    ) {
14518        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14519        self.change_selections(Default::default(), window, cx, |s| {
14520            s.move_heads_with(&mut |map, head, _| {
14521                (
14522                    movement::previous_subword_start(map, head),
14523                    SelectionGoal::None,
14524                )
14525            });
14526        })
14527    }
14528
14529    pub fn delete_to_previous_word_start(
14530        &mut self,
14531        action: &DeleteToPreviousWordStart,
14532        window: &mut Window,
14533        cx: &mut Context<Self>,
14534    ) {
14535        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14536        self.transact(window, cx, |this, window, cx| {
14537            this.select_autoclose_pair(window, cx);
14538            this.change_selections(Default::default(), window, cx, |s| {
14539                s.move_with(&mut |map, selection| {
14540                    if selection.is_empty() {
14541                        let mut cursor = if action.ignore_newlines {
14542                            movement::previous_word_start(map, selection.head())
14543                        } else {
14544                            movement::previous_word_start_or_newline(map, selection.head())
14545                        };
14546                        cursor = movement::adjust_greedy_deletion(
14547                            map,
14548                            selection.head(),
14549                            cursor,
14550                            action.ignore_brackets,
14551                        );
14552                        selection.set_head(cursor, SelectionGoal::None);
14553                    }
14554                });
14555            });
14556            this.insert("", window, cx);
14557        });
14558    }
14559
14560    pub fn delete_to_previous_subword_start(
14561        &mut self,
14562        action: &DeleteToPreviousSubwordStart,
14563        window: &mut Window,
14564        cx: &mut Context<Self>,
14565    ) {
14566        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14567        self.transact(window, cx, |this, window, cx| {
14568            this.select_autoclose_pair(window, cx);
14569            this.change_selections(Default::default(), window, cx, |s| {
14570                s.move_with(&mut |map, selection| {
14571                    if selection.is_empty() {
14572                        let mut cursor = if action.ignore_newlines {
14573                            movement::previous_subword_start(map, selection.head())
14574                        } else {
14575                            movement::previous_subword_start_or_newline(map, selection.head())
14576                        };
14577                        cursor = movement::adjust_greedy_deletion(
14578                            map,
14579                            selection.head(),
14580                            cursor,
14581                            action.ignore_brackets,
14582                        );
14583                        selection.set_head(cursor, SelectionGoal::None);
14584                    }
14585                });
14586            });
14587            this.insert("", window, cx);
14588        });
14589    }
14590
14591    pub fn move_to_next_word_end(
14592        &mut self,
14593        _: &MoveToNextWordEnd,
14594        window: &mut Window,
14595        cx: &mut Context<Self>,
14596    ) {
14597        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14598        self.change_selections(Default::default(), window, cx, |s| {
14599            s.move_cursors_with(&mut |map, head, _| {
14600                (movement::next_word_end(map, head), SelectionGoal::None)
14601            });
14602        })
14603    }
14604
14605    pub fn move_to_next_subword_end(
14606        &mut self,
14607        _: &MoveToNextSubwordEnd,
14608        window: &mut Window,
14609        cx: &mut Context<Self>,
14610    ) {
14611        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14612        self.change_selections(Default::default(), window, cx, |s| {
14613            s.move_cursors_with(&mut |map, head, _| {
14614                (movement::next_subword_end(map, head), SelectionGoal::None)
14615            });
14616        })
14617    }
14618
14619    pub fn select_to_next_word_end(
14620        &mut self,
14621        _: &SelectToNextWordEnd,
14622        window: &mut Window,
14623        cx: &mut Context<Self>,
14624    ) {
14625        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14626        self.change_selections(Default::default(), window, cx, |s| {
14627            s.move_heads_with(&mut |map, head, _| {
14628                (movement::next_word_end(map, head), SelectionGoal::None)
14629            });
14630        })
14631    }
14632
14633    pub fn select_to_next_subword_end(
14634        &mut self,
14635        _: &SelectToNextSubwordEnd,
14636        window: &mut Window,
14637        cx: &mut Context<Self>,
14638    ) {
14639        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14640        self.change_selections(Default::default(), window, cx, |s| {
14641            s.move_heads_with(&mut |map, head, _| {
14642                (movement::next_subword_end(map, head), SelectionGoal::None)
14643            });
14644        })
14645    }
14646
14647    pub fn delete_to_next_word_end(
14648        &mut self,
14649        action: &DeleteToNextWordEnd,
14650        window: &mut Window,
14651        cx: &mut Context<Self>,
14652    ) {
14653        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14654        self.transact(window, cx, |this, window, cx| {
14655            this.change_selections(Default::default(), window, cx, |s| {
14656                s.move_with(&mut |map, selection| {
14657                    if selection.is_empty() {
14658                        let mut cursor = if action.ignore_newlines {
14659                            movement::next_word_end(map, selection.head())
14660                        } else {
14661                            movement::next_word_end_or_newline(map, selection.head())
14662                        };
14663                        cursor = movement::adjust_greedy_deletion(
14664                            map,
14665                            selection.head(),
14666                            cursor,
14667                            action.ignore_brackets,
14668                        );
14669                        selection.set_head(cursor, SelectionGoal::None);
14670                    }
14671                });
14672            });
14673            this.insert("", window, cx);
14674        });
14675    }
14676
14677    pub fn delete_to_next_subword_end(
14678        &mut self,
14679        action: &DeleteToNextSubwordEnd,
14680        window: &mut Window,
14681        cx: &mut Context<Self>,
14682    ) {
14683        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14684        self.transact(window, cx, |this, window, cx| {
14685            this.change_selections(Default::default(), window, cx, |s| {
14686                s.move_with(&mut |map, selection| {
14687                    if selection.is_empty() {
14688                        let mut cursor = if action.ignore_newlines {
14689                            movement::next_subword_end(map, selection.head())
14690                        } else {
14691                            movement::next_subword_end_or_newline(map, selection.head())
14692                        };
14693                        cursor = movement::adjust_greedy_deletion(
14694                            map,
14695                            selection.head(),
14696                            cursor,
14697                            action.ignore_brackets,
14698                        );
14699                        selection.set_head(cursor, SelectionGoal::None);
14700                    }
14701                });
14702            });
14703            this.insert("", window, cx);
14704        });
14705    }
14706
14707    pub fn move_to_beginning_of_line(
14708        &mut self,
14709        action: &MoveToBeginningOfLine,
14710        window: &mut Window,
14711        cx: &mut Context<Self>,
14712    ) {
14713        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
14714        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14715        self.change_selections(Default::default(), window, cx, |s| {
14716            s.move_cursors_with(&mut |map, head, _| {
14717                (
14718                    movement::indented_line_beginning(
14719                        map,
14720                        head,
14721                        action.stop_at_soft_wraps,
14722                        stop_at_indent,
14723                    ),
14724                    SelectionGoal::None,
14725                )
14726            });
14727        })
14728    }
14729
14730    pub fn select_to_beginning_of_line(
14731        &mut self,
14732        action: &SelectToBeginningOfLine,
14733        window: &mut Window,
14734        cx: &mut Context<Self>,
14735    ) {
14736        let stop_at_indent = action.stop_at_indent && !self.mode.is_single_line();
14737        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14738        self.change_selections(Default::default(), window, cx, |s| {
14739            s.move_heads_with(&mut |map, head, _| {
14740                (
14741                    movement::indented_line_beginning(
14742                        map,
14743                        head,
14744                        action.stop_at_soft_wraps,
14745                        stop_at_indent,
14746                    ),
14747                    SelectionGoal::None,
14748                )
14749            });
14750        });
14751    }
14752
14753    pub fn delete_to_beginning_of_line(
14754        &mut self,
14755        action: &DeleteToBeginningOfLine,
14756        window: &mut Window,
14757        cx: &mut Context<Self>,
14758    ) {
14759        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14760        self.transact(window, cx, |this, window, cx| {
14761            this.change_selections(Default::default(), window, cx, |s| {
14762                s.move_with(&mut |_, selection| {
14763                    selection.reversed = true;
14764                });
14765            });
14766
14767            this.select_to_beginning_of_line(
14768                &SelectToBeginningOfLine {
14769                    stop_at_soft_wraps: false,
14770                    stop_at_indent: action.stop_at_indent,
14771                },
14772                window,
14773                cx,
14774            );
14775            this.backspace(&Backspace, window, cx);
14776        });
14777    }
14778
14779    pub fn move_to_end_of_line(
14780        &mut self,
14781        action: &MoveToEndOfLine,
14782        window: &mut Window,
14783        cx: &mut Context<Self>,
14784    ) {
14785        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14786        self.change_selections(Default::default(), window, cx, |s| {
14787            s.move_cursors_with(&mut |map, head, _| {
14788                (
14789                    movement::line_end(map, head, action.stop_at_soft_wraps),
14790                    SelectionGoal::None,
14791                )
14792            });
14793        })
14794    }
14795
14796    pub fn select_to_end_of_line(
14797        &mut self,
14798        action: &SelectToEndOfLine,
14799        window: &mut Window,
14800        cx: &mut Context<Self>,
14801    ) {
14802        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14803        self.change_selections(Default::default(), window, cx, |s| {
14804            s.move_heads_with(&mut |map, head, _| {
14805                (
14806                    movement::line_end(map, head, action.stop_at_soft_wraps),
14807                    SelectionGoal::None,
14808                )
14809            });
14810        })
14811    }
14812
14813    pub fn delete_to_end_of_line(
14814        &mut self,
14815        _: &DeleteToEndOfLine,
14816        window: &mut Window,
14817        cx: &mut Context<Self>,
14818    ) {
14819        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14820        self.transact(window, cx, |this, window, cx| {
14821            this.select_to_end_of_line(
14822                &SelectToEndOfLine {
14823                    stop_at_soft_wraps: false,
14824                },
14825                window,
14826                cx,
14827            );
14828            this.delete(&Delete, window, cx);
14829        });
14830    }
14831
14832    pub fn cut_to_end_of_line(
14833        &mut self,
14834        action: &CutToEndOfLine,
14835        window: &mut Window,
14836        cx: &mut Context<Self>,
14837    ) {
14838        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14839        self.transact(window, cx, |this, window, cx| {
14840            this.select_to_end_of_line(
14841                &SelectToEndOfLine {
14842                    stop_at_soft_wraps: false,
14843                },
14844                window,
14845                cx,
14846            );
14847            if !action.stop_at_newlines {
14848                this.change_selections(Default::default(), window, cx, |s| {
14849                    s.move_with(&mut |_, sel| {
14850                        if sel.is_empty() {
14851                            sel.end = DisplayPoint::new(sel.end.row() + 1_u32, 0);
14852                        }
14853                    });
14854                });
14855            }
14856            this.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
14857            let item = this.cut_common(false, window, cx);
14858            cx.write_to_clipboard(item);
14859        });
14860    }
14861
14862    pub fn move_to_start_of_paragraph(
14863        &mut self,
14864        _: &MoveToStartOfParagraph,
14865        window: &mut Window,
14866        cx: &mut Context<Self>,
14867    ) {
14868        if matches!(self.mode, EditorMode::SingleLine) {
14869            cx.propagate();
14870            return;
14871        }
14872        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14873        self.change_selections(Default::default(), window, cx, |s| {
14874            s.move_with(&mut |map, selection| {
14875                selection.collapse_to(
14876                    movement::start_of_paragraph(map, selection.head(), 1),
14877                    SelectionGoal::None,
14878                )
14879            });
14880        })
14881    }
14882
14883    pub fn move_to_end_of_paragraph(
14884        &mut self,
14885        _: &MoveToEndOfParagraph,
14886        window: &mut Window,
14887        cx: &mut Context<Self>,
14888    ) {
14889        if matches!(self.mode, EditorMode::SingleLine) {
14890            cx.propagate();
14891            return;
14892        }
14893        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14894        self.change_selections(Default::default(), window, cx, |s| {
14895            s.move_with(&mut |map, selection| {
14896                selection.collapse_to(
14897                    movement::end_of_paragraph(map, selection.head(), 1),
14898                    SelectionGoal::None,
14899                )
14900            });
14901        })
14902    }
14903
14904    pub fn select_to_start_of_paragraph(
14905        &mut self,
14906        _: &SelectToStartOfParagraph,
14907        window: &mut Window,
14908        cx: &mut Context<Self>,
14909    ) {
14910        if matches!(self.mode, EditorMode::SingleLine) {
14911            cx.propagate();
14912            return;
14913        }
14914        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14915        self.change_selections(Default::default(), window, cx, |s| {
14916            s.move_heads_with(&mut |map, head, _| {
14917                (
14918                    movement::start_of_paragraph(map, head, 1),
14919                    SelectionGoal::None,
14920                )
14921            });
14922        })
14923    }
14924
14925    pub fn select_to_end_of_paragraph(
14926        &mut self,
14927        _: &SelectToEndOfParagraph,
14928        window: &mut Window,
14929        cx: &mut Context<Self>,
14930    ) {
14931        if matches!(self.mode, EditorMode::SingleLine) {
14932            cx.propagate();
14933            return;
14934        }
14935        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14936        self.change_selections(Default::default(), window, cx, |s| {
14937            s.move_heads_with(&mut |map, head, _| {
14938                (
14939                    movement::end_of_paragraph(map, head, 1),
14940                    SelectionGoal::None,
14941                )
14942            });
14943        })
14944    }
14945
14946    pub fn move_to_start_of_excerpt(
14947        &mut self,
14948        _: &MoveToStartOfExcerpt,
14949        window: &mut Window,
14950        cx: &mut Context<Self>,
14951    ) {
14952        if matches!(self.mode, EditorMode::SingleLine) {
14953            cx.propagate();
14954            return;
14955        }
14956        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
14957        self.change_selections(Default::default(), window, cx, |s| {
14958            s.move_with(&mut |map, selection| {
14959                selection.collapse_to(
14960                    movement::start_of_excerpt(
14961                        map,
14962                        selection.head(),
14963                        workspace::searchable::Direction::Prev,
14964                    ),
14965                    SelectionGoal::None,
14966                )
14967            });
14968        })
14969    }
14970
14971    pub fn move_to_start_of_next_excerpt(
14972        &mut self,
14973        _: &MoveToStartOfNextExcerpt,
14974        window: &mut Window,
14975        cx: &mut Context<Self>,
14976    ) {
14977        if matches!(self.mode, EditorMode::SingleLine) {
14978            cx.propagate();
14979            return;
14980        }
14981
14982        self.change_selections(Default::default(), window, cx, |s| {
14983            s.move_with(&mut |map, selection| {
14984                selection.collapse_to(
14985                    movement::start_of_excerpt(
14986                        map,
14987                        selection.head(),
14988                        workspace::searchable::Direction::Next,
14989                    ),
14990                    SelectionGoal::None,
14991                )
14992            });
14993        })
14994    }
14995
14996    pub fn move_to_end_of_excerpt(
14997        &mut self,
14998        _: &MoveToEndOfExcerpt,
14999        window: &mut Window,
15000        cx: &mut Context<Self>,
15001    ) {
15002        if matches!(self.mode, EditorMode::SingleLine) {
15003            cx.propagate();
15004            return;
15005        }
15006        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15007        self.change_selections(Default::default(), window, cx, |s| {
15008            s.move_with(&mut |map, selection| {
15009                selection.collapse_to(
15010                    movement::end_of_excerpt(
15011                        map,
15012                        selection.head(),
15013                        workspace::searchable::Direction::Next,
15014                    ),
15015                    SelectionGoal::None,
15016                )
15017            });
15018        })
15019    }
15020
15021    pub fn move_to_end_of_previous_excerpt(
15022        &mut self,
15023        _: &MoveToEndOfPreviousExcerpt,
15024        window: &mut Window,
15025        cx: &mut Context<Self>,
15026    ) {
15027        if matches!(self.mode, EditorMode::SingleLine) {
15028            cx.propagate();
15029            return;
15030        }
15031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15032        self.change_selections(Default::default(), window, cx, |s| {
15033            s.move_with(&mut |map, selection| {
15034                selection.collapse_to(
15035                    movement::end_of_excerpt(
15036                        map,
15037                        selection.head(),
15038                        workspace::searchable::Direction::Prev,
15039                    ),
15040                    SelectionGoal::None,
15041                )
15042            });
15043        })
15044    }
15045
15046    pub fn select_to_start_of_excerpt(
15047        &mut self,
15048        _: &SelectToStartOfExcerpt,
15049        window: &mut Window,
15050        cx: &mut Context<Self>,
15051    ) {
15052        if matches!(self.mode, EditorMode::SingleLine) {
15053            cx.propagate();
15054            return;
15055        }
15056        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15057        self.change_selections(Default::default(), window, cx, |s| {
15058            s.move_heads_with(&mut |map, head, _| {
15059                (
15060                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15061                    SelectionGoal::None,
15062                )
15063            });
15064        })
15065    }
15066
15067    pub fn select_to_start_of_next_excerpt(
15068        &mut self,
15069        _: &SelectToStartOfNextExcerpt,
15070        window: &mut Window,
15071        cx: &mut Context<Self>,
15072    ) {
15073        if matches!(self.mode, EditorMode::SingleLine) {
15074            cx.propagate();
15075            return;
15076        }
15077        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15078        self.change_selections(Default::default(), window, cx, |s| {
15079            s.move_heads_with(&mut |map, head, _| {
15080                (
15081                    movement::start_of_excerpt(map, head, workspace::searchable::Direction::Next),
15082                    SelectionGoal::None,
15083                )
15084            });
15085        })
15086    }
15087
15088    pub fn select_to_end_of_excerpt(
15089        &mut self,
15090        _: &SelectToEndOfExcerpt,
15091        window: &mut Window,
15092        cx: &mut Context<Self>,
15093    ) {
15094        if matches!(self.mode, EditorMode::SingleLine) {
15095            cx.propagate();
15096            return;
15097        }
15098        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15099        self.change_selections(Default::default(), window, cx, |s| {
15100            s.move_heads_with(&mut |map, head, _| {
15101                (
15102                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Next),
15103                    SelectionGoal::None,
15104                )
15105            });
15106        })
15107    }
15108
15109    pub fn select_to_end_of_previous_excerpt(
15110        &mut self,
15111        _: &SelectToEndOfPreviousExcerpt,
15112        window: &mut Window,
15113        cx: &mut Context<Self>,
15114    ) {
15115        if matches!(self.mode, EditorMode::SingleLine) {
15116            cx.propagate();
15117            return;
15118        }
15119        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15120        self.change_selections(Default::default(), window, cx, |s| {
15121            s.move_heads_with(&mut |map, head, _| {
15122                (
15123                    movement::end_of_excerpt(map, head, workspace::searchable::Direction::Prev),
15124                    SelectionGoal::None,
15125                )
15126            });
15127        })
15128    }
15129
15130    pub fn move_to_beginning(
15131        &mut self,
15132        _: &MoveToBeginning,
15133        window: &mut Window,
15134        cx: &mut Context<Self>,
15135    ) {
15136        if matches!(self.mode, EditorMode::SingleLine) {
15137            cx.propagate();
15138            return;
15139        }
15140        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15141        self.change_selections(Default::default(), window, cx, |s| {
15142            s.select_ranges(vec![Anchor::min()..Anchor::min()]);
15143        });
15144    }
15145
15146    pub fn select_to_beginning(
15147        &mut self,
15148        _: &SelectToBeginning,
15149        window: &mut Window,
15150        cx: &mut Context<Self>,
15151    ) {
15152        let mut selection = self.selections.last::<Point>(&self.display_snapshot(cx));
15153        selection.set_head(Point::zero(), SelectionGoal::None);
15154        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15155        self.change_selections(Default::default(), window, cx, |s| {
15156            s.select(vec![selection]);
15157        });
15158    }
15159
15160    pub fn move_to_end(&mut self, _: &MoveToEnd, window: &mut Window, cx: &mut Context<Self>) {
15161        if matches!(self.mode, EditorMode::SingleLine) {
15162            cx.propagate();
15163            return;
15164        }
15165        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15166        let cursor = self.buffer.read(cx).read(cx).len();
15167        self.change_selections(Default::default(), window, cx, |s| {
15168            s.select_ranges(vec![cursor..cursor])
15169        });
15170    }
15171
15172    pub fn set_nav_history(&mut self, nav_history: Option<ItemNavHistory>) {
15173        self.nav_history = nav_history;
15174    }
15175
15176    pub fn nav_history(&self) -> Option<&ItemNavHistory> {
15177        self.nav_history.as_ref()
15178    }
15179
15180    pub fn create_nav_history_entry(&mut self, cx: &mut Context<Self>) {
15181        self.push_to_nav_history(
15182            self.selections.newest_anchor().head(),
15183            None,
15184            false,
15185            true,
15186            cx,
15187        );
15188    }
15189
15190    fn navigation_data(&self, cursor_anchor: Anchor, cx: &mut Context<Self>) -> NavigationData {
15191        let display_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15192        let buffer = self.buffer.read(cx).read(cx);
15193        let cursor_position = cursor_anchor.to_point(&buffer);
15194        let scroll_anchor = self.scroll_manager.native_anchor(&display_snapshot, cx);
15195        let scroll_top_row = scroll_anchor.top_row(&buffer);
15196        drop(buffer);
15197
15198        NavigationData {
15199            cursor_anchor,
15200            cursor_position,
15201            scroll_anchor,
15202            scroll_top_row,
15203        }
15204    }
15205
15206    fn navigation_entry(
15207        &self,
15208        cursor_anchor: Anchor,
15209        cx: &mut Context<Self>,
15210    ) -> Option<NavigationEntry> {
15211        let Some(history) = self.nav_history.clone() else {
15212            return None;
15213        };
15214        let data = self.navigation_data(cursor_anchor, cx);
15215        Some(history.navigation_entry(Some(Arc::new(data) as Arc<dyn Any + Send + Sync>)))
15216    }
15217
15218    fn push_to_nav_history(
15219        &mut self,
15220        cursor_anchor: Anchor,
15221        new_position: Option<Point>,
15222        is_deactivate: bool,
15223        always: bool,
15224        cx: &mut Context<Self>,
15225    ) {
15226        let data = self.navigation_data(cursor_anchor, cx);
15227        if let Some(nav_history) = self.nav_history.as_mut() {
15228            if let Some(new_position) = new_position {
15229                let row_delta = (new_position.row as i64 - data.cursor_position.row as i64).abs();
15230                if row_delta == 0 || (row_delta < MIN_NAVIGATION_HISTORY_ROW_DELTA && !always) {
15231                    return;
15232                }
15233            }
15234
15235            nav_history.push(Some(data), cx);
15236            cx.emit(EditorEvent::PushedToNavHistory {
15237                anchor: cursor_anchor,
15238                is_deactivate,
15239            })
15240        }
15241    }
15242
15243    pub fn select_to_end(&mut self, _: &SelectToEnd, window: &mut Window, cx: &mut Context<Self>) {
15244        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15245        let buffer = self.buffer.read(cx).snapshot(cx);
15246        let mut selection = self
15247            .selections
15248            .first::<MultiBufferOffset>(&self.display_snapshot(cx));
15249        selection.set_head(buffer.len(), SelectionGoal::None);
15250        self.change_selections(Default::default(), window, cx, |s| {
15251            s.select(vec![selection]);
15252        });
15253    }
15254
15255    pub fn select_all(&mut self, _: &SelectAll, window: &mut Window, cx: &mut Context<Self>) {
15256        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15257        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15258            s.select_ranges([Anchor::min()..Anchor::max()]);
15259        });
15260    }
15261
15262    pub fn select_line(&mut self, _: &SelectLine, window: &mut Window, cx: &mut Context<Self>) {
15263        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15264        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15265        let mut selections = self.selections.all::<Point>(&display_map);
15266        let max_point = display_map.buffer_snapshot().max_point();
15267        for selection in &mut selections {
15268            let rows = selection.spanned_rows(true, &display_map);
15269            selection.start = Point::new(rows.start.0, 0);
15270            selection.end = cmp::min(max_point, Point::new(rows.end.0, 0));
15271            selection.reversed = false;
15272        }
15273        self.change_selections(Default::default(), window, cx, |s| {
15274            s.select(selections);
15275        });
15276    }
15277
15278    pub fn split_selection_into_lines(
15279        &mut self,
15280        action: &SplitSelectionIntoLines,
15281        window: &mut Window,
15282        cx: &mut Context<Self>,
15283    ) {
15284        let selections = self
15285            .selections
15286            .all::<Point>(&self.display_snapshot(cx))
15287            .into_iter()
15288            .map(|selection| selection.start..selection.end)
15289            .collect::<Vec<_>>();
15290        self.unfold_ranges(&selections, true, false, cx);
15291
15292        let mut new_selection_ranges = Vec::new();
15293        {
15294            let buffer = self.buffer.read(cx).read(cx);
15295            for selection in selections {
15296                for row in selection.start.row..selection.end.row {
15297                    let line_start = Point::new(row, 0);
15298                    let line_end = Point::new(row, buffer.line_len(MultiBufferRow(row)));
15299
15300                    if action.keep_selections {
15301                        // Keep the selection range for each line
15302                        let selection_start = if row == selection.start.row {
15303                            selection.start
15304                        } else {
15305                            line_start
15306                        };
15307                        new_selection_ranges.push(selection_start..line_end);
15308                    } else {
15309                        // Collapse to cursor at end of line
15310                        new_selection_ranges.push(line_end..line_end);
15311                    }
15312                }
15313
15314                let is_multiline_selection = selection.start.row != selection.end.row;
15315                // Don't insert last one if it's a multi-line selection ending at the start of a line,
15316                // so this action feels more ergonomic when paired with other selection operations
15317                let should_skip_last = is_multiline_selection && selection.end.column == 0;
15318                if !should_skip_last {
15319                    if action.keep_selections {
15320                        if is_multiline_selection {
15321                            let line_start = Point::new(selection.end.row, 0);
15322                            new_selection_ranges.push(line_start..selection.end);
15323                        } else {
15324                            new_selection_ranges.push(selection.start..selection.end);
15325                        }
15326                    } else {
15327                        new_selection_ranges.push(selection.end..selection.end);
15328                    }
15329                }
15330            }
15331        }
15332        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
15333            s.select_ranges(new_selection_ranges);
15334        });
15335    }
15336
15337    pub fn add_selection_above(
15338        &mut self,
15339        action: &AddSelectionAbove,
15340        window: &mut Window,
15341        cx: &mut Context<Self>,
15342    ) {
15343        self.add_selection(true, action.skip_soft_wrap, window, cx);
15344    }
15345
15346    pub fn add_selection_below(
15347        &mut self,
15348        action: &AddSelectionBelow,
15349        window: &mut Window,
15350        cx: &mut Context<Self>,
15351    ) {
15352        self.add_selection(false, action.skip_soft_wrap, window, cx);
15353    }
15354
15355    fn add_selection(
15356        &mut self,
15357        above: bool,
15358        skip_soft_wrap: bool,
15359        window: &mut Window,
15360        cx: &mut Context<Self>,
15361    ) {
15362        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15363
15364        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15365        let all_selections = self.selections.all::<Point>(&display_map);
15366        let text_layout_details = self.text_layout_details(window, cx);
15367
15368        let (mut columnar_selections, new_selections_to_columnarize) = {
15369            if let Some(state) = self.add_selections_state.as_ref() {
15370                let columnar_selection_ids: HashSet<_> = state
15371                    .groups
15372                    .iter()
15373                    .flat_map(|group| group.stack.iter())
15374                    .copied()
15375                    .collect();
15376
15377                all_selections
15378                    .into_iter()
15379                    .partition(|s| columnar_selection_ids.contains(&s.id))
15380            } else {
15381                (Vec::new(), all_selections)
15382            }
15383        };
15384
15385        let mut state = self
15386            .add_selections_state
15387            .take()
15388            .unwrap_or_else(|| AddSelectionsState { groups: Vec::new() });
15389
15390        for selection in new_selections_to_columnarize {
15391            let range = selection.display_range(&display_map).sorted();
15392            let start_x = display_map.x_for_display_point(range.start, &text_layout_details);
15393            let end_x = display_map.x_for_display_point(range.end, &text_layout_details);
15394            let positions = start_x.min(end_x)..start_x.max(end_x);
15395            let mut stack = Vec::new();
15396            for row in range.start.row().0..=range.end.row().0 {
15397                if let Some(selection) = self.selections.build_columnar_selection(
15398                    &display_map,
15399                    DisplayRow(row),
15400                    &positions,
15401                    selection.reversed,
15402                    &text_layout_details,
15403                ) {
15404                    stack.push(selection.id);
15405                    columnar_selections.push(selection);
15406                }
15407            }
15408            if !stack.is_empty() {
15409                if above {
15410                    stack.reverse();
15411                }
15412                state.groups.push(AddSelectionsGroup { above, stack });
15413            }
15414        }
15415
15416        let mut final_selections = Vec::new();
15417        let end_row = if above {
15418            DisplayRow(0)
15419        } else {
15420            display_map.max_point().row()
15421        };
15422
15423        // When `skip_soft_wrap` is true, we use buffer columns instead of pixel
15424        // positions to place new selections, so we need to keep track of the
15425        // column range of the oldest selection in each group, because
15426        // intermediate selections may have been clamped to shorter lines.
15427        // selections may have been clamped to shorter lines.
15428        let mut goal_columns_by_selection_id = if skip_soft_wrap {
15429            let mut map = HashMap::default();
15430            for group in state.groups.iter() {
15431                if let Some(oldest_id) = group.stack.first() {
15432                    if let Some(oldest_selection) =
15433                        columnar_selections.iter().find(|s| s.id == *oldest_id)
15434                    {
15435                        let start_col = oldest_selection.start.column;
15436                        let end_col = oldest_selection.end.column;
15437                        let goal_columns = start_col.min(end_col)..start_col.max(end_col);
15438                        for id in &group.stack {
15439                            map.insert(*id, goal_columns.clone());
15440                        }
15441                    }
15442                }
15443            }
15444            map
15445        } else {
15446            HashMap::default()
15447        };
15448
15449        let mut last_added_item_per_group = HashMap::default();
15450        for group in state.groups.iter_mut() {
15451            if let Some(last_id) = group.stack.last() {
15452                last_added_item_per_group.insert(*last_id, group);
15453            }
15454        }
15455
15456        for selection in columnar_selections {
15457            if let Some(group) = last_added_item_per_group.get_mut(&selection.id) {
15458                if above == group.above {
15459                    let range = selection.display_range(&display_map).sorted();
15460                    debug_assert_eq!(range.start.row(), range.end.row());
15461                    let row = range.start.row();
15462                    let positions =
15463                        if let SelectionGoal::HorizontalRange { start, end } = selection.goal {
15464                            Pixels::from(start)..Pixels::from(end)
15465                        } else {
15466                            let start_x =
15467                                display_map.x_for_display_point(range.start, &text_layout_details);
15468                            let end_x =
15469                                display_map.x_for_display_point(range.end, &text_layout_details);
15470                            start_x.min(end_x)..start_x.max(end_x)
15471                        };
15472
15473                    let maybe_new_selection = if skip_soft_wrap {
15474                        let goal_columns = goal_columns_by_selection_id
15475                            .remove(&selection.id)
15476                            .unwrap_or_else(|| {
15477                                let start_col = selection.start.column;
15478                                let end_col = selection.end.column;
15479                                start_col.min(end_col)..start_col.max(end_col)
15480                            });
15481                        self.selections.find_next_columnar_selection_by_buffer_row(
15482                            &display_map,
15483                            row,
15484                            end_row,
15485                            above,
15486                            &goal_columns,
15487                            selection.reversed,
15488                            &text_layout_details,
15489                        )
15490                    } else {
15491                        self.selections.find_next_columnar_selection_by_display_row(
15492                            &display_map,
15493                            row,
15494                            end_row,
15495                            above,
15496                            &positions,
15497                            selection.reversed,
15498                            &text_layout_details,
15499                        )
15500                    };
15501
15502                    if let Some(new_selection) = maybe_new_selection {
15503                        group.stack.push(new_selection.id);
15504                        if above {
15505                            final_selections.push(new_selection);
15506                            final_selections.push(selection);
15507                        } else {
15508                            final_selections.push(selection);
15509                            final_selections.push(new_selection);
15510                        }
15511                    } else {
15512                        final_selections.push(selection);
15513                    }
15514                } else {
15515                    group.stack.pop();
15516                }
15517            } else {
15518                final_selections.push(selection);
15519            }
15520        }
15521
15522        self.change_selections(Default::default(), window, cx, |s| {
15523            s.select(final_selections);
15524        });
15525
15526        let final_selection_ids: HashSet<_> = self
15527            .selections
15528            .all::<Point>(&display_map)
15529            .iter()
15530            .map(|s| s.id)
15531            .collect();
15532        state.groups.retain_mut(|group| {
15533            // selections might get merged above so we remove invalid items from stacks
15534            group.stack.retain(|id| final_selection_ids.contains(id));
15535
15536            // single selection in stack can be treated as initial state
15537            group.stack.len() > 1
15538        });
15539
15540        if !state.groups.is_empty() {
15541            self.add_selections_state = Some(state);
15542        }
15543    }
15544
15545    pub fn insert_snippet_at_selections(
15546        &mut self,
15547        action: &InsertSnippet,
15548        window: &mut Window,
15549        cx: &mut Context<Self>,
15550    ) {
15551        self.try_insert_snippet_at_selections(action, window, cx)
15552            .log_err();
15553    }
15554
15555    fn try_insert_snippet_at_selections(
15556        &mut self,
15557        action: &InsertSnippet,
15558        window: &mut Window,
15559        cx: &mut Context<Self>,
15560    ) -> Result<()> {
15561        let insertion_ranges = self
15562            .selections
15563            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
15564            .into_iter()
15565            .map(|selection| selection.range())
15566            .collect_vec();
15567
15568        let snippet = if let Some(snippet_body) = &action.snippet {
15569            if action.language.is_none() && action.name.is_none() {
15570                Snippet::parse(snippet_body)?
15571            } else {
15572                bail!("`snippet` is mutually exclusive with `language` and `name`")
15573            }
15574        } else if let Some(name) = &action.name {
15575            let project = self.project().context("no project")?;
15576            let snippet_store = project.read(cx).snippets().read(cx);
15577            let snippet = snippet_store
15578                .snippets_for(action.language.clone(), cx)
15579                .into_iter()
15580                .find(|snippet| snippet.name == *name)
15581                .context("snippet not found")?;
15582            Snippet::parse(&snippet.body)?
15583        } else {
15584            // todo(andrew): open modal to select snippet
15585            bail!("`name` or `snippet` is required")
15586        };
15587
15588        self.insert_snippet(&insertion_ranges, snippet, window, cx)
15589    }
15590
15591    fn select_match_ranges(
15592        &mut self,
15593        range: Range<MultiBufferOffset>,
15594        reversed: bool,
15595        replace_newest: bool,
15596        auto_scroll: Option<Autoscroll>,
15597        window: &mut Window,
15598        cx: &mut Context<Editor>,
15599    ) {
15600        self.unfold_ranges(
15601            std::slice::from_ref(&range),
15602            false,
15603            auto_scroll.is_some(),
15604            cx,
15605        );
15606        let effects = if let Some(scroll) = auto_scroll {
15607            SelectionEffects::scroll(scroll)
15608        } else {
15609            SelectionEffects::no_scroll()
15610        };
15611        self.change_selections(effects, window, cx, |s| {
15612            if replace_newest {
15613                s.delete(s.newest_anchor().id);
15614            }
15615            if reversed {
15616                s.insert_range(range.end..range.start);
15617            } else {
15618                s.insert_range(range);
15619            }
15620        });
15621    }
15622
15623    pub fn select_next_match_internal(
15624        &mut self,
15625        display_map: &DisplaySnapshot,
15626        replace_newest: bool,
15627        autoscroll: Option<Autoscroll>,
15628        window: &mut Window,
15629        cx: &mut Context<Self>,
15630    ) -> Result<()> {
15631        let buffer = display_map.buffer_snapshot();
15632        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15633        if let Some(mut select_next_state) = self.select_next_state.take() {
15634            let query = &select_next_state.query;
15635            if !select_next_state.done {
15636                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15637                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15638                let mut next_selected_range = None;
15639
15640                let bytes_after_last_selection =
15641                    buffer.bytes_in_range(last_selection.end..buffer.len());
15642                let bytes_before_first_selection =
15643                    buffer.bytes_in_range(MultiBufferOffset(0)..first_selection.start);
15644                let query_matches = query
15645                    .stream_find_iter(bytes_after_last_selection)
15646                    .map(|result| (last_selection.end, result))
15647                    .chain(
15648                        query
15649                            .stream_find_iter(bytes_before_first_selection)
15650                            .map(|result| (MultiBufferOffset(0), result)),
15651                    );
15652
15653                for (start_offset, query_match) in query_matches {
15654                    let query_match = query_match.unwrap(); // can only fail due to I/O
15655                    let offset_range =
15656                        start_offset + query_match.start()..start_offset + query_match.end();
15657
15658                    if !select_next_state.wordwise
15659                        || (!buffer.is_inside_word(offset_range.start, None)
15660                            && !buffer.is_inside_word(offset_range.end, None))
15661                    {
15662                        let idx = selections
15663                            .partition_point(|selection| selection.end <= offset_range.start);
15664                        let overlaps = selections
15665                            .get(idx)
15666                            .map_or(false, |selection| selection.start < offset_range.end);
15667
15668                        if !overlaps {
15669                            next_selected_range = Some(offset_range);
15670                            break;
15671                        }
15672                    }
15673                }
15674
15675                if let Some(next_selected_range) = next_selected_range {
15676                    self.select_match_ranges(
15677                        next_selected_range,
15678                        last_selection.reversed,
15679                        replace_newest,
15680                        autoscroll,
15681                        window,
15682                        cx,
15683                    );
15684                } else {
15685                    select_next_state.done = true;
15686                }
15687            }
15688
15689            self.select_next_state = Some(select_next_state);
15690        } else {
15691            let mut only_carets = true;
15692            let mut same_text_selected = true;
15693            let mut selected_text = None;
15694
15695            let mut selections_iter = selections.iter().peekable();
15696            while let Some(selection) = selections_iter.next() {
15697                if selection.start != selection.end {
15698                    only_carets = false;
15699                }
15700
15701                if same_text_selected {
15702                    if selected_text.is_none() {
15703                        selected_text =
15704                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15705                    }
15706
15707                    if let Some(next_selection) = selections_iter.peek() {
15708                        if next_selection.len() == selection.len() {
15709                            let next_selected_text = buffer
15710                                .text_for_range(next_selection.range())
15711                                .collect::<String>();
15712                            if Some(next_selected_text) != selected_text {
15713                                same_text_selected = false;
15714                                selected_text = None;
15715                            }
15716                        } else {
15717                            same_text_selected = false;
15718                            selected_text = None;
15719                        }
15720                    }
15721                }
15722            }
15723
15724            if only_carets {
15725                for selection in &mut selections {
15726                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15727                    selection.start = word_range.start;
15728                    selection.end = word_range.end;
15729                    selection.goal = SelectionGoal::None;
15730                    selection.reversed = false;
15731                    self.select_match_ranges(
15732                        selection.start..selection.end,
15733                        selection.reversed,
15734                        replace_newest,
15735                        autoscroll,
15736                        window,
15737                        cx,
15738                    );
15739                }
15740
15741                if selections.len() == 1 {
15742                    let selection = selections
15743                        .last()
15744                        .expect("ensured that there's only one selection");
15745                    let query = buffer
15746                        .text_for_range(selection.start..selection.end)
15747                        .collect::<String>();
15748                    let is_empty = query.is_empty();
15749                    let select_state = SelectNextState {
15750                        query: self.build_query(&[query], cx)?,
15751                        wordwise: true,
15752                        done: is_empty,
15753                    };
15754                    self.select_next_state = Some(select_state);
15755                } else {
15756                    self.select_next_state = None;
15757                }
15758            } else if let Some(selected_text) = selected_text {
15759                self.select_next_state = Some(SelectNextState {
15760                    query: self.build_query(&[selected_text], cx)?,
15761                    wordwise: false,
15762                    done: false,
15763                });
15764                self.select_next_match_internal(
15765                    display_map,
15766                    replace_newest,
15767                    autoscroll,
15768                    window,
15769                    cx,
15770                )?;
15771            }
15772        }
15773        Ok(())
15774    }
15775
15776    pub fn select_all_matches(
15777        &mut self,
15778        _action: &SelectAllMatches,
15779        window: &mut Window,
15780        cx: &mut Context<Self>,
15781    ) -> Result<()> {
15782        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15783
15784        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15785
15786        self.select_next_match_internal(&display_map, false, None, window, cx)?;
15787        let Some(select_next_state) = self.select_next_state.as_mut().filter(|state| !state.done)
15788        else {
15789            return Ok(());
15790        };
15791
15792        let mut new_selections = Vec::new();
15793
15794        let reversed = self
15795            .selections
15796            .oldest::<MultiBufferOffset>(&display_map)
15797            .reversed;
15798        let buffer = display_map.buffer_snapshot();
15799        let query_matches = select_next_state
15800            .query
15801            .stream_find_iter(buffer.bytes_in_range(MultiBufferOffset(0)..buffer.len()));
15802
15803        for query_match in query_matches.into_iter() {
15804            let query_match = query_match.context("query match for select all action")?; // can only fail due to I/O
15805            let offset_range = if reversed {
15806                MultiBufferOffset(query_match.end())..MultiBufferOffset(query_match.start())
15807            } else {
15808                MultiBufferOffset(query_match.start())..MultiBufferOffset(query_match.end())
15809            };
15810
15811            if !select_next_state.wordwise
15812                || (!buffer.is_inside_word(offset_range.start, None)
15813                    && !buffer.is_inside_word(offset_range.end, None))
15814            {
15815                new_selections.push(offset_range.start..offset_range.end);
15816            }
15817        }
15818
15819        select_next_state.done = true;
15820
15821        if new_selections.is_empty() {
15822            log::error!("bug: new_selections is empty in select_all_matches");
15823            return Ok(());
15824        }
15825
15826        self.unfold_ranges(&new_selections, false, false, cx);
15827        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
15828            selections.select_ranges(new_selections)
15829        });
15830
15831        Ok(())
15832    }
15833
15834    pub fn select_next(
15835        &mut self,
15836        action: &SelectNext,
15837        window: &mut Window,
15838        cx: &mut Context<Self>,
15839    ) -> Result<()> {
15840        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15841        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15842        self.select_next_match_internal(
15843            &display_map,
15844            action.replace_newest,
15845            Some(Autoscroll::newest()),
15846            window,
15847            cx,
15848        )
15849    }
15850
15851    pub fn select_previous(
15852        &mut self,
15853        action: &SelectPrevious,
15854        window: &mut Window,
15855        cx: &mut Context<Self>,
15856    ) -> Result<()> {
15857        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
15858        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
15859        let buffer = display_map.buffer_snapshot();
15860        let mut selections = self.selections.all::<MultiBufferOffset>(&display_map);
15861        if let Some(mut select_prev_state) = self.select_prev_state.take() {
15862            let query = &select_prev_state.query;
15863            if !select_prev_state.done {
15864                let first_selection = selections.iter().min_by_key(|s| s.id).unwrap();
15865                let last_selection = selections.iter().max_by_key(|s| s.id).unwrap();
15866                let mut next_selected_range = None;
15867                // When we're iterating matches backwards, the oldest match will actually be the furthest one in the buffer.
15868                let bytes_before_last_selection =
15869                    buffer.reversed_bytes_in_range(MultiBufferOffset(0)..last_selection.start);
15870                let bytes_after_first_selection =
15871                    buffer.reversed_bytes_in_range(first_selection.end..buffer.len());
15872                let query_matches = query
15873                    .stream_find_iter(bytes_before_last_selection)
15874                    .map(|result| (last_selection.start, result))
15875                    .chain(
15876                        query
15877                            .stream_find_iter(bytes_after_first_selection)
15878                            .map(|result| (buffer.len(), result)),
15879                    );
15880                for (end_offset, query_match) in query_matches {
15881                    let query_match = query_match.unwrap(); // can only fail due to I/O
15882                    let offset_range =
15883                        end_offset - query_match.end()..end_offset - query_match.start();
15884
15885                    if !select_prev_state.wordwise
15886                        || (!buffer.is_inside_word(offset_range.start, None)
15887                            && !buffer.is_inside_word(offset_range.end, None))
15888                    {
15889                        next_selected_range = Some(offset_range);
15890                        break;
15891                    }
15892                }
15893
15894                if let Some(next_selected_range) = next_selected_range {
15895                    self.select_match_ranges(
15896                        next_selected_range,
15897                        last_selection.reversed,
15898                        action.replace_newest,
15899                        Some(Autoscroll::newest()),
15900                        window,
15901                        cx,
15902                    );
15903                } else {
15904                    select_prev_state.done = true;
15905                }
15906            }
15907
15908            self.select_prev_state = Some(select_prev_state);
15909        } else {
15910            let mut only_carets = true;
15911            let mut same_text_selected = true;
15912            let mut selected_text = None;
15913
15914            let mut selections_iter = selections.iter().peekable();
15915            while let Some(selection) = selections_iter.next() {
15916                if selection.start != selection.end {
15917                    only_carets = false;
15918                }
15919
15920                if same_text_selected {
15921                    if selected_text.is_none() {
15922                        selected_text =
15923                            Some(buffer.text_for_range(selection.range()).collect::<String>());
15924                    }
15925
15926                    if let Some(next_selection) = selections_iter.peek() {
15927                        if next_selection.len() == selection.len() {
15928                            let next_selected_text = buffer
15929                                .text_for_range(next_selection.range())
15930                                .collect::<String>();
15931                            if Some(next_selected_text) != selected_text {
15932                                same_text_selected = false;
15933                                selected_text = None;
15934                            }
15935                        } else {
15936                            same_text_selected = false;
15937                            selected_text = None;
15938                        }
15939                    }
15940                }
15941            }
15942
15943            if only_carets {
15944                for selection in &mut selections {
15945                    let (word_range, _) = buffer.surrounding_word(selection.start, None);
15946                    selection.start = word_range.start;
15947                    selection.end = word_range.end;
15948                    selection.goal = SelectionGoal::None;
15949                    selection.reversed = false;
15950                    self.select_match_ranges(
15951                        selection.start..selection.end,
15952                        selection.reversed,
15953                        action.replace_newest,
15954                        Some(Autoscroll::newest()),
15955                        window,
15956                        cx,
15957                    );
15958                }
15959                if selections.len() == 1 {
15960                    let selection = selections
15961                        .last()
15962                        .expect("ensured that there's only one selection");
15963                    let query = buffer
15964                        .text_for_range(selection.start..selection.end)
15965                        .collect::<String>();
15966                    let is_empty = query.is_empty();
15967                    let select_state = SelectNextState {
15968                        query: self.build_query(&[query.chars().rev().collect::<String>()], cx)?,
15969                        wordwise: true,
15970                        done: is_empty,
15971                    };
15972                    self.select_prev_state = Some(select_state);
15973                } else {
15974                    self.select_prev_state = None;
15975                }
15976            } else if let Some(selected_text) = selected_text {
15977                self.select_prev_state = Some(SelectNextState {
15978                    query: self
15979                        .build_query(&[selected_text.chars().rev().collect::<String>()], cx)?,
15980                    wordwise: false,
15981                    done: false,
15982                });
15983                self.select_previous(action, window, cx)?;
15984            }
15985        }
15986        Ok(())
15987    }
15988
15989    /// Builds an `AhoCorasick` automaton from the provided patterns, while
15990    /// setting the case sensitivity based on the global
15991    /// `SelectNextCaseSensitive` setting, if set, otherwise based on the
15992    /// editor's settings.
15993    fn build_query<I, P>(&self, patterns: I, cx: &Context<Self>) -> Result<AhoCorasick, BuildError>
15994    where
15995        I: IntoIterator<Item = P>,
15996        P: AsRef<[u8]>,
15997    {
15998        let case_sensitive = self
15999            .select_next_is_case_sensitive
16000            .unwrap_or_else(|| EditorSettings::get_global(cx).search.case_sensitive);
16001
16002        let mut builder = AhoCorasickBuilder::new();
16003        builder.ascii_case_insensitive(!case_sensitive);
16004        builder.build(patterns)
16005    }
16006
16007    pub fn find_next_match(
16008        &mut self,
16009        _: &FindNextMatch,
16010        window: &mut Window,
16011        cx: &mut Context<Self>,
16012    ) -> Result<()> {
16013        let selections = self.selections.disjoint_anchors_arc();
16014        match selections.first() {
16015            Some(first) if selections.len() >= 2 => {
16016                self.change_selections(Default::default(), window, cx, |s| {
16017                    s.select_ranges([first.range()]);
16018                });
16019            }
16020            _ => self.select_next(
16021                &SelectNext {
16022                    replace_newest: true,
16023                },
16024                window,
16025                cx,
16026            )?,
16027        }
16028        Ok(())
16029    }
16030
16031    pub fn find_previous_match(
16032        &mut self,
16033        _: &FindPreviousMatch,
16034        window: &mut Window,
16035        cx: &mut Context<Self>,
16036    ) -> Result<()> {
16037        let selections = self.selections.disjoint_anchors_arc();
16038        match selections.last() {
16039            Some(last) if selections.len() >= 2 => {
16040                self.change_selections(Default::default(), window, cx, |s| {
16041                    s.select_ranges([last.range()]);
16042                });
16043            }
16044            _ => self.select_previous(
16045                &SelectPrevious {
16046                    replace_newest: true,
16047                },
16048                window,
16049                cx,
16050            )?,
16051        }
16052        Ok(())
16053    }
16054
16055    pub fn toggle_comments(
16056        &mut self,
16057        action: &ToggleComments,
16058        window: &mut Window,
16059        cx: &mut Context<Self>,
16060    ) {
16061        if self.read_only(cx) {
16062            return;
16063        }
16064        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
16065        let text_layout_details = &self.text_layout_details(window, cx);
16066        self.transact(window, cx, |this, window, cx| {
16067            let mut selections = this
16068                .selections
16069                .all::<MultiBufferPoint>(&this.display_snapshot(cx));
16070            let mut edits = Vec::new();
16071            let mut selection_edit_ranges = Vec::new();
16072            let mut last_toggled_row = None;
16073            let snapshot = this.buffer.read(cx).read(cx);
16074            let empty_str: Arc<str> = Arc::default();
16075            let mut suffixes_inserted = Vec::new();
16076            let ignore_indent = action.ignore_indent;
16077
16078            fn comment_prefix_range(
16079                snapshot: &MultiBufferSnapshot,
16080                row: MultiBufferRow,
16081                comment_prefix: &str,
16082                comment_prefix_whitespace: &str,
16083                ignore_indent: bool,
16084            ) -> Range<Point> {
16085                let indent_size = if ignore_indent {
16086                    0
16087                } else {
16088                    snapshot.indent_size_for_line(row).len
16089                };
16090
16091                let start = Point::new(row.0, indent_size);
16092
16093                let mut line_bytes = snapshot
16094                    .bytes_in_range(start..snapshot.max_point())
16095                    .flatten()
16096                    .copied();
16097
16098                // If this line currently begins with the line comment prefix, then record
16099                // the range containing the prefix.
16100                if line_bytes
16101                    .by_ref()
16102                    .take(comment_prefix.len())
16103                    .eq(comment_prefix.bytes())
16104                {
16105                    // Include any whitespace that matches the comment prefix.
16106                    let matching_whitespace_len = line_bytes
16107                        .zip(comment_prefix_whitespace.bytes())
16108                        .take_while(|(a, b)| a == b)
16109                        .count() as u32;
16110                    let end = Point::new(
16111                        start.row,
16112                        start.column + comment_prefix.len() as u32 + matching_whitespace_len,
16113                    );
16114                    start..end
16115                } else {
16116                    start..start
16117                }
16118            }
16119
16120            fn comment_suffix_range(
16121                snapshot: &MultiBufferSnapshot,
16122                row: MultiBufferRow,
16123                comment_suffix: &str,
16124                comment_suffix_has_leading_space: bool,
16125            ) -> Range<Point> {
16126                let end = Point::new(row.0, snapshot.line_len(row));
16127                let suffix_start_column = end.column.saturating_sub(comment_suffix.len() as u32);
16128
16129                let mut line_end_bytes = snapshot
16130                    .bytes_in_range(Point::new(end.row, suffix_start_column.saturating_sub(1))..end)
16131                    .flatten()
16132                    .copied();
16133
16134                let leading_space_len = if suffix_start_column > 0
16135                    && line_end_bytes.next() == Some(b' ')
16136                    && comment_suffix_has_leading_space
16137                {
16138                    1
16139                } else {
16140                    0
16141                };
16142
16143                // If this line currently begins with the line comment prefix, then record
16144                // the range containing the prefix.
16145                if line_end_bytes.by_ref().eq(comment_suffix.bytes()) {
16146                    let start = Point::new(end.row, suffix_start_column - leading_space_len);
16147                    start..end
16148                } else {
16149                    end..end
16150                }
16151            }
16152
16153            // TODO: Handle selections that cross excerpts
16154            for selection in &mut selections {
16155                let start_column = snapshot
16156                    .indent_size_for_line(MultiBufferRow(selection.start.row))
16157                    .len;
16158                let language = if let Some(language) =
16159                    snapshot.language_scope_at(Point::new(selection.start.row, start_column))
16160                {
16161                    language
16162                } else {
16163                    continue;
16164                };
16165
16166                selection_edit_ranges.clear();
16167
16168                // If multiple selections contain a given row, avoid processing that
16169                // row more than once.
16170                let mut start_row = MultiBufferRow(selection.start.row);
16171                if last_toggled_row == Some(start_row) {
16172                    start_row = start_row.next_row();
16173                }
16174                let end_row =
16175                    if selection.end.row > selection.start.row && selection.end.column == 0 {
16176                        MultiBufferRow(selection.end.row - 1)
16177                    } else {
16178                        MultiBufferRow(selection.end.row)
16179                    };
16180                last_toggled_row = Some(end_row);
16181
16182                if start_row > end_row {
16183                    continue;
16184                }
16185
16186                // If the language has line comments, toggle those.
16187                let mut full_comment_prefixes = language.line_comment_prefixes().to_vec();
16188
16189                // If ignore_indent is set, trim spaces from the right side of all full_comment_prefixes
16190                if ignore_indent {
16191                    full_comment_prefixes = full_comment_prefixes
16192                        .into_iter()
16193                        .map(|s| Arc::from(s.trim_end()))
16194                        .collect();
16195                }
16196
16197                if !full_comment_prefixes.is_empty() {
16198                    let first_prefix = full_comment_prefixes
16199                        .first()
16200                        .expect("prefixes is non-empty");
16201                    let prefix_trimmed_lengths = full_comment_prefixes
16202                        .iter()
16203                        .map(|p| p.trim_end_matches(' ').len())
16204                        .collect::<SmallVec<[usize; 4]>>();
16205
16206                    let mut all_selection_lines_are_comments = true;
16207
16208                    for row in start_row.0..=end_row.0 {
16209                        let row = MultiBufferRow(row);
16210                        if start_row < end_row && snapshot.is_line_blank(row) {
16211                            continue;
16212                        }
16213
16214                        let prefix_range = full_comment_prefixes
16215                            .iter()
16216                            .zip(prefix_trimmed_lengths.iter().copied())
16217                            .map(|(prefix, trimmed_prefix_len)| {
16218                                comment_prefix_range(
16219                                    snapshot.deref(),
16220                                    row,
16221                                    &prefix[..trimmed_prefix_len],
16222                                    &prefix[trimmed_prefix_len..],
16223                                    ignore_indent,
16224                                )
16225                            })
16226                            .max_by_key(|range| range.end.column - range.start.column)
16227                            .expect("prefixes is non-empty");
16228
16229                        if prefix_range.is_empty() {
16230                            all_selection_lines_are_comments = false;
16231                        }
16232
16233                        selection_edit_ranges.push(prefix_range);
16234                    }
16235
16236                    if all_selection_lines_are_comments {
16237                        edits.extend(
16238                            selection_edit_ranges
16239                                .iter()
16240                                .cloned()
16241                                .map(|range| (range, empty_str.clone())),
16242                        );
16243                    } else {
16244                        let min_column = selection_edit_ranges
16245                            .iter()
16246                            .map(|range| range.start.column)
16247                            .min()
16248                            .unwrap_or(0);
16249                        edits.extend(selection_edit_ranges.iter().map(|range| {
16250                            let position = Point::new(range.start.row, min_column);
16251                            (position..position, first_prefix.clone())
16252                        }));
16253                    }
16254                } else if let Some(BlockCommentConfig {
16255                    start: full_comment_prefix,
16256                    end: comment_suffix,
16257                    ..
16258                }) = language.block_comment()
16259                {
16260                    let comment_prefix = full_comment_prefix.trim_end_matches(' ');
16261                    let comment_prefix_whitespace = &full_comment_prefix[comment_prefix.len()..];
16262                    let prefix_range = comment_prefix_range(
16263                        snapshot.deref(),
16264                        start_row,
16265                        comment_prefix,
16266                        comment_prefix_whitespace,
16267                        ignore_indent,
16268                    );
16269                    let suffix_range = comment_suffix_range(
16270                        snapshot.deref(),
16271                        end_row,
16272                        comment_suffix.trim_start_matches(' '),
16273                        comment_suffix.starts_with(' '),
16274                    );
16275
16276                    if prefix_range.is_empty() || suffix_range.is_empty() {
16277                        edits.push((
16278                            prefix_range.start..prefix_range.start,
16279                            full_comment_prefix.clone(),
16280                        ));
16281                        edits.push((suffix_range.end..suffix_range.end, comment_suffix.clone()));
16282                        suffixes_inserted.push((end_row, comment_suffix.len()));
16283                    } else {
16284                        edits.push((prefix_range, empty_str.clone()));
16285                        edits.push((suffix_range, empty_str.clone()));
16286                    }
16287                } else {
16288                    continue;
16289                }
16290            }
16291
16292            drop(snapshot);
16293            this.buffer.update(cx, |buffer, cx| {
16294                buffer.edit(edits, None, cx);
16295            });
16296
16297            // Adjust selections so that they end before any comment suffixes that
16298            // were inserted.
16299            let mut suffixes_inserted = suffixes_inserted.into_iter().peekable();
16300            let mut selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16301            let snapshot = this.buffer.read(cx).read(cx);
16302            for selection in &mut selections {
16303                while let Some((row, suffix_len)) = suffixes_inserted.peek().copied() {
16304                    match row.cmp(&MultiBufferRow(selection.end.row)) {
16305                        Ordering::Less => {
16306                            suffixes_inserted.next();
16307                            continue;
16308                        }
16309                        Ordering::Greater => break,
16310                        Ordering::Equal => {
16311                            if selection.end.column == snapshot.line_len(row) {
16312                                if selection.is_empty() {
16313                                    selection.start.column -= suffix_len as u32;
16314                                }
16315                                selection.end.column -= suffix_len as u32;
16316                            }
16317                            break;
16318                        }
16319                    }
16320                }
16321            }
16322
16323            drop(snapshot);
16324            this.change_selections(Default::default(), window, cx, |s| s.select(selections));
16325
16326            let selections = this.selections.all::<Point>(&this.display_snapshot(cx));
16327            let selections_on_single_row = selections.windows(2).all(|selections| {
16328                selections[0].start.row == selections[1].start.row
16329                    && selections[0].end.row == selections[1].end.row
16330                    && selections[0].start.row == selections[0].end.row
16331            });
16332            let selections_selecting = selections
16333                .iter()
16334                .any(|selection| selection.start != selection.end);
16335            let advance_downwards = action.advance_downwards
16336                && selections_on_single_row
16337                && !selections_selecting
16338                && !matches!(this.mode, EditorMode::SingleLine);
16339
16340            if advance_downwards {
16341                let snapshot = this.buffer.read(cx).snapshot(cx);
16342
16343                this.change_selections(Default::default(), window, cx, |s| {
16344                    s.move_cursors_with(&mut |display_snapshot, display_point, _| {
16345                        let mut point = display_point.to_point(display_snapshot);
16346                        point.row += 1;
16347                        point = snapshot.clip_point(point, Bias::Left);
16348                        let display_point = point.to_display_point(display_snapshot);
16349                        let goal = SelectionGoal::HorizontalPosition(
16350                            display_snapshot
16351                                .x_for_display_point(display_point, text_layout_details)
16352                                .into(),
16353                        );
16354                        (display_point, goal)
16355                    })
16356                });
16357            }
16358        });
16359    }
16360
16361    pub fn select_enclosing_symbol(
16362        &mut self,
16363        _: &SelectEnclosingSymbol,
16364        window: &mut Window,
16365        cx: &mut Context<Self>,
16366    ) {
16367        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16368
16369        let buffer = self.buffer.read(cx).snapshot(cx);
16370        let old_selections = self
16371            .selections
16372            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16373            .into_boxed_slice();
16374
16375        fn update_selection(
16376            selection: &Selection<MultiBufferOffset>,
16377            buffer_snap: &MultiBufferSnapshot,
16378        ) -> Option<Selection<MultiBufferOffset>> {
16379            let cursor = selection.head();
16380            let (_buffer_id, symbols) = buffer_snap.symbols_containing(cursor, None)?;
16381            for symbol in symbols.iter().rev() {
16382                let start = symbol.range.start.to_offset(buffer_snap);
16383                let end = symbol.range.end.to_offset(buffer_snap);
16384                let new_range = start..end;
16385                if start < selection.start || end > selection.end {
16386                    return Some(Selection {
16387                        id: selection.id,
16388                        start: new_range.start,
16389                        end: new_range.end,
16390                        goal: SelectionGoal::None,
16391                        reversed: selection.reversed,
16392                    });
16393                }
16394            }
16395            None
16396        }
16397
16398        let mut selected_larger_symbol = false;
16399        let new_selections = old_selections
16400            .iter()
16401            .map(|selection| match update_selection(selection, &buffer) {
16402                Some(new_selection) => {
16403                    if new_selection.range() != selection.range() {
16404                        selected_larger_symbol = true;
16405                    }
16406                    new_selection
16407                }
16408                None => selection.clone(),
16409            })
16410            .collect::<Vec<_>>();
16411
16412        if selected_larger_symbol {
16413            self.change_selections(Default::default(), window, cx, |s| {
16414                s.select(new_selections);
16415            });
16416        }
16417    }
16418
16419    pub fn select_larger_syntax_node(
16420        &mut self,
16421        _: &SelectLargerSyntaxNode,
16422        window: &mut Window,
16423        cx: &mut Context<Self>,
16424    ) {
16425        let Some(visible_row_count) = self.visible_row_count() else {
16426            return;
16427        };
16428        let old_selections: Box<[_]> = self
16429            .selections
16430            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16431            .into();
16432        if old_selections.is_empty() {
16433            return;
16434        }
16435
16436        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16437
16438        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16439        let buffer = self.buffer.read(cx).snapshot(cx);
16440
16441        let mut selected_larger_node = false;
16442        let mut new_selections = old_selections
16443            .iter()
16444            .map(|selection| {
16445                let old_range = selection.start..selection.end;
16446
16447                if let Some((node, _)) = buffer.syntax_ancestor(old_range.clone()) {
16448                    // manually select word at selection
16449                    if ["string_content", "inline"].contains(&node.kind()) {
16450                        let (word_range, _) = buffer.surrounding_word(old_range.start, None);
16451                        // ignore if word is already selected
16452                        if !word_range.is_empty() && old_range != word_range {
16453                            let (last_word_range, _) = buffer.surrounding_word(old_range.end, None);
16454                            // only select word if start and end point belongs to same word
16455                            if word_range == last_word_range {
16456                                selected_larger_node = true;
16457                                return Selection {
16458                                    id: selection.id,
16459                                    start: word_range.start,
16460                                    end: word_range.end,
16461                                    goal: SelectionGoal::None,
16462                                    reversed: selection.reversed,
16463                                };
16464                            }
16465                        }
16466                    }
16467                }
16468
16469                let mut new_range = old_range.clone();
16470                while let Some((node, range)) = buffer.syntax_ancestor(new_range.clone()) {
16471                    new_range = range;
16472                    if !node.is_named() {
16473                        continue;
16474                    }
16475                    if !display_map.intersects_fold(new_range.start)
16476                        && !display_map.intersects_fold(new_range.end)
16477                    {
16478                        break;
16479                    }
16480                }
16481
16482                selected_larger_node |= new_range != old_range;
16483                Selection {
16484                    id: selection.id,
16485                    start: new_range.start,
16486                    end: new_range.end,
16487                    goal: SelectionGoal::None,
16488                    reversed: selection.reversed,
16489                }
16490            })
16491            .collect::<Vec<_>>();
16492
16493        if !selected_larger_node {
16494            return; // don't put this call in the history
16495        }
16496
16497        // scroll based on transformation done to the last selection created by the user
16498        let (last_old, last_new) = old_selections
16499            .last()
16500            .zip(new_selections.last().cloned())
16501            .expect("old_selections isn't empty");
16502
16503        // revert selection
16504        let is_selection_reversed = {
16505            let should_newest_selection_be_reversed = last_old.start != last_new.start;
16506            new_selections.last_mut().expect("checked above").reversed =
16507                should_newest_selection_be_reversed;
16508            should_newest_selection_be_reversed
16509        };
16510
16511        if selected_larger_node {
16512            self.select_syntax_node_history.disable_clearing = true;
16513            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16514                s.select(new_selections.clone());
16515            });
16516            self.select_syntax_node_history.disable_clearing = false;
16517        }
16518
16519        let start_row = last_new.start.to_display_point(&display_map).row().0;
16520        let end_row = last_new.end.to_display_point(&display_map).row().0;
16521        let selection_height = end_row - start_row + 1;
16522        let scroll_margin_rows = self.vertical_scroll_margin() as u32;
16523
16524        let fits_on_the_screen = visible_row_count >= selection_height + scroll_margin_rows * 2;
16525        let scroll_behavior = if fits_on_the_screen {
16526            self.request_autoscroll(Autoscroll::fit(), cx);
16527            SelectSyntaxNodeScrollBehavior::FitSelection
16528        } else if is_selection_reversed {
16529            self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16530            SelectSyntaxNodeScrollBehavior::CursorTop
16531        } else {
16532            self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16533            SelectSyntaxNodeScrollBehavior::CursorBottom
16534        };
16535
16536        let old_selections: Box<[Selection<Anchor>]> = old_selections
16537            .iter()
16538            .map(|s| s.map(|offset| buffer.anchor_before(offset)))
16539            .collect();
16540        self.select_syntax_node_history.push((
16541            old_selections,
16542            scroll_behavior,
16543            is_selection_reversed,
16544        ));
16545    }
16546
16547    pub fn select_smaller_syntax_node(
16548        &mut self,
16549        _: &SelectSmallerSyntaxNode,
16550        window: &mut Window,
16551        cx: &mut Context<Self>,
16552    ) {
16553        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16554
16555        if let Some((mut selections, scroll_behavior, is_selection_reversed)) =
16556            self.select_syntax_node_history.pop()
16557        {
16558            if let Some(selection) = selections.last_mut() {
16559                selection.reversed = is_selection_reversed;
16560            }
16561
16562            let snapshot = self.buffer.read(cx).snapshot(cx);
16563            let selections: Vec<Selection<MultiBufferOffset>> = selections
16564                .iter()
16565                .map(|s| s.map(|anchor| anchor.to_offset(&snapshot)))
16566                .collect();
16567
16568            self.select_syntax_node_history.disable_clearing = true;
16569            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
16570                s.select(selections);
16571            });
16572            self.select_syntax_node_history.disable_clearing = false;
16573
16574            match scroll_behavior {
16575                SelectSyntaxNodeScrollBehavior::CursorTop => {
16576                    self.scroll_cursor_top(&ScrollCursorTop, window, cx);
16577                }
16578                SelectSyntaxNodeScrollBehavior::FitSelection => {
16579                    self.request_autoscroll(Autoscroll::fit(), cx);
16580                }
16581                SelectSyntaxNodeScrollBehavior::CursorBottom => {
16582                    self.scroll_cursor_bottom(&ScrollCursorBottom, window, cx);
16583                }
16584            }
16585        }
16586    }
16587
16588    pub fn unwrap_syntax_node(
16589        &mut self,
16590        _: &UnwrapSyntaxNode,
16591        window: &mut Window,
16592        cx: &mut Context<Self>,
16593    ) {
16594        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16595
16596        let buffer = self.buffer.read(cx).snapshot(cx);
16597        let selections = self
16598            .selections
16599            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16600            .into_iter()
16601            // subtracting the offset requires sorting
16602            .sorted_by_key(|i| i.start);
16603
16604        let full_edits = selections
16605            .into_iter()
16606            .filter_map(|selection| {
16607                let child = if selection.is_empty()
16608                    && let Some((_, ancestor_range)) =
16609                        buffer.syntax_ancestor(selection.start..selection.end)
16610                {
16611                    ancestor_range
16612                } else {
16613                    selection.range()
16614                };
16615
16616                let mut parent = child.clone();
16617                while let Some((_, ancestor_range)) = buffer.syntax_ancestor(parent.clone()) {
16618                    parent = ancestor_range;
16619                    if parent.start < child.start || parent.end > child.end {
16620                        break;
16621                    }
16622                }
16623
16624                if parent == child {
16625                    return None;
16626                }
16627                let text = buffer.text_for_range(child).collect::<String>();
16628                Some((selection.id, parent, text))
16629            })
16630            .collect::<Vec<_>>();
16631        if full_edits.is_empty() {
16632            return;
16633        }
16634
16635        self.transact(window, cx, |this, window, cx| {
16636            this.buffer.update(cx, |buffer, cx| {
16637                buffer.edit(
16638                    full_edits
16639                        .iter()
16640                        .map(|(_, p, t)| (p.clone(), t.clone()))
16641                        .collect::<Vec<_>>(),
16642                    None,
16643                    cx,
16644                );
16645            });
16646            this.change_selections(Default::default(), window, cx, |s| {
16647                let mut offset = 0;
16648                let mut selections = vec![];
16649                for (id, parent, text) in full_edits {
16650                    let start = parent.start - offset;
16651                    offset += (parent.end - parent.start) - text.len();
16652                    selections.push(Selection {
16653                        id,
16654                        start,
16655                        end: start + text.len(),
16656                        reversed: false,
16657                        goal: Default::default(),
16658                    });
16659                }
16660                s.select(selections);
16661            });
16662        });
16663    }
16664
16665    pub fn select_next_syntax_node(
16666        &mut self,
16667        _: &SelectNextSyntaxNode,
16668        window: &mut Window,
16669        cx: &mut Context<Self>,
16670    ) {
16671        let old_selections: Box<[_]> = self
16672            .selections
16673            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16674            .into();
16675        if old_selections.is_empty() {
16676            return;
16677        }
16678
16679        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16680
16681        let buffer = self.buffer.read(cx).snapshot(cx);
16682        let mut selected_sibling = false;
16683
16684        let new_selections = old_selections
16685            .iter()
16686            .map(|selection| {
16687                let old_range = selection.start..selection.end;
16688
16689                let old_range =
16690                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16691                let excerpt = buffer.excerpt_containing(old_range.clone());
16692
16693                if let Some(mut excerpt) = excerpt
16694                    && let Some(node) = excerpt
16695                        .buffer()
16696                        .syntax_next_sibling(excerpt.map_range_to_buffer(old_range))
16697                {
16698                    let new_range = excerpt.map_range_from_buffer(
16699                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16700                    );
16701                    selected_sibling = true;
16702                    Selection {
16703                        id: selection.id,
16704                        start: new_range.start,
16705                        end: new_range.end,
16706                        goal: SelectionGoal::None,
16707                        reversed: selection.reversed,
16708                    }
16709                } else {
16710                    selection.clone()
16711                }
16712            })
16713            .collect::<Vec<_>>();
16714
16715        if selected_sibling {
16716            self.change_selections(
16717                SelectionEffects::scroll(Autoscroll::fit()),
16718                window,
16719                cx,
16720                |s| {
16721                    s.select(new_selections);
16722                },
16723            );
16724        }
16725    }
16726
16727    pub fn select_prev_syntax_node(
16728        &mut self,
16729        _: &SelectPreviousSyntaxNode,
16730        window: &mut Window,
16731        cx: &mut Context<Self>,
16732    ) {
16733        let old_selections: Box<[_]> = self
16734            .selections
16735            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16736            .into();
16737        if old_selections.is_empty() {
16738            return;
16739        }
16740
16741        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16742
16743        let buffer = self.buffer.read(cx).snapshot(cx);
16744        let mut selected_sibling = false;
16745
16746        let new_selections = old_selections
16747            .iter()
16748            .map(|selection| {
16749                let old_range = selection.start..selection.end;
16750                let old_range =
16751                    old_range.start.to_offset(&buffer)..old_range.end.to_offset(&buffer);
16752                let excerpt = buffer.excerpt_containing(old_range.clone());
16753
16754                if let Some(mut excerpt) = excerpt
16755                    && let Some(node) = excerpt
16756                        .buffer()
16757                        .syntax_prev_sibling(excerpt.map_range_to_buffer(old_range))
16758                {
16759                    let new_range = excerpt.map_range_from_buffer(
16760                        BufferOffset(node.byte_range().start)..BufferOffset(node.byte_range().end),
16761                    );
16762                    selected_sibling = true;
16763                    Selection {
16764                        id: selection.id,
16765                        start: new_range.start,
16766                        end: new_range.end,
16767                        goal: SelectionGoal::None,
16768                        reversed: selection.reversed,
16769                    }
16770                } else {
16771                    selection.clone()
16772                }
16773            })
16774            .collect::<Vec<_>>();
16775
16776        if selected_sibling {
16777            self.change_selections(
16778                SelectionEffects::scroll(Autoscroll::fit()),
16779                window,
16780                cx,
16781                |s| {
16782                    s.select(new_selections);
16783                },
16784            );
16785        }
16786    }
16787
16788    pub fn move_to_start_of_larger_syntax_node(
16789        &mut self,
16790        _: &MoveToStartOfLargerSyntaxNode,
16791        window: &mut Window,
16792        cx: &mut Context<Self>,
16793    ) {
16794        self.move_cursors_to_syntax_nodes(window, cx, false);
16795    }
16796
16797    pub fn move_to_end_of_larger_syntax_node(
16798        &mut self,
16799        _: &MoveToEndOfLargerSyntaxNode,
16800        window: &mut Window,
16801        cx: &mut Context<Self>,
16802    ) {
16803        self.move_cursors_to_syntax_nodes(window, cx, true);
16804    }
16805
16806    fn find_syntax_node_boundary(
16807        &self,
16808        selection_pos: MultiBufferOffset,
16809        move_to_end: bool,
16810        display_map: &DisplaySnapshot,
16811        buffer: &MultiBufferSnapshot,
16812    ) -> MultiBufferOffset {
16813        let old_range = selection_pos..selection_pos;
16814        let mut new_pos = selection_pos;
16815        let mut search_range = old_range;
16816        while let Some((node, range)) = buffer.syntax_ancestor(search_range.clone()) {
16817            search_range = range.clone();
16818            if !node.is_named()
16819                || display_map.intersects_fold(range.start)
16820                || display_map.intersects_fold(range.end)
16821                // If cursor is already at the end of the syntax node, continue searching
16822                || (move_to_end && range.end == selection_pos)
16823                // If cursor is already at the start of the syntax node, continue searching
16824                || (!move_to_end && range.start == selection_pos)
16825            {
16826                continue;
16827            }
16828
16829            // If we found a string_content node, find the largest parent that is still string_content
16830            // Enables us to skip to the end of strings without taking multiple steps inside the string
16831            let (_, final_range) = if node.kind() == "string_content" {
16832                let mut current_node = node;
16833                let mut current_range = range;
16834                while let Some((parent, parent_range)) =
16835                    buffer.syntax_ancestor(current_range.clone())
16836                {
16837                    if parent.kind() == "string_content" {
16838                        current_node = parent;
16839                        current_range = parent_range;
16840                    } else {
16841                        break;
16842                    }
16843                }
16844
16845                (current_node, current_range)
16846            } else {
16847                (node, range)
16848            };
16849
16850            new_pos = if move_to_end {
16851                final_range.end
16852            } else {
16853                final_range.start
16854            };
16855
16856            break;
16857        }
16858
16859        new_pos
16860    }
16861
16862    fn move_cursors_to_syntax_nodes(
16863        &mut self,
16864        window: &mut Window,
16865        cx: &mut Context<Self>,
16866        move_to_end: bool,
16867    ) -> bool {
16868        let old_selections: Box<[_]> = self
16869            .selections
16870            .all::<MultiBufferOffset>(&self.display_snapshot(cx))
16871            .into();
16872        if old_selections.is_empty() {
16873            return false;
16874        }
16875
16876        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16877
16878        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16879        let buffer = self.buffer.read(cx).snapshot(cx);
16880
16881        let mut any_cursor_moved = false;
16882        let new_selections = old_selections
16883            .iter()
16884            .map(|selection| {
16885                if !selection.is_empty() {
16886                    return selection.clone();
16887                }
16888
16889                let selection_pos = selection.head();
16890                let new_pos = self.find_syntax_node_boundary(
16891                    selection_pos,
16892                    move_to_end,
16893                    &display_map,
16894                    &buffer,
16895                );
16896
16897                any_cursor_moved |= new_pos != selection_pos;
16898
16899                Selection {
16900                    id: selection.id,
16901                    start: new_pos,
16902                    end: new_pos,
16903                    goal: SelectionGoal::None,
16904                    reversed: false,
16905                }
16906            })
16907            .collect::<Vec<_>>();
16908
16909        self.change_selections(Default::default(), window, cx, |s| {
16910            s.select(new_selections);
16911        });
16912        self.request_autoscroll(Autoscroll::newest(), cx);
16913
16914        any_cursor_moved
16915    }
16916
16917    pub fn select_to_start_of_larger_syntax_node(
16918        &mut self,
16919        _: &SelectToStartOfLargerSyntaxNode,
16920        window: &mut Window,
16921        cx: &mut Context<Self>,
16922    ) {
16923        self.select_to_syntax_nodes(window, cx, false);
16924    }
16925
16926    pub fn select_to_end_of_larger_syntax_node(
16927        &mut self,
16928        _: &SelectToEndOfLargerSyntaxNode,
16929        window: &mut Window,
16930        cx: &mut Context<Self>,
16931    ) {
16932        self.select_to_syntax_nodes(window, cx, true);
16933    }
16934
16935    fn select_to_syntax_nodes(
16936        &mut self,
16937        window: &mut Window,
16938        cx: &mut Context<Self>,
16939        move_to_end: bool,
16940    ) {
16941        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16942
16943        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
16944        let buffer = self.buffer.read(cx).snapshot(cx);
16945        let old_selections = self.selections.all::<MultiBufferOffset>(&display_map);
16946
16947        let new_selections = old_selections
16948            .iter()
16949            .map(|selection| {
16950                let new_pos = self.find_syntax_node_boundary(
16951                    selection.head(),
16952                    move_to_end,
16953                    &display_map,
16954                    &buffer,
16955                );
16956
16957                let mut new_selection = selection.clone();
16958                new_selection.set_head(new_pos, SelectionGoal::None);
16959                new_selection
16960            })
16961            .collect::<Vec<_>>();
16962
16963        self.change_selections(Default::default(), window, cx, |s| {
16964            s.select(new_selections);
16965        });
16966    }
16967
16968    pub fn move_to_enclosing_bracket(
16969        &mut self,
16970        _: &MoveToEnclosingBracket,
16971        window: &mut Window,
16972        cx: &mut Context<Self>,
16973    ) {
16974        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
16975        self.change_selections(Default::default(), window, cx, |s| {
16976            s.move_offsets_with(&mut |snapshot, selection| {
16977                let Some(enclosing_bracket_ranges) =
16978                    snapshot.enclosing_bracket_ranges(selection.start..selection.end)
16979                else {
16980                    return;
16981                };
16982
16983                let mut best_length = usize::MAX;
16984                let mut best_inside = false;
16985                let mut best_in_bracket_range = false;
16986                let mut best_destination = None;
16987                for (open, close) in enclosing_bracket_ranges {
16988                    let close = close.to_inclusive();
16989                    let length = *close.end() - open.start;
16990                    let inside = selection.start >= open.end && selection.end <= *close.start();
16991                    let in_bracket_range = open.to_inclusive().contains(&selection.head())
16992                        || close.contains(&selection.head());
16993
16994                    // If best is next to a bracket and current isn't, skip
16995                    if !in_bracket_range && best_in_bracket_range {
16996                        continue;
16997                    }
16998
16999                    // Prefer smaller lengths unless best is inside and current isn't
17000                    if length > best_length && (best_inside || !inside) {
17001                        continue;
17002                    }
17003
17004                    best_length = length;
17005                    best_inside = inside;
17006                    best_in_bracket_range = in_bracket_range;
17007                    best_destination = Some(
17008                        if close.contains(&selection.start) && close.contains(&selection.end) {
17009                            if inside { open.end } else { open.start }
17010                        } else if inside {
17011                            *close.start()
17012                        } else {
17013                            *close.end()
17014                        },
17015                    );
17016                }
17017
17018                if let Some(destination) = best_destination {
17019                    selection.collapse_to(destination, SelectionGoal::None);
17020                }
17021            })
17022        });
17023    }
17024
17025    pub fn undo_selection(
17026        &mut self,
17027        _: &UndoSelection,
17028        window: &mut Window,
17029        cx: &mut Context<Self>,
17030    ) {
17031        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17032        if let Some(entry) = self.selection_history.undo_stack.pop_back() {
17033            self.selection_history.mode = SelectionHistoryMode::Undoing;
17034            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17035                this.end_selection(window, cx);
17036                this.change_selections(
17037                    SelectionEffects::scroll(Autoscroll::newest()),
17038                    window,
17039                    cx,
17040                    |s| s.select_anchors(entry.selections.to_vec()),
17041                );
17042            });
17043            self.selection_history.mode = SelectionHistoryMode::Normal;
17044
17045            self.select_next_state = entry.select_next_state;
17046            self.select_prev_state = entry.select_prev_state;
17047            self.add_selections_state = entry.add_selections_state;
17048        }
17049    }
17050
17051    pub fn redo_selection(
17052        &mut self,
17053        _: &RedoSelection,
17054        window: &mut Window,
17055        cx: &mut Context<Self>,
17056    ) {
17057        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17058        if let Some(entry) = self.selection_history.redo_stack.pop_back() {
17059            self.selection_history.mode = SelectionHistoryMode::Redoing;
17060            self.with_selection_effects_deferred(window, cx, |this, window, cx| {
17061                this.end_selection(window, cx);
17062                this.change_selections(
17063                    SelectionEffects::scroll(Autoscroll::newest()),
17064                    window,
17065                    cx,
17066                    |s| s.select_anchors(entry.selections.to_vec()),
17067                );
17068            });
17069            self.selection_history.mode = SelectionHistoryMode::Normal;
17070
17071            self.select_next_state = entry.select_next_state;
17072            self.select_prev_state = entry.select_prev_state;
17073            self.add_selections_state = entry.add_selections_state;
17074        }
17075    }
17076
17077    pub fn expand_excerpts(
17078        &mut self,
17079        action: &ExpandExcerpts,
17080        _: &mut Window,
17081        cx: &mut Context<Self>,
17082    ) {
17083        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::UpAndDown, cx)
17084    }
17085
17086    pub fn expand_excerpts_down(
17087        &mut self,
17088        action: &ExpandExcerptsDown,
17089        _: &mut Window,
17090        cx: &mut Context<Self>,
17091    ) {
17092        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Down, cx)
17093    }
17094
17095    pub fn expand_excerpts_up(
17096        &mut self,
17097        action: &ExpandExcerptsUp,
17098        _: &mut Window,
17099        cx: &mut Context<Self>,
17100    ) {
17101        self.expand_excerpts_for_direction(action.lines, ExpandExcerptDirection::Up, cx)
17102    }
17103
17104    pub fn expand_excerpts_for_direction(
17105        &mut self,
17106        lines: u32,
17107        direction: ExpandExcerptDirection,
17108        cx: &mut Context<Self>,
17109    ) {
17110        let selections = self.selections.disjoint_anchors_arc();
17111
17112        let lines = if lines == 0 {
17113            EditorSettings::get_global(cx).expand_excerpt_lines
17114        } else {
17115            lines
17116        };
17117
17118        let snapshot = self.buffer.read(cx).snapshot(cx);
17119        let excerpt_ids = selections
17120            .iter()
17121            .flat_map(|selection| snapshot.excerpt_ids_for_range(selection.range()))
17122            .unique()
17123            .sorted()
17124            .collect::<Vec<_>>();
17125
17126        if self.delegate_expand_excerpts {
17127            cx.emit(EditorEvent::ExpandExcerptsRequested {
17128                excerpt_ids,
17129                lines,
17130                direction,
17131            });
17132            return;
17133        }
17134
17135        self.buffer.update(cx, |buffer, cx| {
17136            buffer.expand_excerpts(excerpt_ids, lines, direction, cx)
17137        })
17138    }
17139
17140    pub fn expand_excerpt(
17141        &mut self,
17142        excerpt: ExcerptId,
17143        direction: ExpandExcerptDirection,
17144        window: &mut Window,
17145        cx: &mut Context<Self>,
17146    ) {
17147        let lines_to_expand = EditorSettings::get_global(cx).expand_excerpt_lines;
17148
17149        if self.delegate_expand_excerpts {
17150            cx.emit(EditorEvent::ExpandExcerptsRequested {
17151                excerpt_ids: vec![excerpt],
17152                lines: lines_to_expand,
17153                direction,
17154            });
17155            return;
17156        }
17157
17158        let current_scroll_position = self.scroll_position(cx);
17159        let mut scroll = None;
17160
17161        if direction == ExpandExcerptDirection::Down {
17162            let multi_buffer = self.buffer.read(cx);
17163            let snapshot = multi_buffer.snapshot(cx);
17164            if let Some(buffer_id) = snapshot.buffer_id_for_excerpt(excerpt)
17165                && let Some(buffer) = multi_buffer.buffer(buffer_id)
17166                && let Some(excerpt_range) = snapshot.context_range_for_excerpt(excerpt)
17167            {
17168                let buffer_snapshot = buffer.read(cx).snapshot();
17169                let excerpt_end_row = Point::from_anchor(&excerpt_range.end, &buffer_snapshot).row;
17170                let last_row = buffer_snapshot.max_point().row;
17171                let lines_below = last_row.saturating_sub(excerpt_end_row);
17172                if lines_below >= lines_to_expand {
17173                    scroll = Some(
17174                        current_scroll_position
17175                            + gpui::Point::new(0.0, lines_to_expand as ScrollOffset),
17176                    );
17177                }
17178            }
17179        }
17180        if direction == ExpandExcerptDirection::Up
17181            && self
17182                .buffer
17183                .read(cx)
17184                .snapshot(cx)
17185                .excerpt_before(excerpt)
17186                .is_none()
17187        {
17188            scroll = Some(current_scroll_position);
17189        }
17190
17191        self.buffer.update(cx, |buffer, cx| {
17192            buffer.expand_excerpts([excerpt], lines_to_expand, direction, cx)
17193        });
17194
17195        if let Some(new_scroll_position) = scroll {
17196            self.set_scroll_position(new_scroll_position, window, cx);
17197        }
17198    }
17199
17200    pub fn go_to_singleton_buffer_point(
17201        &mut self,
17202        point: Point,
17203        window: &mut Window,
17204        cx: &mut Context<Self>,
17205    ) {
17206        self.go_to_singleton_buffer_range(point..point, window, cx);
17207    }
17208
17209    pub fn go_to_singleton_buffer_range(
17210        &mut self,
17211        range: Range<Point>,
17212        window: &mut Window,
17213        cx: &mut Context<Self>,
17214    ) {
17215        let multibuffer = self.buffer().read(cx);
17216        let Some(buffer) = multibuffer.as_singleton() else {
17217            return;
17218        };
17219        let Some(start) = multibuffer.buffer_point_to_anchor(&buffer, range.start, cx) else {
17220            return;
17221        };
17222        let Some(end) = multibuffer.buffer_point_to_anchor(&buffer, range.end, cx) else {
17223            return;
17224        };
17225        self.change_selections(
17226            SelectionEffects::default().nav_history(true),
17227            window,
17228            cx,
17229            |s| s.select_anchor_ranges([start..end]),
17230        );
17231    }
17232
17233    pub fn go_to_diagnostic(
17234        &mut self,
17235        action: &GoToDiagnostic,
17236        window: &mut Window,
17237        cx: &mut Context<Self>,
17238    ) {
17239        if !self.diagnostics_enabled() {
17240            return;
17241        }
17242        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17243        self.go_to_diagnostic_impl(Direction::Next, action.severity, window, cx)
17244    }
17245
17246    pub fn go_to_prev_diagnostic(
17247        &mut self,
17248        action: &GoToPreviousDiagnostic,
17249        window: &mut Window,
17250        cx: &mut Context<Self>,
17251    ) {
17252        if !self.diagnostics_enabled() {
17253            return;
17254        }
17255        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17256        self.go_to_diagnostic_impl(Direction::Prev, action.severity, window, cx)
17257    }
17258
17259    pub fn go_to_diagnostic_impl(
17260        &mut self,
17261        direction: Direction,
17262        severity: GoToDiagnosticSeverityFilter,
17263        window: &mut Window,
17264        cx: &mut Context<Self>,
17265    ) {
17266        let buffer = self.buffer.read(cx).snapshot(cx);
17267        let selection = self
17268            .selections
17269            .newest::<MultiBufferOffset>(&self.display_snapshot(cx));
17270
17271        let mut active_group_id = None;
17272        if let ActiveDiagnostic::Group(active_group) = &self.active_diagnostics
17273            && active_group.active_range.start.to_offset(&buffer) == selection.start
17274        {
17275            active_group_id = Some(active_group.group_id);
17276        }
17277
17278        fn filtered<'a>(
17279            severity: GoToDiagnosticSeverityFilter,
17280            diagnostics: impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>>,
17281        ) -> impl Iterator<Item = DiagnosticEntryRef<'a, MultiBufferOffset>> {
17282            diagnostics
17283                .filter(move |entry| severity.matches(entry.diagnostic.severity))
17284                .filter(|entry| entry.range.start != entry.range.end)
17285                .filter(|entry| !entry.diagnostic.is_unnecessary)
17286        }
17287
17288        let before = filtered(
17289            severity,
17290            buffer
17291                .diagnostics_in_range(MultiBufferOffset(0)..selection.start)
17292                .filter(|entry| entry.range.start <= selection.start),
17293        );
17294        let after = filtered(
17295            severity,
17296            buffer
17297                .diagnostics_in_range(selection.start..buffer.len())
17298                .filter(|entry| entry.range.start >= selection.start),
17299        );
17300
17301        let mut found: Option<DiagnosticEntryRef<MultiBufferOffset>> = None;
17302        if direction == Direction::Prev {
17303            'outer: for prev_diagnostics in [before.collect::<Vec<_>>(), after.collect::<Vec<_>>()]
17304            {
17305                for diagnostic in prev_diagnostics.into_iter().rev() {
17306                    if diagnostic.range.start != selection.start
17307                        || active_group_id
17308                            .is_some_and(|active| diagnostic.diagnostic.group_id < active)
17309                    {
17310                        found = Some(diagnostic);
17311                        break 'outer;
17312                    }
17313                }
17314            }
17315        } else {
17316            for diagnostic in after.chain(before) {
17317                if diagnostic.range.start != selection.start
17318                    || active_group_id.is_some_and(|active| diagnostic.diagnostic.group_id > active)
17319                {
17320                    found = Some(diagnostic);
17321                    break;
17322                }
17323            }
17324        }
17325        let Some(next_diagnostic) = found else {
17326            return;
17327        };
17328
17329        let next_diagnostic_start = buffer.anchor_after(next_diagnostic.range.start);
17330        let Some(buffer_id) = buffer.buffer_id_for_anchor(next_diagnostic_start) else {
17331            return;
17332        };
17333        let snapshot = self.snapshot(window, cx);
17334        if snapshot.intersects_fold(next_diagnostic.range.start) {
17335            self.unfold_ranges(
17336                std::slice::from_ref(&next_diagnostic.range),
17337                true,
17338                false,
17339                cx,
17340            );
17341        }
17342        self.change_selections(Default::default(), window, cx, |s| {
17343            s.select_ranges(vec![
17344                next_diagnostic.range.start..next_diagnostic.range.start,
17345            ])
17346        });
17347        self.activate_diagnostics(buffer_id, next_diagnostic, window, cx);
17348        self.refresh_edit_prediction(false, true, window, cx);
17349    }
17350
17351    pub fn go_to_next_hunk(&mut self, _: &GoToHunk, window: &mut Window, cx: &mut Context<Self>) {
17352        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17353        let snapshot = self.snapshot(window, cx);
17354        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
17355        self.go_to_hunk_before_or_after_position(
17356            &snapshot,
17357            selection.head(),
17358            Direction::Next,
17359            true,
17360            window,
17361            cx,
17362        );
17363    }
17364
17365    pub fn go_to_hunk_before_or_after_position(
17366        &mut self,
17367        snapshot: &EditorSnapshot,
17368        position: Point,
17369        direction: Direction,
17370        wrap_around: bool,
17371        window: &mut Window,
17372        cx: &mut Context<Editor>,
17373    ) {
17374        let row = if direction == Direction::Next {
17375            self.hunk_after_position(snapshot, position, wrap_around)
17376                .map(|hunk| hunk.row_range.start)
17377        } else {
17378            self.hunk_before_position(snapshot, position, wrap_around)
17379        };
17380
17381        if let Some(row) = row {
17382            let destination = Point::new(row.0, 0);
17383            let autoscroll = Autoscroll::center();
17384
17385            self.unfold_ranges(&[destination..destination], false, false, cx);
17386            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17387                s.select_ranges([destination..destination]);
17388            });
17389        }
17390    }
17391
17392    fn hunk_after_position(
17393        &mut self,
17394        snapshot: &EditorSnapshot,
17395        position: Point,
17396        wrap_around: bool,
17397    ) -> Option<MultiBufferDiffHunk> {
17398        let result = snapshot
17399            .buffer_snapshot()
17400            .diff_hunks_in_range(position..snapshot.buffer_snapshot().max_point())
17401            .find(|hunk| hunk.row_range.start.0 > position.row);
17402
17403        if wrap_around {
17404            result.or_else(|| {
17405                snapshot
17406                    .buffer_snapshot()
17407                    .diff_hunks_in_range(Point::zero()..position)
17408                    .find(|hunk| hunk.row_range.end.0 < position.row)
17409            })
17410        } else {
17411            result
17412        }
17413    }
17414
17415    fn go_to_prev_hunk(
17416        &mut self,
17417        _: &GoToPreviousHunk,
17418        window: &mut Window,
17419        cx: &mut Context<Self>,
17420    ) {
17421        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17422        let snapshot = self.snapshot(window, cx);
17423        let selection = self.selections.newest::<Point>(&snapshot.display_snapshot);
17424        self.go_to_hunk_before_or_after_position(
17425            &snapshot,
17426            selection.head(),
17427            Direction::Prev,
17428            true,
17429            window,
17430            cx,
17431        );
17432    }
17433
17434    fn hunk_before_position(
17435        &mut self,
17436        snapshot: &EditorSnapshot,
17437        position: Point,
17438        wrap_around: bool,
17439    ) -> Option<MultiBufferRow> {
17440        let result = snapshot.buffer_snapshot().diff_hunk_before(position);
17441
17442        if wrap_around {
17443            result.or_else(|| snapshot.buffer_snapshot().diff_hunk_before(Point::MAX))
17444        } else {
17445            result
17446        }
17447    }
17448
17449    fn go_to_next_change(
17450        &mut self,
17451        _: &GoToNextChange,
17452        window: &mut Window,
17453        cx: &mut Context<Self>,
17454    ) {
17455        if let Some(selections) = self
17456            .change_list
17457            .next_change(1, Direction::Next)
17458            .map(|s| s.to_vec())
17459        {
17460            self.change_selections(Default::default(), window, cx, |s| {
17461                let map = s.display_snapshot();
17462                s.select_display_ranges(selections.iter().map(|a| {
17463                    let point = a.to_display_point(&map);
17464                    point..point
17465                }))
17466            })
17467        }
17468    }
17469
17470    fn go_to_previous_change(
17471        &mut self,
17472        _: &GoToPreviousChange,
17473        window: &mut Window,
17474        cx: &mut Context<Self>,
17475    ) {
17476        if let Some(selections) = self
17477            .change_list
17478            .next_change(1, Direction::Prev)
17479            .map(|s| s.to_vec())
17480        {
17481            self.change_selections(Default::default(), window, cx, |s| {
17482                let map = s.display_snapshot();
17483                s.select_display_ranges(selections.iter().map(|a| {
17484                    let point = a.to_display_point(&map);
17485                    point..point
17486                }))
17487            })
17488        }
17489    }
17490
17491    pub fn go_to_next_document_highlight(
17492        &mut self,
17493        _: &GoToNextDocumentHighlight,
17494        window: &mut Window,
17495        cx: &mut Context<Self>,
17496    ) {
17497        self.go_to_document_highlight_before_or_after_position(Direction::Next, window, cx);
17498    }
17499
17500    pub fn go_to_prev_document_highlight(
17501        &mut self,
17502        _: &GoToPreviousDocumentHighlight,
17503        window: &mut Window,
17504        cx: &mut Context<Self>,
17505    ) {
17506        self.go_to_document_highlight_before_or_after_position(Direction::Prev, window, cx);
17507    }
17508
17509    pub fn go_to_document_highlight_before_or_after_position(
17510        &mut self,
17511        direction: Direction,
17512        window: &mut Window,
17513        cx: &mut Context<Editor>,
17514    ) {
17515        self.hide_mouse_cursor(HideMouseCursorOrigin::MovementAction, cx);
17516        let snapshot = self.snapshot(window, cx);
17517        let buffer = &snapshot.buffer_snapshot();
17518        let position = self
17519            .selections
17520            .newest::<Point>(&snapshot.display_snapshot)
17521            .head();
17522        let anchor_position = buffer.anchor_after(position);
17523
17524        // Get all document highlights (both read and write)
17525        let mut all_highlights = Vec::new();
17526
17527        if let Some((_, read_highlights)) = self
17528            .background_highlights
17529            .get(&HighlightKey::DocumentHighlightRead)
17530        {
17531            all_highlights.extend(read_highlights.iter());
17532        }
17533
17534        if let Some((_, write_highlights)) = self
17535            .background_highlights
17536            .get(&HighlightKey::DocumentHighlightWrite)
17537        {
17538            all_highlights.extend(write_highlights.iter());
17539        }
17540
17541        if all_highlights.is_empty() {
17542            return;
17543        }
17544
17545        // Sort highlights by position
17546        all_highlights.sort_by(|a, b| a.start.cmp(&b.start, buffer));
17547
17548        let target_highlight = match direction {
17549            Direction::Next => {
17550                // Find the first highlight after the current position
17551                all_highlights
17552                    .iter()
17553                    .find(|highlight| highlight.start.cmp(&anchor_position, buffer).is_gt())
17554            }
17555            Direction::Prev => {
17556                // Find the last highlight before the current position
17557                all_highlights
17558                    .iter()
17559                    .rev()
17560                    .find(|highlight| highlight.end.cmp(&anchor_position, buffer).is_lt())
17561            }
17562        };
17563
17564        if let Some(highlight) = target_highlight {
17565            let destination = highlight.start.to_point(buffer);
17566            let autoscroll = Autoscroll::center();
17567
17568            self.unfold_ranges(&[destination..destination], false, false, cx);
17569            self.change_selections(SelectionEffects::scroll(autoscroll), window, cx, |s| {
17570                s.select_ranges([destination..destination]);
17571            });
17572        }
17573    }
17574
17575    fn go_to_line<T: 'static>(
17576        &mut self,
17577        position: Anchor,
17578        highlight_color: Option<Hsla>,
17579        window: &mut Window,
17580        cx: &mut Context<Self>,
17581    ) {
17582        let snapshot = self.snapshot(window, cx).display_snapshot;
17583        let position = position.to_point(&snapshot.buffer_snapshot());
17584        let start = snapshot
17585            .buffer_snapshot()
17586            .clip_point(Point::new(position.row, 0), Bias::Left);
17587        let end = start + Point::new(1, 0);
17588        let start = snapshot.buffer_snapshot().anchor_before(start);
17589        let end = snapshot.buffer_snapshot().anchor_before(end);
17590
17591        self.highlight_rows::<T>(
17592            start..end,
17593            highlight_color
17594                .unwrap_or_else(|| cx.theme().colors().editor_highlighted_line_background),
17595            Default::default(),
17596            cx,
17597        );
17598
17599        if self.buffer.read(cx).is_singleton() {
17600            self.request_autoscroll(Autoscroll::center().for_anchor(start), cx);
17601        }
17602    }
17603
17604    pub fn go_to_definition(
17605        &mut self,
17606        _: &GoToDefinition,
17607        window: &mut Window,
17608        cx: &mut Context<Self>,
17609    ) -> Task<Result<Navigated>> {
17610        let definition =
17611            self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, false, window, cx);
17612        let fallback_strategy = EditorSettings::get_global(cx).go_to_definition_fallback;
17613        cx.spawn_in(window, async move |editor, cx| {
17614            if definition.await? == Navigated::Yes {
17615                return Ok(Navigated::Yes);
17616            }
17617            match fallback_strategy {
17618                GoToDefinitionFallback::None => Ok(Navigated::No),
17619                GoToDefinitionFallback::FindAllReferences => {
17620                    match editor.update_in(cx, |editor, window, cx| {
17621                        editor.find_all_references(&FindAllReferences::default(), window, cx)
17622                    })? {
17623                        Some(references) => references.await,
17624                        None => Ok(Navigated::No),
17625                    }
17626                }
17627            }
17628        })
17629    }
17630
17631    pub fn go_to_declaration(
17632        &mut self,
17633        _: &GoToDeclaration,
17634        window: &mut Window,
17635        cx: &mut Context<Self>,
17636    ) -> Task<Result<Navigated>> {
17637        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, false, window, cx)
17638    }
17639
17640    pub fn go_to_declaration_split(
17641        &mut self,
17642        _: &GoToDeclaration,
17643        window: &mut Window,
17644        cx: &mut Context<Self>,
17645    ) -> Task<Result<Navigated>> {
17646        self.go_to_definition_of_kind(GotoDefinitionKind::Declaration, true, window, cx)
17647    }
17648
17649    pub fn go_to_implementation(
17650        &mut self,
17651        _: &GoToImplementation,
17652        window: &mut Window,
17653        cx: &mut Context<Self>,
17654    ) -> Task<Result<Navigated>> {
17655        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, false, window, cx)
17656    }
17657
17658    pub fn go_to_implementation_split(
17659        &mut self,
17660        _: &GoToImplementationSplit,
17661        window: &mut Window,
17662        cx: &mut Context<Self>,
17663    ) -> Task<Result<Navigated>> {
17664        self.go_to_definition_of_kind(GotoDefinitionKind::Implementation, true, window, cx)
17665    }
17666
17667    pub fn go_to_type_definition(
17668        &mut self,
17669        _: &GoToTypeDefinition,
17670        window: &mut Window,
17671        cx: &mut Context<Self>,
17672    ) -> Task<Result<Navigated>> {
17673        self.go_to_definition_of_kind(GotoDefinitionKind::Type, false, window, cx)
17674    }
17675
17676    pub fn go_to_definition_split(
17677        &mut self,
17678        _: &GoToDefinitionSplit,
17679        window: &mut Window,
17680        cx: &mut Context<Self>,
17681    ) -> Task<Result<Navigated>> {
17682        self.go_to_definition_of_kind(GotoDefinitionKind::Symbol, true, window, cx)
17683    }
17684
17685    pub fn go_to_type_definition_split(
17686        &mut self,
17687        _: &GoToTypeDefinitionSplit,
17688        window: &mut Window,
17689        cx: &mut Context<Self>,
17690    ) -> Task<Result<Navigated>> {
17691        self.go_to_definition_of_kind(GotoDefinitionKind::Type, true, window, cx)
17692    }
17693
17694    fn go_to_definition_of_kind(
17695        &mut self,
17696        kind: GotoDefinitionKind,
17697        split: bool,
17698        window: &mut Window,
17699        cx: &mut Context<Self>,
17700    ) -> Task<Result<Navigated>> {
17701        let Some(provider) = self.semantics_provider.clone() else {
17702            return Task::ready(Ok(Navigated::No));
17703        };
17704        let head = self
17705            .selections
17706            .newest::<MultiBufferOffset>(&self.display_snapshot(cx))
17707            .head();
17708        let buffer = self.buffer.read(cx);
17709        let Some((buffer, head)) = buffer.text_anchor_for_position(head, cx) else {
17710            return Task::ready(Ok(Navigated::No));
17711        };
17712        let Some(definitions) = provider.definitions(&buffer, head, kind, cx) else {
17713            return Task::ready(Ok(Navigated::No));
17714        };
17715
17716        let nav_entry = self.navigation_entry(self.selections.newest_anchor().head(), cx);
17717
17718        cx.spawn_in(window, async move |editor, cx| {
17719            let Some(definitions) = definitions.await? else {
17720                return Ok(Navigated::No);
17721            };
17722            let navigated = editor
17723                .update_in(cx, |editor, window, cx| {
17724                    editor.navigate_to_hover_links(
17725                        Some(kind),
17726                        definitions
17727                            .into_iter()
17728                            .filter(|location| {
17729                                hover_links::exclude_link_to_position(&buffer, &head, location, cx)
17730                            })
17731                            .map(HoverLink::Text)
17732                            .collect::<Vec<_>>(),
17733                        nav_entry,
17734                        split,
17735                        window,
17736                        cx,
17737                    )
17738                })?
17739                .await?;
17740            anyhow::Ok(navigated)
17741        })
17742    }
17743
17744    pub fn open_url(&mut self, _: &OpenUrl, window: &mut Window, cx: &mut Context<Self>) {
17745        let selection = self.selections.newest_anchor();
17746        let head = selection.head();
17747        let tail = selection.tail();
17748
17749        let Some((buffer, start_position)) =
17750            self.buffer.read(cx).text_anchor_for_position(head, cx)
17751        else {
17752            return;
17753        };
17754
17755        let end_position = if head != tail {
17756            let Some((_, pos)) = self.buffer.read(cx).text_anchor_for_position(tail, cx) else {
17757                return;
17758            };
17759            Some(pos)
17760        } else {
17761            None
17762        };
17763
17764        let url_finder = cx.spawn_in(window, async move |_editor, cx| {
17765            let url = if let Some(end_pos) = end_position {
17766                find_url_from_range(&buffer, start_position..end_pos, cx.clone())
17767            } else {
17768                find_url(&buffer, start_position, cx.clone()).map(|(_, url)| url)
17769            };
17770
17771            if let Some(url) = url {
17772                cx.update(|window, cx| {
17773                    if parse_zed_link(&url, cx).is_some() {
17774                        window.dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17775                    } else {
17776                        cx.open_url(&url);
17777                    }
17778                })?;
17779            }
17780
17781            anyhow::Ok(())
17782        });
17783
17784        url_finder.detach();
17785    }
17786
17787    pub fn open_selected_filename(
17788        &mut self,
17789        _: &OpenSelectedFilename,
17790        window: &mut Window,
17791        cx: &mut Context<Self>,
17792    ) {
17793        let Some(workspace) = self.workspace() else {
17794            return;
17795        };
17796
17797        let position = self.selections.newest_anchor().head();
17798
17799        let Some((buffer, buffer_position)) =
17800            self.buffer.read(cx).text_anchor_for_position(position, cx)
17801        else {
17802            return;
17803        };
17804
17805        let project = self.project.clone();
17806
17807        cx.spawn_in(window, async move |_, cx| {
17808            let result = find_file(&buffer, project, buffer_position, cx).await;
17809
17810            if let Some((_, path)) = result {
17811                workspace
17812                    .update_in(cx, |workspace, window, cx| {
17813                        workspace.open_resolved_path(path, window, cx)
17814                    })?
17815                    .await?;
17816            }
17817            anyhow::Ok(())
17818        })
17819        .detach();
17820    }
17821
17822    pub(crate) fn navigate_to_hover_links(
17823        &mut self,
17824        kind: Option<GotoDefinitionKind>,
17825        definitions: Vec<HoverLink>,
17826        origin: Option<NavigationEntry>,
17827        split: bool,
17828        window: &mut Window,
17829        cx: &mut Context<Editor>,
17830    ) -> Task<Result<Navigated>> {
17831        // Separate out url and file links, we can only handle one of them at most or an arbitrary number of locations
17832        let mut first_url_or_file = None;
17833        let definitions: Vec<_> = definitions
17834            .into_iter()
17835            .filter_map(|def| match def {
17836                HoverLink::Text(link) => Some(Task::ready(anyhow::Ok(Some(link.target)))),
17837                HoverLink::InlayHint(lsp_location, server_id) => {
17838                    let computation =
17839                        self.compute_target_location(lsp_location, server_id, window, cx);
17840                    Some(cx.background_spawn(computation))
17841                }
17842                HoverLink::Url(url) => {
17843                    first_url_or_file = Some(Either::Left(url));
17844                    None
17845                }
17846                HoverLink::File(path) => {
17847                    first_url_or_file = Some(Either::Right(path));
17848                    None
17849                }
17850            })
17851            .collect();
17852
17853        let workspace = self.workspace();
17854
17855        cx.spawn_in(window, async move |editor, cx| {
17856            let locations: Vec<Location> = future::join_all(definitions)
17857                .await
17858                .into_iter()
17859                .filter_map(|location| location.transpose())
17860                .collect::<Result<_>>()
17861                .context("location tasks")?;
17862            let mut locations = cx.update(|_, cx| {
17863                locations
17864                    .into_iter()
17865                    .map(|location| {
17866                        let buffer = location.buffer.read(cx);
17867                        (location.buffer, location.range.to_point(buffer))
17868                    })
17869                    .into_group_map()
17870            })?;
17871            let mut num_locations = 0;
17872            for ranges in locations.values_mut() {
17873                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
17874                ranges.dedup();
17875                num_locations += ranges.len();
17876            }
17877
17878            if num_locations > 1 {
17879                let tab_kind = match kind {
17880                    Some(GotoDefinitionKind::Implementation) => "Implementations",
17881                    Some(GotoDefinitionKind::Symbol) | None => "Definitions",
17882                    Some(GotoDefinitionKind::Declaration) => "Declarations",
17883                    Some(GotoDefinitionKind::Type) => "Types",
17884                };
17885                let title = editor
17886                    .update_in(cx, |_, _, cx| {
17887                        let target = locations
17888                            .iter()
17889                            .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
17890                            .map(|(buffer, location)| {
17891                                buffer
17892                                    .read(cx)
17893                                    .text_for_range(location.clone())
17894                                    .collect::<String>()
17895                            })
17896                            .filter(|text| !text.contains('\n'))
17897                            .unique()
17898                            .take(3)
17899                            .join(", ");
17900                        if target.is_empty() {
17901                            tab_kind.to_owned()
17902                        } else {
17903                            format!("{tab_kind} for {target}")
17904                        }
17905                    })
17906                    .context("buffer title")?;
17907
17908                let Some(workspace) = workspace else {
17909                    return Ok(Navigated::No);
17910                };
17911
17912                let opened = workspace
17913                    .update_in(cx, |workspace, window, cx| {
17914                        let allow_preview = PreviewTabsSettings::get_global(cx)
17915                            .enable_preview_multibuffer_from_code_navigation;
17916                        if let Some((target_editor, target_pane)) =
17917                            Self::open_locations_in_multibuffer(
17918                                workspace,
17919                                locations,
17920                                title,
17921                                split,
17922                                allow_preview,
17923                                MultibufferSelectionMode::First,
17924                                window,
17925                                cx,
17926                            )
17927                        {
17928                            // We create our own nav history instead of using
17929                            // `target_editor.nav_history` because `nav_history`
17930                            // seems to be populated asynchronously when an item
17931                            // is added to a pane
17932                            let mut nav_history = target_pane
17933                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
17934                            target_editor.update(cx, |editor, cx| {
17935                                let nav_data = editor
17936                                    .navigation_data(editor.selections.newest_anchor().head(), cx);
17937                                let target =
17938                                    Some(nav_history.navigation_entry(Some(
17939                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
17940                                    )));
17941                                nav_history.push_tag(origin, target);
17942                            })
17943                        }
17944                    })
17945                    .is_ok();
17946
17947                anyhow::Ok(Navigated::from_bool(opened))
17948            } else if num_locations == 0 {
17949                // If there is one url or file, open it directly
17950                match first_url_or_file {
17951                    Some(Either::Left(url)) => {
17952                        cx.update(|window, cx| {
17953                            if parse_zed_link(&url, cx).is_some() {
17954                                window
17955                                    .dispatch_action(Box::new(zed_actions::OpenZedUrl { url }), cx);
17956                            } else {
17957                                cx.open_url(&url);
17958                            }
17959                        })?;
17960                        Ok(Navigated::Yes)
17961                    }
17962                    Some(Either::Right(path)) => {
17963                        // TODO(andrew): respect preview tab settings
17964                        //               `enable_keep_preview_on_code_navigation` and
17965                        //               `enable_preview_file_from_code_navigation`
17966                        let Some(workspace) = workspace else {
17967                            return Ok(Navigated::No);
17968                        };
17969                        workspace
17970                            .update_in(cx, |workspace, window, cx| {
17971                                workspace.open_resolved_path(path, window, cx)
17972                            })?
17973                            .await?;
17974                        Ok(Navigated::Yes)
17975                    }
17976                    None => Ok(Navigated::No),
17977                }
17978            } else {
17979                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
17980                let target_range = target_ranges.first().unwrap().clone();
17981
17982                editor.update_in(cx, |editor, window, cx| {
17983                    let range = editor.range_for_match(&target_range);
17984                    let range = collapse_multiline_range(range);
17985
17986                    if !split
17987                        && Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref()
17988                    {
17989                        editor.go_to_singleton_buffer_range(range, window, cx);
17990
17991                        let target =
17992                            editor.navigation_entry(editor.selections.newest_anchor().head(), cx);
17993                        if let Some(mut nav_history) = editor.nav_history.clone() {
17994                            nav_history.push_tag(origin, target);
17995                        }
17996                    } else {
17997                        let Some(workspace) = workspace else {
17998                            return Navigated::No;
17999                        };
18000                        let pane = workspace.read(cx).active_pane().clone();
18001                        window.defer(cx, move |window, cx| {
18002                            let (target_editor, target_pane): (Entity<Self>, Entity<Pane>) =
18003                                workspace.update(cx, |workspace, cx| {
18004                                    let pane = if split {
18005                                        workspace.adjacent_pane(window, cx)
18006                                    } else {
18007                                        workspace.active_pane().clone()
18008                                    };
18009
18010                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18011                                    let keep_old_preview = preview_tabs_settings
18012                                        .enable_keep_preview_on_code_navigation;
18013                                    let allow_new_preview = preview_tabs_settings
18014                                        .enable_preview_file_from_code_navigation;
18015
18016                                    let editor = workspace.open_project_item(
18017                                        pane.clone(),
18018                                        target_buffer.clone(),
18019                                        true,
18020                                        true,
18021                                        keep_old_preview,
18022                                        allow_new_preview,
18023                                        window,
18024                                        cx,
18025                                    );
18026                                    (editor, pane)
18027                                });
18028                            // We create our own nav history instead of using
18029                            // `target_editor.nav_history` because `nav_history`
18030                            // seems to be populated asynchronously when an item
18031                            // is added to a pane
18032                            let mut nav_history = target_pane
18033                                .update(cx, |pane, _| pane.nav_history_for_item(&target_editor));
18034                            target_editor.update(cx, |target_editor, cx| {
18035                                // When selecting a definition in a different buffer, disable the nav history
18036                                // to avoid creating a history entry at the previous cursor location.
18037                                pane.update(cx, |pane, _| pane.disable_history());
18038                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18039
18040                                let nav_data = target_editor.navigation_data(
18041                                    target_editor.selections.newest_anchor().head(),
18042                                    cx,
18043                                );
18044                                let target =
18045                                    Some(nav_history.navigation_entry(Some(
18046                                        Arc::new(nav_data) as Arc<dyn Any + Send + Sync>
18047                                    )));
18048                                nav_history.push_tag(origin, target);
18049                                pane.update(cx, |pane, _| pane.enable_history());
18050                            });
18051                        });
18052                    }
18053                    Navigated::Yes
18054                })
18055            }
18056        })
18057    }
18058
18059    fn compute_target_location(
18060        &self,
18061        lsp_location: lsp::Location,
18062        server_id: LanguageServerId,
18063        window: &mut Window,
18064        cx: &mut Context<Self>,
18065    ) -> Task<anyhow::Result<Option<Location>>> {
18066        let Some(project) = self.project.clone() else {
18067            return Task::ready(Ok(None));
18068        };
18069
18070        cx.spawn_in(window, async move |editor, cx| {
18071            let location_task = editor.update(cx, |_, cx| {
18072                project.update(cx, |project, cx| {
18073                    project.open_local_buffer_via_lsp(lsp_location.uri.clone(), server_id, cx)
18074                })
18075            })?;
18076            let location = Some({
18077                let target_buffer_handle = location_task.await.context("open local buffer")?;
18078                let range = target_buffer_handle.read_with(cx, |target_buffer, _| {
18079                    let target_start = target_buffer
18080                        .clip_point_utf16(point_from_lsp(lsp_location.range.start), Bias::Left);
18081                    let target_end = target_buffer
18082                        .clip_point_utf16(point_from_lsp(lsp_location.range.end), Bias::Left);
18083                    target_buffer.anchor_after(target_start)
18084                        ..target_buffer.anchor_before(target_end)
18085                });
18086                Location {
18087                    buffer: target_buffer_handle,
18088                    range,
18089                }
18090            });
18091            Ok(location)
18092        })
18093    }
18094
18095    fn go_to_next_reference(
18096        &mut self,
18097        _: &GoToNextReference,
18098        window: &mut Window,
18099        cx: &mut Context<Self>,
18100    ) {
18101        let task = self.go_to_reference_before_or_after_position(Direction::Next, 1, window, cx);
18102        if let Some(task) = task {
18103            task.detach();
18104        };
18105    }
18106
18107    fn go_to_prev_reference(
18108        &mut self,
18109        _: &GoToPreviousReference,
18110        window: &mut Window,
18111        cx: &mut Context<Self>,
18112    ) {
18113        let task = self.go_to_reference_before_or_after_position(Direction::Prev, 1, window, cx);
18114        if let Some(task) = task {
18115            task.detach();
18116        };
18117    }
18118
18119    pub fn go_to_reference_before_or_after_position(
18120        &mut self,
18121        direction: Direction,
18122        count: usize,
18123        window: &mut Window,
18124        cx: &mut Context<Self>,
18125    ) -> Option<Task<Result<()>>> {
18126        let selection = self.selections.newest_anchor();
18127        let head = selection.head();
18128
18129        let multi_buffer = self.buffer.read(cx);
18130
18131        let (buffer, text_head) = multi_buffer.text_anchor_for_position(head, cx)?;
18132        let workspace = self.workspace()?;
18133        let project = workspace.read(cx).project().clone();
18134        let references =
18135            project.update(cx, |project, cx| project.references(&buffer, text_head, cx));
18136        Some(cx.spawn_in(window, async move |editor, cx| -> Result<()> {
18137            let Some(locations) = references.await? else {
18138                return Ok(());
18139            };
18140
18141            if locations.is_empty() {
18142                // totally normal - the cursor may be on something which is not
18143                // a symbol (e.g. a keyword)
18144                log::info!("no references found under cursor");
18145                return Ok(());
18146            }
18147
18148            let multi_buffer = editor.read_with(cx, |editor, _| editor.buffer().clone())?;
18149
18150            let (locations, current_location_index) =
18151                multi_buffer.update(cx, |multi_buffer, cx| {
18152                    let mut locations = locations
18153                        .into_iter()
18154                        .filter_map(|loc| {
18155                            let start = multi_buffer.buffer_anchor_to_anchor(
18156                                &loc.buffer,
18157                                loc.range.start,
18158                                cx,
18159                            )?;
18160                            let end = multi_buffer.buffer_anchor_to_anchor(
18161                                &loc.buffer,
18162                                loc.range.end,
18163                                cx,
18164                            )?;
18165                            Some(start..end)
18166                        })
18167                        .collect::<Vec<_>>();
18168
18169                    let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18170                    // There is an O(n) implementation, but given this list will be
18171                    // small (usually <100 items), the extra O(log(n)) factor isn't
18172                    // worth the (surprisingly large amount of) extra complexity.
18173                    locations
18174                        .sort_unstable_by(|l, r| l.start.cmp(&r.start, &multi_buffer_snapshot));
18175
18176                    let head_offset = head.to_offset(&multi_buffer_snapshot);
18177
18178                    let current_location_index = locations.iter().position(|loc| {
18179                        loc.start.to_offset(&multi_buffer_snapshot) <= head_offset
18180                            && loc.end.to_offset(&multi_buffer_snapshot) >= head_offset
18181                    });
18182
18183                    (locations, current_location_index)
18184                });
18185
18186            let Some(current_location_index) = current_location_index else {
18187                // This indicates something has gone wrong, because we already
18188                // handle the "no references" case above
18189                log::error!(
18190                    "failed to find current reference under cursor. Total references: {}",
18191                    locations.len()
18192                );
18193                return Ok(());
18194            };
18195
18196            let destination_location_index = match direction {
18197                Direction::Next => (current_location_index + count) % locations.len(),
18198                Direction::Prev => {
18199                    (current_location_index + locations.len() - count % locations.len())
18200                        % locations.len()
18201                }
18202            };
18203
18204            // TODO(cameron): is this needed?
18205            // the thinking is to avoid "jumping to the current location" (avoid
18206            // polluting "jumplist" in vim terms)
18207            if current_location_index == destination_location_index {
18208                return Ok(());
18209            }
18210
18211            let Range { start, end } = locations[destination_location_index];
18212
18213            editor.update_in(cx, |editor, window, cx| {
18214                let effects = SelectionEffects::default();
18215
18216                editor.unfold_ranges(&[start..end], false, false, cx);
18217                editor.change_selections(effects, window, cx, |s| {
18218                    s.select_ranges([start..start]);
18219                });
18220            })?;
18221
18222            Ok(())
18223        }))
18224    }
18225
18226    pub fn find_all_references(
18227        &mut self,
18228        action: &FindAllReferences,
18229        window: &mut Window,
18230        cx: &mut Context<Self>,
18231    ) -> Option<Task<Result<Navigated>>> {
18232        let always_open_multibuffer = action.always_open_multibuffer;
18233        let selection = self.selections.newest_anchor();
18234        let multi_buffer = self.buffer.read(cx);
18235        let multi_buffer_snapshot = multi_buffer.snapshot(cx);
18236        let selection_offset = selection.map(|anchor| anchor.to_offset(&multi_buffer_snapshot));
18237        let selection_point = selection.map(|anchor| anchor.to_point(&multi_buffer_snapshot));
18238        let head = selection_offset.head();
18239
18240        let head_anchor = multi_buffer_snapshot.anchor_at(
18241            head,
18242            if head < selection_offset.tail() {
18243                Bias::Right
18244            } else {
18245                Bias::Left
18246            },
18247        );
18248
18249        match self
18250            .find_all_references_task_sources
18251            .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18252        {
18253            Ok(_) => {
18254                log::info!(
18255                    "Ignoring repeated FindAllReferences invocation with the position of already running task"
18256                );
18257                return None;
18258            }
18259            Err(i) => {
18260                self.find_all_references_task_sources.insert(i, head_anchor);
18261            }
18262        }
18263
18264        let (buffer, head) = multi_buffer.text_anchor_for_position(head, cx)?;
18265        let workspace = self.workspace()?;
18266        let project = workspace.read(cx).project().clone();
18267        let references = project.update(cx, |project, cx| project.references(&buffer, head, cx));
18268        Some(cx.spawn_in(window, async move |editor, cx| {
18269            let _cleanup = cx.on_drop(&editor, move |editor, _| {
18270                if let Ok(i) = editor
18271                    .find_all_references_task_sources
18272                    .binary_search_by(|anchor| anchor.cmp(&head_anchor, &multi_buffer_snapshot))
18273                {
18274                    editor.find_all_references_task_sources.remove(i);
18275                }
18276            });
18277
18278            let Some(locations) = references.await? else {
18279                return anyhow::Ok(Navigated::No);
18280            };
18281            let mut locations = cx.update(|_, cx| {
18282                locations
18283                    .into_iter()
18284                    .map(|location| {
18285                        let buffer = location.buffer.read(cx);
18286                        (location.buffer, location.range.to_point(buffer))
18287                    })
18288                    // if special-casing the single-match case, remove ranges
18289                    // that intersect current selection
18290                    .filter(|(location_buffer, location)| {
18291                        if always_open_multibuffer || &buffer != location_buffer {
18292                            return true;
18293                        }
18294
18295                        !location.contains_inclusive(&selection_point.range())
18296                    })
18297                    .into_group_map()
18298            })?;
18299            if locations.is_empty() {
18300                return anyhow::Ok(Navigated::No);
18301            }
18302            for ranges in locations.values_mut() {
18303                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18304                ranges.dedup();
18305            }
18306            let mut num_locations = 0;
18307            for ranges in locations.values_mut() {
18308                ranges.sort_by_key(|range| (range.start, Reverse(range.end)));
18309                ranges.dedup();
18310                num_locations += ranges.len();
18311            }
18312
18313            if num_locations == 1 && !always_open_multibuffer {
18314                let (target_buffer, target_ranges) = locations.into_iter().next().unwrap();
18315                let target_range = target_ranges.first().unwrap().clone();
18316
18317                return editor.update_in(cx, |editor, window, cx| {
18318                    let range = target_range.to_point(target_buffer.read(cx));
18319                    let range = editor.range_for_match(&range);
18320                    let range = range.start..range.start;
18321
18322                    if Some(&target_buffer) == editor.buffer.read(cx).as_singleton().as_ref() {
18323                        editor.go_to_singleton_buffer_range(range, window, cx);
18324                    } else {
18325                        let pane = workspace.read(cx).active_pane().clone();
18326                        window.defer(cx, move |window, cx| {
18327                            let target_editor: Entity<Self> =
18328                                workspace.update(cx, |workspace, cx| {
18329                                    let pane = workspace.active_pane().clone();
18330
18331                                    let preview_tabs_settings = PreviewTabsSettings::get_global(cx);
18332                                    let keep_old_preview = preview_tabs_settings
18333                                        .enable_keep_preview_on_code_navigation;
18334                                    let allow_new_preview = preview_tabs_settings
18335                                        .enable_preview_file_from_code_navigation;
18336
18337                                    workspace.open_project_item(
18338                                        pane,
18339                                        target_buffer.clone(),
18340                                        true,
18341                                        true,
18342                                        keep_old_preview,
18343                                        allow_new_preview,
18344                                        window,
18345                                        cx,
18346                                    )
18347                                });
18348                            target_editor.update(cx, |target_editor, cx| {
18349                                // When selecting a definition in a different buffer, disable the nav history
18350                                // to avoid creating a history entry at the previous cursor location.
18351                                pane.update(cx, |pane, _| pane.disable_history());
18352                                target_editor.go_to_singleton_buffer_range(range, window, cx);
18353                                pane.update(cx, |pane, _| pane.enable_history());
18354                            });
18355                        });
18356                    }
18357                    Navigated::No
18358                });
18359            }
18360
18361            workspace.update_in(cx, |workspace, window, cx| {
18362                let target = locations
18363                    .iter()
18364                    .flat_map(|(k, v)| iter::repeat(k.clone()).zip(v))
18365                    .map(|(buffer, location)| {
18366                        buffer
18367                            .read(cx)
18368                            .text_for_range(location.clone())
18369                            .collect::<String>()
18370                    })
18371                    .filter(|text| !text.contains('\n'))
18372                    .unique()
18373                    .take(3)
18374                    .join(", ");
18375                let title = if target.is_empty() {
18376                    "References".to_owned()
18377                } else {
18378                    format!("References to {target}")
18379                };
18380                let allow_preview = PreviewTabsSettings::get_global(cx)
18381                    .enable_preview_multibuffer_from_code_navigation;
18382                Self::open_locations_in_multibuffer(
18383                    workspace,
18384                    locations,
18385                    title,
18386                    false,
18387                    allow_preview,
18388                    MultibufferSelectionMode::First,
18389                    window,
18390                    cx,
18391                );
18392                Navigated::Yes
18393            })
18394        }))
18395    }
18396
18397    /// Opens a multibuffer with the given project locations in it.
18398    pub fn open_locations_in_multibuffer(
18399        workspace: &mut Workspace,
18400        locations: std::collections::HashMap<Entity<Buffer>, Vec<Range<Point>>>,
18401        title: String,
18402        split: bool,
18403        allow_preview: bool,
18404        multibuffer_selection_mode: MultibufferSelectionMode,
18405        window: &mut Window,
18406        cx: &mut Context<Workspace>,
18407    ) -> Option<(Entity<Editor>, Entity<Pane>)> {
18408        if locations.is_empty() {
18409            log::error!("bug: open_locations_in_multibuffer called with empty list of locations");
18410            return None;
18411        }
18412
18413        let capability = workspace.project().read(cx).capability();
18414        let mut ranges = <Vec<Range<Anchor>>>::new();
18415
18416        // a key to find existing multibuffer editors with the same set of locations
18417        // to prevent us from opening more and more multibuffer tabs for searches and the like
18418        let mut key = (title.clone(), vec![]);
18419        let excerpt_buffer = cx.new(|cx| {
18420            let key = &mut key.1;
18421            let mut multibuffer = MultiBuffer::new(capability);
18422            for (buffer, mut ranges_for_buffer) in locations {
18423                ranges_for_buffer.sort_by_key(|range| (range.start, Reverse(range.end)));
18424                key.push((buffer.read(cx).remote_id(), ranges_for_buffer.clone()));
18425                let (new_ranges, _) = multibuffer.set_excerpts_for_path(
18426                    PathKey::for_buffer(&buffer, cx),
18427                    buffer.clone(),
18428                    ranges_for_buffer,
18429                    multibuffer_context_lines(cx),
18430                    cx,
18431                );
18432                ranges.extend(new_ranges)
18433            }
18434
18435            multibuffer.with_title(title)
18436        });
18437        let existing = workspace.active_pane().update(cx, |pane, cx| {
18438            pane.items()
18439                .filter_map(|item| item.downcast::<Editor>())
18440                .find(|editor| {
18441                    editor
18442                        .read(cx)
18443                        .lookup_key
18444                        .as_ref()
18445                        .and_then(|it| {
18446                            it.downcast_ref::<(String, Vec<(BufferId, Vec<Range<Point>>)>)>()
18447                        })
18448                        .is_some_and(|it| *it == key)
18449                })
18450        });
18451        let was_existing = existing.is_some();
18452        let editor = existing.unwrap_or_else(|| {
18453            cx.new(|cx| {
18454                let mut editor = Editor::for_multibuffer(
18455                    excerpt_buffer,
18456                    Some(workspace.project().clone()),
18457                    window,
18458                    cx,
18459                );
18460                editor.lookup_key = Some(Box::new(key));
18461                editor
18462            })
18463        });
18464        editor.update(cx, |editor, cx| match multibuffer_selection_mode {
18465            MultibufferSelectionMode::First => {
18466                if let Some(first_range) = ranges.first() {
18467                    editor.change_selections(
18468                        SelectionEffects::no_scroll(),
18469                        window,
18470                        cx,
18471                        |selections| {
18472                            selections.clear_disjoint();
18473                            selections.select_anchor_ranges(std::iter::once(first_range.clone()));
18474                        },
18475                    );
18476                }
18477                editor.highlight_background(
18478                    HighlightKey::Editor,
18479                    &ranges,
18480                    |_, theme| theme.colors().editor_highlighted_line_background,
18481                    cx,
18482                );
18483            }
18484            MultibufferSelectionMode::All => {
18485                editor.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
18486                    selections.clear_disjoint();
18487                    selections.select_anchor_ranges(ranges);
18488                });
18489            }
18490        });
18491
18492        let item = Box::new(editor.clone());
18493
18494        let pane = if split {
18495            workspace.adjacent_pane(window, cx)
18496        } else {
18497            workspace.active_pane().clone()
18498        };
18499        let activate_pane = split;
18500
18501        let mut destination_index = None;
18502        pane.update(cx, |pane, cx| {
18503            if allow_preview && !was_existing {
18504                destination_index = pane.replace_preview_item_id(item.item_id(), window, cx);
18505            }
18506            if was_existing && !allow_preview {
18507                pane.unpreview_item_if_preview(item.item_id());
18508            }
18509            pane.add_item(item, activate_pane, true, destination_index, window, cx);
18510        });
18511
18512        Some((editor, pane))
18513    }
18514
18515    pub fn rename(
18516        &mut self,
18517        _: &Rename,
18518        window: &mut Window,
18519        cx: &mut Context<Self>,
18520    ) -> Option<Task<Result<()>>> {
18521        use language::ToOffset as _;
18522
18523        let provider = self.semantics_provider.clone()?;
18524        let selection = self.selections.newest_anchor().clone();
18525        let (cursor_buffer, cursor_buffer_position) = self
18526            .buffer
18527            .read(cx)
18528            .text_anchor_for_position(selection.head(), cx)?;
18529        let (tail_buffer, cursor_buffer_position_end) = self
18530            .buffer
18531            .read(cx)
18532            .text_anchor_for_position(selection.tail(), cx)?;
18533        if tail_buffer != cursor_buffer {
18534            return None;
18535        }
18536
18537        let snapshot = cursor_buffer.read(cx).snapshot();
18538        let cursor_buffer_offset = cursor_buffer_position.to_offset(&snapshot);
18539        let cursor_buffer_offset_end = cursor_buffer_position_end.to_offset(&snapshot);
18540        let prepare_rename = provider
18541            .range_for_rename(&cursor_buffer, cursor_buffer_position, cx)
18542            .unwrap_or_else(|| Task::ready(Ok(None)));
18543        drop(snapshot);
18544
18545        Some(cx.spawn_in(window, async move |this, cx| {
18546            let rename_range = if let Some(range) = prepare_rename.await? {
18547                Some(range)
18548            } else {
18549                this.update(cx, |this, cx| {
18550                    let buffer = this.buffer.read(cx).snapshot(cx);
18551                    let mut buffer_highlights = this
18552                        .document_highlights_for_position(selection.head(), &buffer)
18553                        .filter(|highlight| {
18554                            highlight.start.excerpt_id == selection.head().excerpt_id
18555                                && highlight.end.excerpt_id == selection.head().excerpt_id
18556                        });
18557                    buffer_highlights
18558                        .next()
18559                        .map(|highlight| highlight.start.text_anchor..highlight.end.text_anchor)
18560                })?
18561            };
18562            if let Some(rename_range) = rename_range {
18563                this.update_in(cx, |this, window, cx| {
18564                    let snapshot = cursor_buffer.read(cx).snapshot();
18565                    let rename_buffer_range = rename_range.to_offset(&snapshot);
18566                    let cursor_offset_in_rename_range =
18567                        cursor_buffer_offset.saturating_sub(rename_buffer_range.start);
18568                    let cursor_offset_in_rename_range_end =
18569                        cursor_buffer_offset_end.saturating_sub(rename_buffer_range.start);
18570
18571                    this.take_rename(false, window, cx);
18572                    let buffer = this.buffer.read(cx).read(cx);
18573                    let cursor_offset = selection.head().to_offset(&buffer);
18574                    let rename_start =
18575                        cursor_offset.saturating_sub_usize(cursor_offset_in_rename_range);
18576                    let rename_end = rename_start + rename_buffer_range.len();
18577                    let range = buffer.anchor_before(rename_start)..buffer.anchor_after(rename_end);
18578                    let mut old_highlight_id = None;
18579                    let old_name: Arc<str> = buffer
18580                        .chunks(rename_start..rename_end, true)
18581                        .map(|chunk| {
18582                            if old_highlight_id.is_none() {
18583                                old_highlight_id = chunk.syntax_highlight_id;
18584                            }
18585                            chunk.text
18586                        })
18587                        .collect::<String>()
18588                        .into();
18589
18590                    drop(buffer);
18591
18592                    // Position the selection in the rename editor so that it matches the current selection.
18593                    this.show_local_selections = false;
18594                    let rename_editor = cx.new(|cx| {
18595                        let mut editor = Editor::single_line(window, cx);
18596                        editor.buffer.update(cx, |buffer, cx| {
18597                            buffer.edit(
18598                                [(MultiBufferOffset(0)..MultiBufferOffset(0), old_name.clone())],
18599                                None,
18600                                cx,
18601                            )
18602                        });
18603                        let cursor_offset_in_rename_range =
18604                            MultiBufferOffset(cursor_offset_in_rename_range);
18605                        let cursor_offset_in_rename_range_end =
18606                            MultiBufferOffset(cursor_offset_in_rename_range_end);
18607                        let rename_selection_range = match cursor_offset_in_rename_range
18608                            .cmp(&cursor_offset_in_rename_range_end)
18609                        {
18610                            Ordering::Equal => {
18611                                editor.select_all(&SelectAll, window, cx);
18612                                return editor;
18613                            }
18614                            Ordering::Less => {
18615                                cursor_offset_in_rename_range..cursor_offset_in_rename_range_end
18616                            }
18617                            Ordering::Greater => {
18618                                cursor_offset_in_rename_range_end..cursor_offset_in_rename_range
18619                            }
18620                        };
18621                        if rename_selection_range.end.0 > old_name.len() {
18622                            editor.select_all(&SelectAll, window, cx);
18623                        } else {
18624                            editor.change_selections(Default::default(), window, cx, |s| {
18625                                s.select_ranges([rename_selection_range]);
18626                            });
18627                        }
18628                        editor
18629                    });
18630                    cx.subscribe(&rename_editor, |_, _, e: &EditorEvent, cx| {
18631                        if e == &EditorEvent::Focused {
18632                            cx.emit(EditorEvent::FocusedIn)
18633                        }
18634                    })
18635                    .detach();
18636
18637                    let write_highlights =
18638                        this.clear_background_highlights(HighlightKey::DocumentHighlightWrite, cx);
18639                    let read_highlights =
18640                        this.clear_background_highlights(HighlightKey::DocumentHighlightRead, cx);
18641                    let ranges = write_highlights
18642                        .iter()
18643                        .flat_map(|(_, ranges)| ranges.iter())
18644                        .chain(read_highlights.iter().flat_map(|(_, ranges)| ranges.iter()))
18645                        .cloned()
18646                        .collect();
18647
18648                    this.highlight_text(
18649                        HighlightKey::Rename,
18650                        ranges,
18651                        HighlightStyle {
18652                            fade_out: Some(0.6),
18653                            ..Default::default()
18654                        },
18655                        cx,
18656                    );
18657                    let rename_focus_handle = rename_editor.focus_handle(cx);
18658                    window.focus(&rename_focus_handle, cx);
18659                    let block_id = this.insert_blocks(
18660                        [BlockProperties {
18661                            style: BlockStyle::Flex,
18662                            placement: BlockPlacement::Below(range.start),
18663                            height: Some(1),
18664                            render: Arc::new({
18665                                let rename_editor = rename_editor.clone();
18666                                move |cx: &mut BlockContext| {
18667                                    let mut text_style = cx.editor_style.text.clone();
18668                                    if let Some(highlight_style) = old_highlight_id
18669                                        .and_then(|h| h.style(&cx.editor_style.syntax))
18670                                    {
18671                                        text_style = text_style.highlight(highlight_style);
18672                                    }
18673                                    div()
18674                                        .block_mouse_except_scroll()
18675                                        .pl(cx.anchor_x)
18676                                        .child(EditorElement::new(
18677                                            &rename_editor,
18678                                            EditorStyle {
18679                                                background: cx.theme().system().transparent,
18680                                                local_player: cx.editor_style.local_player,
18681                                                text: text_style,
18682                                                scrollbar_width: cx.editor_style.scrollbar_width,
18683                                                syntax: cx.editor_style.syntax.clone(),
18684                                                status: cx.editor_style.status.clone(),
18685                                                inlay_hints_style: HighlightStyle {
18686                                                    font_weight: Some(FontWeight::BOLD),
18687                                                    ..make_inlay_hints_style(cx.app)
18688                                                },
18689                                                edit_prediction_styles: make_suggestion_styles(
18690                                                    cx.app,
18691                                                ),
18692                                                ..EditorStyle::default()
18693                                            },
18694                                        ))
18695                                        .into_any_element()
18696                                }
18697                            }),
18698                            priority: 0,
18699                        }],
18700                        Some(Autoscroll::fit()),
18701                        cx,
18702                    )[0];
18703                    this.pending_rename = Some(RenameState {
18704                        range,
18705                        old_name,
18706                        editor: rename_editor,
18707                        block_id,
18708                    });
18709                })?;
18710            }
18711
18712            Ok(())
18713        }))
18714    }
18715
18716    pub fn confirm_rename(
18717        &mut self,
18718        _: &ConfirmRename,
18719        window: &mut Window,
18720        cx: &mut Context<Self>,
18721    ) -> Option<Task<Result<()>>> {
18722        let rename = self.take_rename(false, window, cx)?;
18723        let workspace = self.workspace()?.downgrade();
18724        let (buffer, start) = self
18725            .buffer
18726            .read(cx)
18727            .text_anchor_for_position(rename.range.start, cx)?;
18728        let (end_buffer, _) = self
18729            .buffer
18730            .read(cx)
18731            .text_anchor_for_position(rename.range.end, cx)?;
18732        if buffer != end_buffer {
18733            return None;
18734        }
18735
18736        let old_name = rename.old_name;
18737        let new_name = rename.editor.read(cx).text(cx);
18738
18739        let rename = self.semantics_provider.as_ref()?.perform_rename(
18740            &buffer,
18741            start,
18742            new_name.clone(),
18743            cx,
18744        )?;
18745
18746        Some(cx.spawn_in(window, async move |editor, cx| {
18747            let project_transaction = rename.await?;
18748            Self::open_project_transaction(
18749                &editor,
18750                workspace,
18751                project_transaction,
18752                format!("Rename: {}{}", old_name, new_name),
18753                cx,
18754            )
18755            .await?;
18756
18757            editor.update(cx, |editor, cx| {
18758                editor.refresh_document_highlights(cx);
18759            })?;
18760            Ok(())
18761        }))
18762    }
18763
18764    fn take_rename(
18765        &mut self,
18766        moving_cursor: bool,
18767        window: &mut Window,
18768        cx: &mut Context<Self>,
18769    ) -> Option<RenameState> {
18770        let rename = self.pending_rename.take()?;
18771        if rename.editor.focus_handle(cx).is_focused(window) {
18772            window.focus(&self.focus_handle, cx);
18773        }
18774
18775        self.remove_blocks(
18776            [rename.block_id].into_iter().collect(),
18777            Some(Autoscroll::fit()),
18778            cx,
18779        );
18780        self.clear_highlights(HighlightKey::Rename, cx);
18781        self.show_local_selections = true;
18782
18783        if moving_cursor {
18784            let cursor_in_rename_editor = rename.editor.update(cx, |editor, cx| {
18785                editor
18786                    .selections
18787                    .newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
18788                    .head()
18789            });
18790
18791            // Update the selection to match the position of the selection inside
18792            // the rename editor.
18793            let snapshot = self.buffer.read(cx).read(cx);
18794            let rename_range = rename.range.to_offset(&snapshot);
18795            let cursor_in_editor = snapshot
18796                .clip_offset(rename_range.start + cursor_in_rename_editor, Bias::Left)
18797                .min(rename_range.end);
18798            drop(snapshot);
18799
18800            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
18801                s.select_ranges(vec![cursor_in_editor..cursor_in_editor])
18802            });
18803        } else {
18804            self.refresh_document_highlights(cx);
18805        }
18806
18807        Some(rename)
18808    }
18809
18810    pub fn pending_rename(&self) -> Option<&RenameState> {
18811        self.pending_rename.as_ref()
18812    }
18813
18814    fn format(
18815        &mut self,
18816        _: &Format,
18817        window: &mut Window,
18818        cx: &mut Context<Self>,
18819    ) -> Option<Task<Result<()>>> {
18820        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18821
18822        let project = match &self.project {
18823            Some(project) => project.clone(),
18824            None => return None,
18825        };
18826
18827        Some(self.perform_format(
18828            project,
18829            FormatTrigger::Manual,
18830            FormatTarget::Buffers(self.buffer.read(cx).all_buffers()),
18831            window,
18832            cx,
18833        ))
18834    }
18835
18836    fn format_selections(
18837        &mut self,
18838        _: &FormatSelections,
18839        window: &mut Window,
18840        cx: &mut Context<Self>,
18841    ) -> Option<Task<Result<()>>> {
18842        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18843
18844        let project = match &self.project {
18845            Some(project) => project.clone(),
18846            None => return None,
18847        };
18848
18849        let ranges = self
18850            .selections
18851            .all_adjusted(&self.display_snapshot(cx))
18852            .into_iter()
18853            .map(|selection| selection.range())
18854            .collect_vec();
18855
18856        Some(self.perform_format(
18857            project,
18858            FormatTrigger::Manual,
18859            FormatTarget::Ranges(ranges),
18860            window,
18861            cx,
18862        ))
18863    }
18864
18865    fn perform_format(
18866        &mut self,
18867        project: Entity<Project>,
18868        trigger: FormatTrigger,
18869        target: FormatTarget,
18870        window: &mut Window,
18871        cx: &mut Context<Self>,
18872    ) -> Task<Result<()>> {
18873        let buffer = self.buffer.clone();
18874        let (buffers, target) = match target {
18875            FormatTarget::Buffers(buffers) => (buffers, LspFormatTarget::Buffers),
18876            FormatTarget::Ranges(selection_ranges) => {
18877                let multi_buffer = buffer.read(cx);
18878                let snapshot = multi_buffer.read(cx);
18879                let mut buffers = HashSet::default();
18880                let mut buffer_id_to_ranges: BTreeMap<BufferId, Vec<Range<text::Anchor>>> =
18881                    BTreeMap::new();
18882                for selection_range in selection_ranges {
18883                    for (buffer, buffer_range, _) in
18884                        snapshot.range_to_buffer_ranges(selection_range.start..=selection_range.end)
18885                    {
18886                        let buffer_id = buffer.remote_id();
18887                        let start = buffer.anchor_before(buffer_range.start);
18888                        let end = buffer.anchor_after(buffer_range.end);
18889                        buffers.insert(multi_buffer.buffer(buffer_id).unwrap());
18890                        buffer_id_to_ranges
18891                            .entry(buffer_id)
18892                            .and_modify(|buffer_ranges| buffer_ranges.push(start..end))
18893                            .or_insert_with(|| vec![start..end]);
18894                    }
18895                }
18896                (buffers, LspFormatTarget::Ranges(buffer_id_to_ranges))
18897            }
18898        };
18899
18900        let transaction_id_prev = buffer.read(cx).last_transaction_id(cx);
18901        let selections_prev = transaction_id_prev
18902            .and_then(|transaction_id_prev| {
18903                // default to selections as they were after the last edit, if we have them,
18904                // instead of how they are now.
18905                // This will make it so that editing, moving somewhere else, formatting, then undoing the format
18906                // will take you back to where you made the last edit, instead of staying where you scrolled
18907                self.selection_history
18908                    .transaction(transaction_id_prev)
18909                    .map(|t| t.0.clone())
18910            })
18911            .unwrap_or_else(|| self.selections.disjoint_anchors_arc());
18912
18913        let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
18914        let format = project.update(cx, |project, cx| {
18915            project.format(buffers, target, true, trigger, cx)
18916        });
18917
18918        cx.spawn_in(window, async move |editor, cx| {
18919            let transaction = futures::select_biased! {
18920                transaction = format.log_err().fuse() => transaction,
18921                () = timeout => {
18922                    log::warn!("timed out waiting for formatting");
18923                    None
18924                }
18925            };
18926
18927            buffer.update(cx, |buffer, cx| {
18928                if let Some(transaction) = transaction
18929                    && !buffer.is_singleton()
18930                {
18931                    buffer.push_transaction(&transaction.0, cx);
18932                }
18933                cx.notify();
18934            });
18935
18936            if let Some(transaction_id_now) =
18937                buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))
18938            {
18939                let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
18940                if has_new_transaction {
18941                    editor
18942                        .update(cx, |editor, _| {
18943                            editor
18944                                .selection_history
18945                                .insert_transaction(transaction_id_now, selections_prev);
18946                        })
18947                        .ok();
18948                }
18949            }
18950
18951            Ok(())
18952        })
18953    }
18954
18955    fn organize_imports(
18956        &mut self,
18957        _: &OrganizeImports,
18958        window: &mut Window,
18959        cx: &mut Context<Self>,
18960    ) -> Option<Task<Result<()>>> {
18961        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
18962        let project = match &self.project {
18963            Some(project) => project.clone(),
18964            None => return None,
18965        };
18966        Some(self.perform_code_action_kind(
18967            project,
18968            CodeActionKind::SOURCE_ORGANIZE_IMPORTS,
18969            window,
18970            cx,
18971        ))
18972    }
18973
18974    fn perform_code_action_kind(
18975        &mut self,
18976        project: Entity<Project>,
18977        kind: CodeActionKind,
18978        window: &mut Window,
18979        cx: &mut Context<Self>,
18980    ) -> Task<Result<()>> {
18981        let buffer = self.buffer.clone();
18982        let buffers = buffer.read(cx).all_buffers();
18983        let mut timeout = cx.background_executor().timer(CODE_ACTION_TIMEOUT).fuse();
18984        let apply_action = project.update(cx, |project, cx| {
18985            project.apply_code_action_kind(buffers, kind, true, cx)
18986        });
18987        cx.spawn_in(window, async move |_, cx| {
18988            let transaction = futures::select_biased! {
18989                () = timeout => {
18990                    log::warn!("timed out waiting for executing code action");
18991                    None
18992                }
18993                transaction = apply_action.log_err().fuse() => transaction,
18994            };
18995            buffer.update(cx, |buffer, cx| {
18996                // check if we need this
18997                if let Some(transaction) = transaction
18998                    && !buffer.is_singleton()
18999                {
19000                    buffer.push_transaction(&transaction.0, cx);
19001                }
19002                cx.notify();
19003            });
19004            Ok(())
19005        })
19006    }
19007
19008    pub fn restart_language_server(
19009        &mut self,
19010        _: &RestartLanguageServer,
19011        _: &mut Window,
19012        cx: &mut Context<Self>,
19013    ) {
19014        if let Some(project) = self.project.clone() {
19015            self.buffer.update(cx, |multi_buffer, cx| {
19016                project.update(cx, |project, cx| {
19017                    project.restart_language_servers_for_buffers(
19018                        multi_buffer.all_buffers().into_iter().collect(),
19019                        HashSet::default(),
19020                        cx,
19021                    );
19022                });
19023            })
19024        }
19025    }
19026
19027    pub fn stop_language_server(
19028        &mut self,
19029        _: &StopLanguageServer,
19030        _: &mut Window,
19031        cx: &mut Context<Self>,
19032    ) {
19033        if let Some(project) = self.project.clone() {
19034            self.buffer.update(cx, |multi_buffer, cx| {
19035                project.update(cx, |project, cx| {
19036                    project.stop_language_servers_for_buffers(
19037                        multi_buffer.all_buffers().into_iter().collect(),
19038                        HashSet::default(),
19039                        cx,
19040                    );
19041                });
19042            });
19043        }
19044    }
19045
19046    fn cancel_language_server_work(
19047        workspace: &mut Workspace,
19048        _: &actions::CancelLanguageServerWork,
19049        _: &mut Window,
19050        cx: &mut Context<Workspace>,
19051    ) {
19052        let project = workspace.project();
19053        let buffers = workspace
19054            .active_item(cx)
19055            .and_then(|item| item.act_as::<Editor>(cx))
19056            .map_or(HashSet::default(), |editor| {
19057                editor.read(cx).buffer.read(cx).all_buffers()
19058            });
19059        project.update(cx, |project, cx| {
19060            project.cancel_language_server_work_for_buffers(buffers, cx);
19061        });
19062    }
19063
19064    fn show_character_palette(
19065        &mut self,
19066        _: &ShowCharacterPalette,
19067        window: &mut Window,
19068        _: &mut Context<Self>,
19069    ) {
19070        window.show_character_palette();
19071    }
19072
19073    fn refresh_active_diagnostics(&mut self, cx: &mut Context<Editor>) {
19074        if !self.diagnostics_enabled() {
19075            return;
19076        }
19077
19078        if let ActiveDiagnostic::Group(active_diagnostics) = &mut self.active_diagnostics {
19079            let buffer = self.buffer.read(cx).snapshot(cx);
19080            let primary_range_start = active_diagnostics.active_range.start.to_offset(&buffer);
19081            let primary_range_end = active_diagnostics.active_range.end.to_offset(&buffer);
19082            let is_valid = buffer
19083                .diagnostics_in_range::<MultiBufferOffset>(primary_range_start..primary_range_end)
19084                .any(|entry| {
19085                    entry.diagnostic.is_primary
19086                        && !entry.range.is_empty()
19087                        && entry.range.start == primary_range_start
19088                        && entry.diagnostic.message == active_diagnostics.active_message
19089                });
19090
19091            if !is_valid {
19092                self.dismiss_diagnostics(cx);
19093            }
19094        }
19095    }
19096
19097    pub fn active_diagnostic_group(&self) -> Option<&ActiveDiagnosticGroup> {
19098        match &self.active_diagnostics {
19099            ActiveDiagnostic::Group(group) => Some(group),
19100            _ => None,
19101        }
19102    }
19103
19104    pub fn set_all_diagnostics_active(&mut self, cx: &mut Context<Self>) {
19105        if !self.diagnostics_enabled() {
19106            return;
19107        }
19108        self.dismiss_diagnostics(cx);
19109        self.active_diagnostics = ActiveDiagnostic::All;
19110    }
19111
19112    fn activate_diagnostics(
19113        &mut self,
19114        buffer_id: BufferId,
19115        diagnostic: DiagnosticEntryRef<'_, MultiBufferOffset>,
19116        window: &mut Window,
19117        cx: &mut Context<Self>,
19118    ) {
19119        if !self.diagnostics_enabled() || matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19120            return;
19121        }
19122        self.dismiss_diagnostics(cx);
19123        let snapshot = self.snapshot(window, cx);
19124        let buffer = self.buffer.read(cx).snapshot(cx);
19125        let Some(renderer) = GlobalDiagnosticRenderer::global(cx) else {
19126            return;
19127        };
19128
19129        let diagnostic_group = buffer
19130            .diagnostic_group(buffer_id, diagnostic.diagnostic.group_id)
19131            .collect::<Vec<_>>();
19132
19133        let language_registry = self
19134            .project()
19135            .map(|project| project.read(cx).languages().clone());
19136
19137        let blocks = renderer.render_group(
19138            diagnostic_group,
19139            buffer_id,
19140            snapshot,
19141            cx.weak_entity(),
19142            language_registry,
19143            cx,
19144        );
19145
19146        let blocks = self.display_map.update(cx, |display_map, cx| {
19147            display_map.insert_blocks(blocks, cx).into_iter().collect()
19148        });
19149        self.active_diagnostics = ActiveDiagnostic::Group(ActiveDiagnosticGroup {
19150            active_range: buffer.anchor_before(diagnostic.range.start)
19151                ..buffer.anchor_after(diagnostic.range.end),
19152            active_message: diagnostic.diagnostic.message.clone(),
19153            group_id: diagnostic.diagnostic.group_id,
19154            blocks,
19155        });
19156        cx.notify();
19157    }
19158
19159    fn dismiss_diagnostics(&mut self, cx: &mut Context<Self>) {
19160        if matches!(self.active_diagnostics, ActiveDiagnostic::All) {
19161            return;
19162        };
19163
19164        let prev = mem::replace(&mut self.active_diagnostics, ActiveDiagnostic::None);
19165        if let ActiveDiagnostic::Group(group) = prev {
19166            self.display_map.update(cx, |display_map, cx| {
19167                display_map.remove_blocks(group.blocks, cx);
19168            });
19169            cx.notify();
19170        }
19171    }
19172
19173    /// Disable inline diagnostics rendering for this editor.
19174    pub fn disable_inline_diagnostics(&mut self) {
19175        self.inline_diagnostics_enabled = false;
19176        self.inline_diagnostics_update = Task::ready(());
19177        self.inline_diagnostics.clear();
19178    }
19179
19180    pub fn disable_diagnostics(&mut self, cx: &mut Context<Self>) {
19181        self.diagnostics_enabled = false;
19182        self.dismiss_diagnostics(cx);
19183        self.inline_diagnostics_update = Task::ready(());
19184        self.inline_diagnostics.clear();
19185    }
19186
19187    pub fn disable_word_completions(&mut self) {
19188        self.word_completions_enabled = false;
19189    }
19190
19191    pub fn diagnostics_enabled(&self) -> bool {
19192        self.diagnostics_enabled && self.lsp_data_enabled()
19193    }
19194
19195    pub fn inline_diagnostics_enabled(&self) -> bool {
19196        self.inline_diagnostics_enabled && self.diagnostics_enabled()
19197    }
19198
19199    pub fn show_inline_diagnostics(&self) -> bool {
19200        self.show_inline_diagnostics
19201    }
19202
19203    pub fn toggle_inline_diagnostics(
19204        &mut self,
19205        _: &ToggleInlineDiagnostics,
19206        window: &mut Window,
19207        cx: &mut Context<Editor>,
19208    ) {
19209        self.show_inline_diagnostics = !self.show_inline_diagnostics;
19210        self.refresh_inline_diagnostics(false, window, cx);
19211    }
19212
19213    pub fn set_max_diagnostics_severity(&mut self, severity: DiagnosticSeverity, cx: &mut App) {
19214        self.diagnostics_max_severity = severity;
19215        self.display_map.update(cx, |display_map, _| {
19216            display_map.diagnostics_max_severity = self.diagnostics_max_severity;
19217        });
19218    }
19219
19220    pub fn toggle_diagnostics(
19221        &mut self,
19222        _: &ToggleDiagnostics,
19223        window: &mut Window,
19224        cx: &mut Context<Editor>,
19225    ) {
19226        if !self.diagnostics_enabled() {
19227            return;
19228        }
19229
19230        let new_severity = if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19231            EditorSettings::get_global(cx)
19232                .diagnostics_max_severity
19233                .filter(|severity| severity != &DiagnosticSeverity::Off)
19234                .unwrap_or(DiagnosticSeverity::Hint)
19235        } else {
19236            DiagnosticSeverity::Off
19237        };
19238        self.set_max_diagnostics_severity(new_severity, cx);
19239        if self.diagnostics_max_severity == DiagnosticSeverity::Off {
19240            self.active_diagnostics = ActiveDiagnostic::None;
19241            self.inline_diagnostics_update = Task::ready(());
19242            self.inline_diagnostics.clear();
19243        } else {
19244            self.refresh_inline_diagnostics(false, window, cx);
19245        }
19246
19247        cx.notify();
19248    }
19249
19250    pub fn toggle_minimap(
19251        &mut self,
19252        _: &ToggleMinimap,
19253        window: &mut Window,
19254        cx: &mut Context<Editor>,
19255    ) {
19256        if self.supports_minimap(cx) {
19257            self.set_minimap_visibility(self.minimap_visibility.toggle_visibility(), window, cx);
19258        }
19259    }
19260
19261    fn refresh_inline_diagnostics(
19262        &mut self,
19263        debounce: bool,
19264        window: &mut Window,
19265        cx: &mut Context<Self>,
19266    ) {
19267        let max_severity = ProjectSettings::get_global(cx)
19268            .diagnostics
19269            .inline
19270            .max_severity
19271            .unwrap_or(self.diagnostics_max_severity);
19272
19273        if !self.inline_diagnostics_enabled()
19274            || !self.diagnostics_enabled()
19275            || !self.show_inline_diagnostics
19276            || max_severity == DiagnosticSeverity::Off
19277        {
19278            self.inline_diagnostics_update = Task::ready(());
19279            self.inline_diagnostics.clear();
19280            return;
19281        }
19282
19283        let debounce_ms = ProjectSettings::get_global(cx)
19284            .diagnostics
19285            .inline
19286            .update_debounce_ms;
19287        let debounce = if debounce && debounce_ms > 0 {
19288            Some(Duration::from_millis(debounce_ms))
19289        } else {
19290            None
19291        };
19292        self.inline_diagnostics_update = cx.spawn_in(window, async move |editor, cx| {
19293            if let Some(debounce) = debounce {
19294                cx.background_executor().timer(debounce).await;
19295            }
19296            let Some(snapshot) = editor.upgrade().map(|editor| {
19297                editor.update(cx, |editor, cx| editor.buffer().read(cx).snapshot(cx))
19298            }) else {
19299                return;
19300            };
19301
19302            let new_inline_diagnostics = cx
19303                .background_spawn(async move {
19304                    let mut inline_diagnostics = Vec::<(Anchor, InlineDiagnostic)>::new();
19305                    for diagnostic_entry in
19306                        snapshot.diagnostics_in_range(MultiBufferOffset(0)..snapshot.len())
19307                    {
19308                        let message = diagnostic_entry
19309                            .diagnostic
19310                            .message
19311                            .split_once('\n')
19312                            .map(|(line, _)| line)
19313                            .map(SharedString::new)
19314                            .unwrap_or_else(|| {
19315                                SharedString::new(&*diagnostic_entry.diagnostic.message)
19316                            });
19317                        let start_anchor = snapshot.anchor_before(diagnostic_entry.range.start);
19318                        let (Ok(i) | Err(i)) = inline_diagnostics
19319                            .binary_search_by(|(probe, _)| probe.cmp(&start_anchor, &snapshot));
19320                        inline_diagnostics.insert(
19321                            i,
19322                            (
19323                                start_anchor,
19324                                InlineDiagnostic {
19325                                    message,
19326                                    group_id: diagnostic_entry.diagnostic.group_id,
19327                                    start: diagnostic_entry.range.start.to_point(&snapshot),
19328                                    is_primary: diagnostic_entry.diagnostic.is_primary,
19329                                    severity: diagnostic_entry.diagnostic.severity,
19330                                },
19331                            ),
19332                        );
19333                    }
19334                    inline_diagnostics
19335                })
19336                .await;
19337
19338            editor
19339                .update(cx, |editor, cx| {
19340                    editor.inline_diagnostics = new_inline_diagnostics;
19341                    cx.notify();
19342                })
19343                .ok();
19344        });
19345    }
19346
19347    fn pull_diagnostics(
19348        &mut self,
19349        buffer_id: BufferId,
19350        _window: &Window,
19351        cx: &mut Context<Self>,
19352    ) -> Option<()> {
19353        // `ActiveDiagnostic::All` is a special mode where editor's diagnostics are managed by the external view,
19354        // skip any LSP updates for it.
19355
19356        if self.active_diagnostics == ActiveDiagnostic::All || !self.diagnostics_enabled() {
19357            return None;
19358        }
19359        let pull_diagnostics_settings = ProjectSettings::get_global(cx)
19360            .diagnostics
19361            .lsp_pull_diagnostics;
19362        if !pull_diagnostics_settings.enabled {
19363            return None;
19364        }
19365        let debounce = Duration::from_millis(pull_diagnostics_settings.debounce_ms);
19366        let project = self.project()?.downgrade();
19367        let buffer = self.buffer().read(cx).buffer(buffer_id)?;
19368
19369        self.pull_diagnostics_task = cx.spawn(async move |_, cx| {
19370            cx.background_executor().timer(debounce).await;
19371            if let Ok(task) = project.update(cx, |project, cx| {
19372                project.lsp_store().update(cx, |lsp_store, cx| {
19373                    lsp_store.pull_diagnostics_for_buffer(buffer, cx)
19374                })
19375            }) {
19376                task.await.log_err();
19377            }
19378            project
19379                .update(cx, |project, cx| {
19380                    project.lsp_store().update(cx, |lsp_store, cx| {
19381                        lsp_store.pull_document_diagnostics_for_buffer_edit(buffer_id, cx);
19382                    })
19383                })
19384                .log_err();
19385        });
19386
19387        Some(())
19388    }
19389
19390    pub fn set_selections_from_remote(
19391        &mut self,
19392        selections: Vec<Selection<Anchor>>,
19393        pending_selection: Option<Selection<Anchor>>,
19394        window: &mut Window,
19395        cx: &mut Context<Self>,
19396    ) {
19397        let old_cursor_position = self.selections.newest_anchor().head();
19398        self.selections
19399            .change_with(&self.display_snapshot(cx), |s| {
19400                s.select_anchors(selections);
19401                if let Some(pending_selection) = pending_selection {
19402                    s.set_pending(pending_selection, SelectMode::Character);
19403                } else {
19404                    s.clear_pending();
19405                }
19406            });
19407        self.selections_did_change(
19408            false,
19409            &old_cursor_position,
19410            SelectionEffects::default(),
19411            window,
19412            cx,
19413        );
19414    }
19415
19416    pub fn transact(
19417        &mut self,
19418        window: &mut Window,
19419        cx: &mut Context<Self>,
19420        update: impl FnOnce(&mut Self, &mut Window, &mut Context<Self>),
19421    ) -> Option<TransactionId> {
19422        self.with_selection_effects_deferred(window, cx, |this, window, cx| {
19423            this.start_transaction_at(Instant::now(), window, cx);
19424            update(this, window, cx);
19425            this.end_transaction_at(Instant::now(), cx)
19426        })
19427    }
19428
19429    pub fn start_transaction_at(
19430        &mut self,
19431        now: Instant,
19432        window: &mut Window,
19433        cx: &mut Context<Self>,
19434    ) -> Option<TransactionId> {
19435        self.end_selection(window, cx);
19436        if let Some(tx_id) = self
19437            .buffer
19438            .update(cx, |buffer, cx| buffer.start_transaction_at(now, cx))
19439        {
19440            self.selection_history
19441                .insert_transaction(tx_id, self.selections.disjoint_anchors_arc());
19442            cx.emit(EditorEvent::TransactionBegun {
19443                transaction_id: tx_id,
19444            });
19445            Some(tx_id)
19446        } else {
19447            None
19448        }
19449    }
19450
19451    pub fn end_transaction_at(
19452        &mut self,
19453        now: Instant,
19454        cx: &mut Context<Self>,
19455    ) -> Option<TransactionId> {
19456        if let Some(transaction_id) = self
19457            .buffer
19458            .update(cx, |buffer, cx| buffer.end_transaction_at(now, cx))
19459        {
19460            if let Some((_, end_selections)) =
19461                self.selection_history.transaction_mut(transaction_id)
19462            {
19463                *end_selections = Some(self.selections.disjoint_anchors_arc());
19464            } else {
19465                log::error!("unexpectedly ended a transaction that wasn't started by this editor");
19466            }
19467
19468            cx.emit(EditorEvent::Edited { transaction_id });
19469            Some(transaction_id)
19470        } else {
19471            None
19472        }
19473    }
19474
19475    pub fn modify_transaction_selection_history(
19476        &mut self,
19477        transaction_id: TransactionId,
19478        modify: impl FnOnce(&mut (Arc<[Selection<Anchor>]>, Option<Arc<[Selection<Anchor>]>>)),
19479    ) -> bool {
19480        self.selection_history
19481            .transaction_mut(transaction_id)
19482            .map(modify)
19483            .is_some()
19484    }
19485
19486    pub fn set_mark(&mut self, _: &actions::SetMark, window: &mut Window, cx: &mut Context<Self>) {
19487        if self.selection_mark_mode {
19488            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19489                s.move_with(&mut |_, sel| {
19490                    sel.collapse_to(sel.head(), SelectionGoal::None);
19491                });
19492            })
19493        }
19494        self.selection_mark_mode = true;
19495        cx.notify();
19496    }
19497
19498    pub fn swap_selection_ends(
19499        &mut self,
19500        _: &actions::SwapSelectionEnds,
19501        window: &mut Window,
19502        cx: &mut Context<Self>,
19503    ) {
19504        self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
19505            s.move_with(&mut |_, sel| {
19506                if sel.start != sel.end {
19507                    sel.reversed = !sel.reversed
19508                }
19509            });
19510        });
19511        self.request_autoscroll(Autoscroll::newest(), cx);
19512        cx.notify();
19513    }
19514
19515    pub fn toggle_focus(
19516        workspace: &mut Workspace,
19517        _: &actions::ToggleFocus,
19518        window: &mut Window,
19519        cx: &mut Context<Workspace>,
19520    ) {
19521        let Some(item) = workspace.recent_active_item_by_type::<Self>(cx) else {
19522            return;
19523        };
19524        workspace.activate_item(&item, true, true, window, cx);
19525    }
19526
19527    pub fn toggle_fold(
19528        &mut self,
19529        _: &actions::ToggleFold,
19530        window: &mut Window,
19531        cx: &mut Context<Self>,
19532    ) {
19533        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19534            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19535            let selection = self.selections.newest::<Point>(&display_map);
19536
19537            let range = if selection.is_empty() {
19538                let point = selection.head().to_display_point(&display_map);
19539                let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19540                let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19541                    .to_point(&display_map);
19542                start..end
19543            } else {
19544                selection.range()
19545            };
19546            if display_map.folds_in_range(range).next().is_some() {
19547                self.unfold_lines(&Default::default(), window, cx)
19548            } else {
19549                self.fold(&Default::default(), window, cx)
19550            }
19551        } else {
19552            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19553            let buffer_ids: HashSet<_> = self
19554                .selections
19555                .disjoint_anchor_ranges()
19556                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19557                .collect();
19558
19559            let should_unfold = buffer_ids
19560                .iter()
19561                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19562
19563            for buffer_id in buffer_ids {
19564                if should_unfold {
19565                    self.unfold_buffer(buffer_id, cx);
19566                } else {
19567                    self.fold_buffer(buffer_id, cx);
19568                }
19569            }
19570        }
19571    }
19572
19573    pub fn toggle_fold_recursive(
19574        &mut self,
19575        _: &actions::ToggleFoldRecursive,
19576        window: &mut Window,
19577        cx: &mut Context<Self>,
19578    ) {
19579        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
19580
19581        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19582        let range = if selection.is_empty() {
19583            let point = selection.head().to_display_point(&display_map);
19584            let start = DisplayPoint::new(point.row(), 0).to_point(&display_map);
19585            let end = DisplayPoint::new(point.row(), display_map.line_len(point.row()))
19586                .to_point(&display_map);
19587            start..end
19588        } else {
19589            selection.range()
19590        };
19591        if display_map.folds_in_range(range).next().is_some() {
19592            self.unfold_recursive(&Default::default(), window, cx)
19593        } else {
19594            self.fold_recursive(&Default::default(), window, cx)
19595        }
19596    }
19597
19598    pub fn fold(&mut self, _: &actions::Fold, window: &mut Window, cx: &mut Context<Self>) {
19599        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19600            let mut to_fold = Vec::new();
19601            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19602            let selections = self.selections.all_adjusted(&display_map);
19603
19604            for selection in selections {
19605                let range = selection.range().sorted();
19606                let buffer_start_row = range.start.row;
19607
19608                if range.start.row != range.end.row {
19609                    let mut found = false;
19610                    let mut row = range.start.row;
19611                    while row <= range.end.row {
19612                        if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19613                        {
19614                            found = true;
19615                            row = crease.range().end.row + 1;
19616                            to_fold.push(crease);
19617                        } else {
19618                            row += 1
19619                        }
19620                    }
19621                    if found {
19622                        continue;
19623                    }
19624                }
19625
19626                for row in (0..=range.start.row).rev() {
19627                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row))
19628                        && crease.range().end.row >= buffer_start_row
19629                    {
19630                        to_fold.push(crease);
19631                        if row <= range.start.row {
19632                            break;
19633                        }
19634                    }
19635                }
19636            }
19637
19638            self.fold_creases(to_fold, true, window, cx);
19639        } else {
19640            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19641            let buffer_ids = self
19642                .selections
19643                .disjoint_anchor_ranges()
19644                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19645                .collect::<HashSet<_>>();
19646            for buffer_id in buffer_ids {
19647                self.fold_buffer(buffer_id, cx);
19648            }
19649        }
19650    }
19651
19652    pub fn toggle_fold_all(
19653        &mut self,
19654        _: &actions::ToggleFoldAll,
19655        window: &mut Window,
19656        cx: &mut Context<Self>,
19657    ) {
19658        let has_folds = if self.buffer.read(cx).is_singleton() {
19659            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19660            let has_folds = display_map
19661                .folds_in_range(MultiBufferOffset(0)..display_map.buffer_snapshot().len())
19662                .next()
19663                .is_some();
19664            has_folds
19665        } else {
19666            let buffer_ids = self.buffer.read(cx).excerpt_buffer_ids();
19667            let has_folds = buffer_ids
19668                .iter()
19669                .any(|buffer_id| self.is_buffer_folded(*buffer_id, cx));
19670            has_folds
19671        };
19672
19673        if has_folds {
19674            self.unfold_all(&actions::UnfoldAll, window, cx);
19675        } else {
19676            self.fold_all(&actions::FoldAll, window, cx);
19677        }
19678    }
19679
19680    fn fold_at_level(
19681        &mut self,
19682        fold_at: &FoldAtLevel,
19683        window: &mut Window,
19684        cx: &mut Context<Self>,
19685    ) {
19686        if !self.buffer.read(cx).is_singleton() {
19687            return;
19688        }
19689
19690        let fold_at_level = fold_at.0;
19691        let snapshot = self.buffer.read(cx).snapshot(cx);
19692        let mut to_fold = Vec::new();
19693        let mut stack = vec![(0, snapshot.max_row().0, 1)];
19694
19695        let row_ranges_to_keep: Vec<Range<u32>> = self
19696            .selections
19697            .all::<Point>(&self.display_snapshot(cx))
19698            .into_iter()
19699            .map(|sel| sel.start.row..sel.end.row)
19700            .collect();
19701
19702        while let Some((mut start_row, end_row, current_level)) = stack.pop() {
19703            while start_row < end_row {
19704                match self
19705                    .snapshot(window, cx)
19706                    .crease_for_buffer_row(MultiBufferRow(start_row))
19707                {
19708                    Some(crease) => {
19709                        let nested_start_row = crease.range().start.row + 1;
19710                        let nested_end_row = crease.range().end.row;
19711
19712                        if current_level < fold_at_level {
19713                            stack.push((nested_start_row, nested_end_row, current_level + 1));
19714                        } else if current_level == fold_at_level {
19715                            // Fold iff there is no selection completely contained within the fold region
19716                            if !row_ranges_to_keep.iter().any(|selection| {
19717                                selection.end >= nested_start_row
19718                                    && selection.start <= nested_end_row
19719                            }) {
19720                                to_fold.push(crease);
19721                            }
19722                        }
19723
19724                        start_row = nested_end_row + 1;
19725                    }
19726                    None => start_row += 1,
19727                }
19728            }
19729        }
19730
19731        self.fold_creases(to_fold, true, window, cx);
19732    }
19733
19734    pub fn fold_at_level_1(
19735        &mut self,
19736        _: &actions::FoldAtLevel1,
19737        window: &mut Window,
19738        cx: &mut Context<Self>,
19739    ) {
19740        self.fold_at_level(&actions::FoldAtLevel(1), window, cx);
19741    }
19742
19743    pub fn fold_at_level_2(
19744        &mut self,
19745        _: &actions::FoldAtLevel2,
19746        window: &mut Window,
19747        cx: &mut Context<Self>,
19748    ) {
19749        self.fold_at_level(&actions::FoldAtLevel(2), window, cx);
19750    }
19751
19752    pub fn fold_at_level_3(
19753        &mut self,
19754        _: &actions::FoldAtLevel3,
19755        window: &mut Window,
19756        cx: &mut Context<Self>,
19757    ) {
19758        self.fold_at_level(&actions::FoldAtLevel(3), window, cx);
19759    }
19760
19761    pub fn fold_at_level_4(
19762        &mut self,
19763        _: &actions::FoldAtLevel4,
19764        window: &mut Window,
19765        cx: &mut Context<Self>,
19766    ) {
19767        self.fold_at_level(&actions::FoldAtLevel(4), window, cx);
19768    }
19769
19770    pub fn fold_at_level_5(
19771        &mut self,
19772        _: &actions::FoldAtLevel5,
19773        window: &mut Window,
19774        cx: &mut Context<Self>,
19775    ) {
19776        self.fold_at_level(&actions::FoldAtLevel(5), window, cx);
19777    }
19778
19779    pub fn fold_at_level_6(
19780        &mut self,
19781        _: &actions::FoldAtLevel6,
19782        window: &mut Window,
19783        cx: &mut Context<Self>,
19784    ) {
19785        self.fold_at_level(&actions::FoldAtLevel(6), window, cx);
19786    }
19787
19788    pub fn fold_at_level_7(
19789        &mut self,
19790        _: &actions::FoldAtLevel7,
19791        window: &mut Window,
19792        cx: &mut Context<Self>,
19793    ) {
19794        self.fold_at_level(&actions::FoldAtLevel(7), window, cx);
19795    }
19796
19797    pub fn fold_at_level_8(
19798        &mut self,
19799        _: &actions::FoldAtLevel8,
19800        window: &mut Window,
19801        cx: &mut Context<Self>,
19802    ) {
19803        self.fold_at_level(&actions::FoldAtLevel(8), window, cx);
19804    }
19805
19806    pub fn fold_at_level_9(
19807        &mut self,
19808        _: &actions::FoldAtLevel9,
19809        window: &mut Window,
19810        cx: &mut Context<Self>,
19811    ) {
19812        self.fold_at_level(&actions::FoldAtLevel(9), window, cx);
19813    }
19814
19815    pub fn fold_all(&mut self, _: &actions::FoldAll, window: &mut Window, cx: &mut Context<Self>) {
19816        if self.buffer.read(cx).is_singleton() {
19817            let mut fold_ranges = Vec::new();
19818            let snapshot = self.buffer.read(cx).snapshot(cx);
19819
19820            for row in 0..snapshot.max_row().0 {
19821                if let Some(foldable_range) = self
19822                    .snapshot(window, cx)
19823                    .crease_for_buffer_row(MultiBufferRow(row))
19824                {
19825                    fold_ranges.push(foldable_range);
19826                }
19827            }
19828
19829            self.fold_creases(fold_ranges, true, window, cx);
19830        } else {
19831            self.toggle_fold_multiple_buffers = cx.spawn_in(window, async move |editor, cx| {
19832                editor
19833                    .update_in(cx, |editor, _, cx| {
19834                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
19835                            editor.fold_buffer(buffer_id, cx);
19836                        }
19837                    })
19838                    .ok();
19839            });
19840        }
19841    }
19842
19843    pub fn fold_function_bodies(
19844        &mut self,
19845        _: &actions::FoldFunctionBodies,
19846        window: &mut Window,
19847        cx: &mut Context<Self>,
19848    ) {
19849        let snapshot = self.buffer.read(cx).snapshot(cx);
19850
19851        let ranges = snapshot
19852            .text_object_ranges(
19853                MultiBufferOffset(0)..snapshot.len(),
19854                TreeSitterOptions::default(),
19855            )
19856            .filter_map(|(range, obj)| (obj == TextObject::InsideFunction).then_some(range))
19857            .collect::<Vec<_>>();
19858
19859        let creases = ranges
19860            .into_iter()
19861            .map(|range| Crease::simple(range, self.display_map.read(cx).fold_placeholder.clone()))
19862            .collect();
19863
19864        self.fold_creases(creases, true, window, cx);
19865    }
19866
19867    pub fn fold_recursive(
19868        &mut self,
19869        _: &actions::FoldRecursive,
19870        window: &mut Window,
19871        cx: &mut Context<Self>,
19872    ) {
19873        let mut to_fold = Vec::new();
19874        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19875        let selections = self.selections.all_adjusted(&display_map);
19876
19877        for selection in selections {
19878            let range = selection.range().sorted();
19879            let buffer_start_row = range.start.row;
19880
19881            if range.start.row != range.end.row {
19882                let mut found = false;
19883                for row in range.start.row..=range.end.row {
19884                    if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19885                        found = true;
19886                        to_fold.push(crease);
19887                    }
19888                }
19889                if found {
19890                    continue;
19891                }
19892            }
19893
19894            for row in (0..=range.start.row).rev() {
19895                if let Some(crease) = display_map.crease_for_buffer_row(MultiBufferRow(row)) {
19896                    if crease.range().end.row >= buffer_start_row {
19897                        to_fold.push(crease);
19898                    } else {
19899                        break;
19900                    }
19901                }
19902            }
19903        }
19904
19905        self.fold_creases(to_fold, true, window, cx);
19906    }
19907
19908    pub fn fold_at(
19909        &mut self,
19910        buffer_row: MultiBufferRow,
19911        window: &mut Window,
19912        cx: &mut Context<Self>,
19913    ) {
19914        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19915
19916        if let Some(crease) = display_map.crease_for_buffer_row(buffer_row) {
19917            let autoscroll = self
19918                .selections
19919                .all::<Point>(&display_map)
19920                .iter()
19921                .any(|selection| crease.range().overlaps(&selection.range()));
19922
19923            self.fold_creases(vec![crease], autoscroll, window, cx);
19924        }
19925    }
19926
19927    pub fn unfold_lines(&mut self, _: &UnfoldLines, _window: &mut Window, cx: &mut Context<Self>) {
19928        if self.buffer_kind(cx) == ItemBufferKind::Singleton {
19929            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19930            let buffer = display_map.buffer_snapshot();
19931            let selections = self.selections.all::<Point>(&display_map);
19932            let ranges = selections
19933                .iter()
19934                .map(|s| {
19935                    let range = s.display_range(&display_map).sorted();
19936                    let mut start = range.start.to_point(&display_map);
19937                    let mut end = range.end.to_point(&display_map);
19938                    start.column = 0;
19939                    end.column = buffer.line_len(MultiBufferRow(end.row));
19940                    start..end
19941                })
19942                .collect::<Vec<_>>();
19943
19944            self.unfold_ranges(&ranges, true, true, cx);
19945        } else {
19946            let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
19947            let buffer_ids = self
19948                .selections
19949                .disjoint_anchor_ranges()
19950                .flat_map(|range| multi_buffer_snapshot.buffer_ids_for_range(range))
19951                .collect::<HashSet<_>>();
19952            for buffer_id in buffer_ids {
19953                self.unfold_buffer(buffer_id, cx);
19954            }
19955        }
19956    }
19957
19958    pub fn unfold_recursive(
19959        &mut self,
19960        _: &UnfoldRecursive,
19961        _window: &mut Window,
19962        cx: &mut Context<Self>,
19963    ) {
19964        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19965        let selections = self.selections.all::<Point>(&display_map);
19966        let ranges = selections
19967            .iter()
19968            .map(|s| {
19969                let mut range = s.display_range(&display_map).sorted();
19970                *range.start.column_mut() = 0;
19971                *range.end.column_mut() = display_map.line_len(range.end.row());
19972                let start = range.start.to_point(&display_map);
19973                let end = range.end.to_point(&display_map);
19974                start..end
19975            })
19976            .collect::<Vec<_>>();
19977
19978        self.unfold_ranges(&ranges, true, true, cx);
19979    }
19980
19981    pub fn unfold_at(
19982        &mut self,
19983        buffer_row: MultiBufferRow,
19984        _window: &mut Window,
19985        cx: &mut Context<Self>,
19986    ) {
19987        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
19988
19989        let intersection_range = Point::new(buffer_row.0, 0)
19990            ..Point::new(
19991                buffer_row.0,
19992                display_map.buffer_snapshot().line_len(buffer_row),
19993            );
19994
19995        let autoscroll = self
19996            .selections
19997            .all::<Point>(&display_map)
19998            .iter()
19999            .any(|selection| RangeExt::overlaps(&selection.range(), &intersection_range));
20000
20001        self.unfold_ranges(&[intersection_range], true, autoscroll, cx);
20002    }
20003
20004    pub fn unfold_all(
20005        &mut self,
20006        _: &actions::UnfoldAll,
20007        _window: &mut Window,
20008        cx: &mut Context<Self>,
20009    ) {
20010        if self.buffer.read(cx).is_singleton() {
20011            let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20012            self.unfold_ranges(
20013                &[MultiBufferOffset(0)..display_map.buffer_snapshot().len()],
20014                true,
20015                true,
20016                cx,
20017            );
20018        } else {
20019            self.toggle_fold_multiple_buffers = cx.spawn(async move |editor, cx| {
20020                editor
20021                    .update(cx, |editor, cx| {
20022                        for buffer_id in editor.buffer.read(cx).excerpt_buffer_ids() {
20023                            editor.unfold_buffer(buffer_id, cx);
20024                        }
20025                    })
20026                    .ok();
20027            });
20028        }
20029    }
20030
20031    pub fn fold_selected_ranges(
20032        &mut self,
20033        _: &FoldSelectedRanges,
20034        window: &mut Window,
20035        cx: &mut Context<Self>,
20036    ) {
20037        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20038        let selections = self.selections.all_adjusted(&display_map);
20039        let ranges = selections
20040            .into_iter()
20041            .map(|s| Crease::simple(s.range(), display_map.fold_placeholder.clone()))
20042            .collect::<Vec<_>>();
20043        self.fold_creases(ranges, true, window, cx);
20044    }
20045
20046    pub fn fold_ranges<T: ToOffset + Clone>(
20047        &mut self,
20048        ranges: Vec<Range<T>>,
20049        auto_scroll: bool,
20050        window: &mut Window,
20051        cx: &mut Context<Self>,
20052    ) {
20053        let display_map = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20054        let ranges = ranges
20055            .into_iter()
20056            .map(|r| Crease::simple(r, display_map.fold_placeholder.clone()))
20057            .collect::<Vec<_>>();
20058        self.fold_creases(ranges, auto_scroll, window, cx);
20059    }
20060
20061    pub fn fold_creases<T: ToOffset + Clone>(
20062        &mut self,
20063        creases: Vec<Crease<T>>,
20064        auto_scroll: bool,
20065        window: &mut Window,
20066        cx: &mut Context<Self>,
20067    ) {
20068        if creases.is_empty() {
20069            return;
20070        }
20071
20072        self.display_map.update(cx, |map, cx| map.fold(creases, cx));
20073
20074        if auto_scroll {
20075            self.request_autoscroll(Autoscroll::fit(), cx);
20076        }
20077
20078        cx.notify();
20079
20080        self.scrollbar_marker_state.dirty = true;
20081        self.update_data_on_scroll(window, cx);
20082        self.folds_did_change(cx);
20083    }
20084
20085    /// Removes any folds whose ranges intersect any of the given ranges.
20086    pub fn unfold_ranges<T: ToOffset + Clone>(
20087        &mut self,
20088        ranges: &[Range<T>],
20089        inclusive: bool,
20090        auto_scroll: bool,
20091        cx: &mut Context<Self>,
20092    ) {
20093        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20094            map.unfold_intersecting(ranges.iter().cloned(), inclusive, cx);
20095        });
20096        self.folds_did_change(cx);
20097    }
20098
20099    pub fn fold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20100        self.fold_buffers([buffer_id], cx);
20101    }
20102
20103    pub fn fold_buffers(
20104        &mut self,
20105        buffer_ids: impl IntoIterator<Item = BufferId>,
20106        cx: &mut Context<Self>,
20107    ) {
20108        if self.buffer().read(cx).is_singleton() {
20109            return;
20110        }
20111
20112        let ids_to_fold: Vec<BufferId> = buffer_ids
20113            .into_iter()
20114            .filter(|id| !self.is_buffer_folded(*id, cx))
20115            .collect();
20116
20117        if ids_to_fold.is_empty() {
20118            return;
20119        }
20120
20121        let mut all_folded_excerpt_ids = Vec::new();
20122        for buffer_id in &ids_to_fold {
20123            let folded_excerpts = self.buffer().read(cx).excerpts_for_buffer(*buffer_id, cx);
20124            all_folded_excerpt_ids.extend(folded_excerpts.into_iter().map(|(id, _, _)| id));
20125        }
20126
20127        self.display_map.update(cx, |display_map, cx| {
20128            display_map.fold_buffers(ids_to_fold.clone(), cx)
20129        });
20130
20131        let snapshot = self.display_snapshot(cx);
20132        self.selections.change_with(&snapshot, |selections| {
20133            for buffer_id in ids_to_fold {
20134                selections.remove_selections_from_buffer(buffer_id);
20135            }
20136        });
20137
20138        cx.emit(EditorEvent::BufferFoldToggled {
20139            ids: all_folded_excerpt_ids,
20140            folded: true,
20141        });
20142        cx.notify();
20143    }
20144
20145    pub fn unfold_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20146        if self.buffer().read(cx).is_singleton() || !self.is_buffer_folded(buffer_id, cx) {
20147            return;
20148        }
20149        let unfolded_excerpts = self.buffer().read(cx).excerpts_for_buffer(buffer_id, cx);
20150        self.display_map.update(cx, |display_map, cx| {
20151            display_map.unfold_buffers([buffer_id], cx);
20152        });
20153        cx.emit(EditorEvent::BufferFoldToggled {
20154            ids: unfolded_excerpts.iter().map(|&(id, _, _)| id).collect(),
20155            folded: false,
20156        });
20157        cx.notify();
20158    }
20159
20160    pub fn is_buffer_folded(&self, buffer: BufferId, cx: &App) -> bool {
20161        self.display_map.read(cx).is_buffer_folded(buffer)
20162    }
20163
20164    pub fn has_any_buffer_folded(&self, cx: &App) -> bool {
20165        if self.buffer().read(cx).is_singleton() {
20166            return false;
20167        }
20168        !self.folded_buffers(cx).is_empty()
20169    }
20170
20171    pub fn folded_buffers<'a>(&self, cx: &'a App) -> &'a HashSet<BufferId> {
20172        self.display_map.read(cx).folded_buffers()
20173    }
20174
20175    pub fn disable_header_for_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
20176        self.display_map.update(cx, |display_map, cx| {
20177            display_map.disable_header_for_buffer(buffer_id, cx);
20178        });
20179        cx.notify();
20180    }
20181
20182    /// Removes any folds with the given ranges.
20183    pub fn remove_folds_with_type<T: ToOffset + Clone>(
20184        &mut self,
20185        ranges: &[Range<T>],
20186        type_id: TypeId,
20187        auto_scroll: bool,
20188        cx: &mut Context<Self>,
20189    ) {
20190        self.remove_folds_with(ranges, auto_scroll, cx, |map, cx| {
20191            map.remove_folds_with_type(ranges.iter().cloned(), type_id, cx)
20192        });
20193        self.folds_did_change(cx);
20194    }
20195
20196    fn remove_folds_with<T: ToOffset + Clone>(
20197        &mut self,
20198        ranges: &[Range<T>],
20199        auto_scroll: bool,
20200        cx: &mut Context<Self>,
20201        update: impl FnOnce(&mut DisplayMap, &mut Context<DisplayMap>),
20202    ) {
20203        if ranges.is_empty() {
20204            return;
20205        }
20206
20207        let mut buffers_affected = HashSet::default();
20208        let multi_buffer = self.buffer().read(cx);
20209        for range in ranges {
20210            if let Some((_, buffer, _)) = multi_buffer.excerpt_containing(range.start.clone(), cx) {
20211                buffers_affected.insert(buffer.read(cx).remote_id());
20212            };
20213        }
20214
20215        self.display_map.update(cx, update);
20216
20217        if auto_scroll {
20218            self.request_autoscroll(Autoscroll::fit(), cx);
20219        }
20220
20221        cx.notify();
20222        self.scrollbar_marker_state.dirty = true;
20223        self.active_indent_guides_state.dirty = true;
20224    }
20225
20226    pub fn update_renderer_widths(
20227        &mut self,
20228        widths: impl IntoIterator<Item = (ChunkRendererId, Pixels)>,
20229        cx: &mut Context<Self>,
20230    ) -> bool {
20231        self.display_map
20232            .update(cx, |map, cx| map.update_fold_widths(widths, cx))
20233    }
20234
20235    pub fn default_fold_placeholder(&self, cx: &App) -> FoldPlaceholder {
20236        self.display_map.read(cx).fold_placeholder.clone()
20237    }
20238
20239    pub fn set_expand_all_diff_hunks(&mut self, cx: &mut App) {
20240        self.buffer.update(cx, |buffer, cx| {
20241            buffer.set_all_diff_hunks_expanded(cx);
20242        });
20243    }
20244
20245    pub fn expand_all_diff_hunks(
20246        &mut self,
20247        _: &ExpandAllDiffHunks,
20248        _window: &mut Window,
20249        cx: &mut Context<Self>,
20250    ) {
20251        self.buffer.update(cx, |buffer, cx| {
20252            buffer.expand_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20253        });
20254    }
20255
20256    pub fn collapse_all_diff_hunks(
20257        &mut self,
20258        _: &CollapseAllDiffHunks,
20259        _window: &mut Window,
20260        cx: &mut Context<Self>,
20261    ) {
20262        self.buffer.update(cx, |buffer, cx| {
20263            buffer.collapse_diff_hunks(vec![Anchor::min()..Anchor::max()], cx)
20264        });
20265    }
20266
20267    pub fn toggle_selected_diff_hunks(
20268        &mut self,
20269        _: &ToggleSelectedDiffHunks,
20270        _window: &mut Window,
20271        cx: &mut Context<Self>,
20272    ) {
20273        let ranges: Vec<_> = self
20274            .selections
20275            .disjoint_anchors()
20276            .iter()
20277            .map(|s| s.range())
20278            .collect();
20279        self.toggle_diff_hunks_in_ranges(ranges, cx);
20280    }
20281
20282    pub fn diff_hunks_in_ranges<'a>(
20283        &'a self,
20284        ranges: &'a [Range<Anchor>],
20285        buffer: &'a MultiBufferSnapshot,
20286    ) -> impl 'a + Iterator<Item = MultiBufferDiffHunk> {
20287        ranges.iter().flat_map(move |range| {
20288            let end_excerpt_id = range.end.excerpt_id;
20289            let range = range.to_point(buffer);
20290            let mut peek_end = range.end;
20291            if range.end.row < buffer.max_row().0 {
20292                peek_end = Point::new(range.end.row + 1, 0);
20293            }
20294            buffer
20295                .diff_hunks_in_range(range.start..peek_end)
20296                .filter(move |hunk| hunk.excerpt_id.cmp(&end_excerpt_id, buffer).is_le())
20297        })
20298    }
20299
20300    pub fn has_stageable_diff_hunks_in_ranges(
20301        &self,
20302        ranges: &[Range<Anchor>],
20303        snapshot: &MultiBufferSnapshot,
20304    ) -> bool {
20305        let mut hunks = self.diff_hunks_in_ranges(ranges, snapshot);
20306        hunks.any(|hunk| hunk.status().has_secondary_hunk())
20307    }
20308
20309    pub fn toggle_staged_selected_diff_hunks(
20310        &mut self,
20311        _: &::git::ToggleStaged,
20312        _: &mut Window,
20313        cx: &mut Context<Self>,
20314    ) {
20315        let snapshot = self.buffer.read(cx).snapshot(cx);
20316        let ranges: Vec<_> = self
20317            .selections
20318            .disjoint_anchors()
20319            .iter()
20320            .map(|s| s.range())
20321            .collect();
20322        let stage = self.has_stageable_diff_hunks_in_ranges(&ranges, &snapshot);
20323        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20324    }
20325
20326    pub fn set_render_diff_hunk_controls(
20327        &mut self,
20328        render_diff_hunk_controls: RenderDiffHunkControlsFn,
20329        cx: &mut Context<Self>,
20330    ) {
20331        self.render_diff_hunk_controls = render_diff_hunk_controls;
20332        cx.notify();
20333    }
20334
20335    pub fn stage_and_next(
20336        &mut self,
20337        _: &::git::StageAndNext,
20338        window: &mut Window,
20339        cx: &mut Context<Self>,
20340    ) {
20341        self.do_stage_or_unstage_and_next(true, window, cx);
20342    }
20343
20344    pub fn unstage_and_next(
20345        &mut self,
20346        _: &::git::UnstageAndNext,
20347        window: &mut Window,
20348        cx: &mut Context<Self>,
20349    ) {
20350        self.do_stage_or_unstage_and_next(false, window, cx);
20351    }
20352
20353    pub fn stage_or_unstage_diff_hunks(
20354        &mut self,
20355        stage: bool,
20356        ranges: Vec<Range<Anchor>>,
20357        cx: &mut Context<Self>,
20358    ) {
20359        if self.delegate_stage_and_restore {
20360            let snapshot = self.buffer.read(cx).snapshot(cx);
20361            let hunks: Vec<_> = self.diff_hunks_in_ranges(&ranges, &snapshot).collect();
20362            if !hunks.is_empty() {
20363                cx.emit(EditorEvent::StageOrUnstageRequested { stage, hunks });
20364            }
20365            return;
20366        }
20367        let task = self.save_buffers_for_ranges_if_needed(&ranges, cx);
20368        cx.spawn(async move |this, cx| {
20369            task.await?;
20370            this.update(cx, |this, cx| {
20371                let snapshot = this.buffer.read(cx).snapshot(cx);
20372                let chunk_by = this
20373                    .diff_hunks_in_ranges(&ranges, &snapshot)
20374                    .chunk_by(|hunk| hunk.buffer_id);
20375                for (buffer_id, hunks) in &chunk_by {
20376                    this.do_stage_or_unstage(stage, buffer_id, hunks, cx);
20377                }
20378            })
20379        })
20380        .detach_and_log_err(cx);
20381    }
20382
20383    fn save_buffers_for_ranges_if_needed(
20384        &mut self,
20385        ranges: &[Range<Anchor>],
20386        cx: &mut Context<Editor>,
20387    ) -> Task<Result<()>> {
20388        let multibuffer = self.buffer.read(cx);
20389        let snapshot = multibuffer.read(cx);
20390        let buffer_ids: HashSet<_> = ranges
20391            .iter()
20392            .flat_map(|range| snapshot.buffer_ids_for_range(range.clone()))
20393            .collect();
20394        drop(snapshot);
20395
20396        let mut buffers = HashSet::default();
20397        for buffer_id in buffer_ids {
20398            if let Some(buffer_entity) = multibuffer.buffer(buffer_id) {
20399                let buffer = buffer_entity.read(cx);
20400                if buffer.file().is_some_and(|file| file.disk_state().exists()) && buffer.is_dirty()
20401                {
20402                    buffers.insert(buffer_entity);
20403                }
20404            }
20405        }
20406
20407        if let Some(project) = &self.project {
20408            project.update(cx, |project, cx| project.save_buffers(buffers, cx))
20409        } else {
20410            Task::ready(Ok(()))
20411        }
20412    }
20413
20414    fn do_stage_or_unstage_and_next(
20415        &mut self,
20416        stage: bool,
20417        window: &mut Window,
20418        cx: &mut Context<Self>,
20419    ) {
20420        let ranges = self.selections.disjoint_anchor_ranges().collect::<Vec<_>>();
20421
20422        if ranges.iter().any(|range| range.start != range.end) {
20423            self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20424            return;
20425        }
20426
20427        self.stage_or_unstage_diff_hunks(stage, ranges, cx);
20428
20429        let all_diff_hunks_expanded = self.buffer().read(cx).all_diff_hunks_expanded();
20430        let wrap_around = !all_diff_hunks_expanded;
20431        let snapshot = self.snapshot(window, cx);
20432        let position = self
20433            .selections
20434            .newest::<Point>(&snapshot.display_snapshot)
20435            .head();
20436
20437        self.go_to_hunk_before_or_after_position(
20438            &snapshot,
20439            position,
20440            Direction::Next,
20441            wrap_around,
20442            window,
20443            cx,
20444        );
20445    }
20446
20447    pub(crate) fn do_stage_or_unstage(
20448        &self,
20449        stage: bool,
20450        buffer_id: BufferId,
20451        hunks: impl Iterator<Item = MultiBufferDiffHunk>,
20452        cx: &mut App,
20453    ) -> Option<()> {
20454        let project = self.project()?;
20455        let buffer = project.read(cx).buffer_for_id(buffer_id, cx)?;
20456        let diff = self.buffer.read(cx).diff_for(buffer_id)?;
20457        let buffer_snapshot = buffer.read(cx).snapshot();
20458        let file_exists = buffer_snapshot
20459            .file()
20460            .is_some_and(|file| file.disk_state().exists());
20461        diff.update(cx, |diff, cx| {
20462            diff.stage_or_unstage_hunks(
20463                stage,
20464                &hunks
20465                    .map(|hunk| buffer_diff::DiffHunk {
20466                        buffer_range: hunk.buffer_range,
20467                        // We don't need to pass in word diffs here because they're only used for rendering and
20468                        // this function changes internal state
20469                        base_word_diffs: Vec::default(),
20470                        buffer_word_diffs: Vec::default(),
20471                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
20472                            ..hunk.diff_base_byte_range.end.0,
20473                        secondary_status: hunk.status.secondary,
20474                        range: Point::zero()..Point::zero(), // unused
20475                    })
20476                    .collect::<Vec<_>>(),
20477                &buffer_snapshot,
20478                file_exists,
20479                cx,
20480            )
20481        });
20482        None
20483    }
20484
20485    pub fn expand_selected_diff_hunks(&mut self, cx: &mut Context<Self>) {
20486        let ranges: Vec<_> = self
20487            .selections
20488            .disjoint_anchors()
20489            .iter()
20490            .map(|s| s.range())
20491            .collect();
20492        self.buffer
20493            .update(cx, |buffer, cx| buffer.expand_diff_hunks(ranges, cx))
20494    }
20495
20496    pub fn clear_expanded_diff_hunks(&mut self, cx: &mut Context<Self>) -> bool {
20497        self.buffer.update(cx, |buffer, cx| {
20498            let ranges = vec![Anchor::min()..Anchor::max()];
20499            if !buffer.all_diff_hunks_expanded()
20500                && buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx)
20501            {
20502                buffer.collapse_diff_hunks(ranges, cx);
20503                true
20504            } else {
20505                false
20506            }
20507        })
20508    }
20509
20510    fn has_any_expanded_diff_hunks(&self, cx: &App) -> bool {
20511        if self.buffer.read(cx).all_diff_hunks_expanded() {
20512            return true;
20513        }
20514        let ranges = vec![Anchor::min()..Anchor::max()];
20515        self.buffer
20516            .read(cx)
20517            .has_expanded_diff_hunks_in_ranges(&ranges, cx)
20518    }
20519
20520    fn toggle_diff_hunks_in_ranges(
20521        &mut self,
20522        ranges: Vec<Range<Anchor>>,
20523        cx: &mut Context<Editor>,
20524    ) {
20525        self.buffer.update(cx, |buffer, cx| {
20526            let expand = !buffer.has_expanded_diff_hunks_in_ranges(&ranges, cx);
20527            buffer.expand_or_collapse_diff_hunks(ranges, expand, cx);
20528        })
20529    }
20530
20531    fn toggle_single_diff_hunk(&mut self, range: Range<Anchor>, cx: &mut Context<Self>) {
20532        self.buffer.update(cx, |buffer, cx| {
20533            buffer.toggle_single_diff_hunk(range, cx);
20534        })
20535    }
20536
20537    pub(crate) fn apply_all_diff_hunks(
20538        &mut self,
20539        _: &ApplyAllDiffHunks,
20540        window: &mut Window,
20541        cx: &mut Context<Self>,
20542    ) {
20543        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20544
20545        let buffers = self.buffer.read(cx).all_buffers();
20546        for branch_buffer in buffers {
20547            branch_buffer.update(cx, |branch_buffer, cx| {
20548                branch_buffer.merge_into_base(Vec::new(), cx);
20549            });
20550        }
20551
20552        if let Some(project) = self.project.clone() {
20553            self.save(
20554                SaveOptions {
20555                    format: true,
20556                    autosave: false,
20557                },
20558                project,
20559                window,
20560                cx,
20561            )
20562            .detach_and_log_err(cx);
20563        }
20564    }
20565
20566    pub(crate) fn apply_selected_diff_hunks(
20567        &mut self,
20568        _: &ApplyDiffHunk,
20569        window: &mut Window,
20570        cx: &mut Context<Self>,
20571    ) {
20572        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
20573        let snapshot = self.snapshot(window, cx);
20574        let hunks = snapshot.hunks_for_ranges(
20575            self.selections
20576                .all(&snapshot.display_snapshot)
20577                .into_iter()
20578                .map(|selection| selection.range()),
20579        );
20580        let mut ranges_by_buffer = HashMap::default();
20581        self.transact(window, cx, |editor, _window, cx| {
20582            for hunk in hunks {
20583                if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
20584                    ranges_by_buffer
20585                        .entry(buffer.clone())
20586                        .or_insert_with(Vec::new)
20587                        .push(hunk.buffer_range.to_offset(buffer.read(cx)));
20588                }
20589            }
20590
20591            for (buffer, ranges) in ranges_by_buffer {
20592                buffer.update(cx, |buffer, cx| {
20593                    buffer.merge_into_base(ranges, cx);
20594                });
20595            }
20596        });
20597
20598        if let Some(project) = self.project.clone() {
20599            self.save(
20600                SaveOptions {
20601                    format: true,
20602                    autosave: false,
20603                },
20604                project,
20605                window,
20606                cx,
20607            )
20608            .detach_and_log_err(cx);
20609        }
20610    }
20611
20612    pub fn set_gutter_hovered(&mut self, hovered: bool, cx: &mut Context<Self>) {
20613        if hovered != self.gutter_hovered {
20614            self.gutter_hovered = hovered;
20615            cx.notify();
20616        }
20617    }
20618
20619    pub fn insert_blocks(
20620        &mut self,
20621        blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
20622        autoscroll: Option<Autoscroll>,
20623        cx: &mut Context<Self>,
20624    ) -> Vec<CustomBlockId> {
20625        let blocks = self
20626            .display_map
20627            .update(cx, |display_map, cx| display_map.insert_blocks(blocks, cx));
20628        if let Some(autoscroll) = autoscroll {
20629            self.request_autoscroll(autoscroll, cx);
20630        }
20631        cx.notify();
20632        blocks
20633    }
20634
20635    pub fn resize_blocks(
20636        &mut self,
20637        heights: HashMap<CustomBlockId, u32>,
20638        autoscroll: Option<Autoscroll>,
20639        cx: &mut Context<Self>,
20640    ) {
20641        self.display_map
20642            .update(cx, |display_map, cx| display_map.resize_blocks(heights, cx));
20643        if let Some(autoscroll) = autoscroll {
20644            self.request_autoscroll(autoscroll, cx);
20645        }
20646        cx.notify();
20647    }
20648
20649    pub fn replace_blocks(
20650        &mut self,
20651        renderers: HashMap<CustomBlockId, RenderBlock>,
20652        autoscroll: Option<Autoscroll>,
20653        cx: &mut Context<Self>,
20654    ) {
20655        self.display_map
20656            .update(cx, |display_map, _cx| display_map.replace_blocks(renderers));
20657        if let Some(autoscroll) = autoscroll {
20658            self.request_autoscroll(autoscroll, cx);
20659        }
20660        cx.notify();
20661    }
20662
20663    pub fn remove_blocks(
20664        &mut self,
20665        block_ids: HashSet<CustomBlockId>,
20666        autoscroll: Option<Autoscroll>,
20667        cx: &mut Context<Self>,
20668    ) {
20669        self.display_map.update(cx, |display_map, cx| {
20670            display_map.remove_blocks(block_ids, cx)
20671        });
20672        if let Some(autoscroll) = autoscroll {
20673            self.request_autoscroll(autoscroll, cx);
20674        }
20675        cx.notify();
20676    }
20677
20678    pub fn row_for_block(
20679        &self,
20680        block_id: CustomBlockId,
20681        cx: &mut Context<Self>,
20682    ) -> Option<DisplayRow> {
20683        self.display_map
20684            .update(cx, |map, cx| map.row_for_block(block_id, cx))
20685    }
20686
20687    pub(crate) fn set_focused_block(&mut self, focused_block: FocusedBlock) {
20688        self.focused_block = Some(focused_block);
20689    }
20690
20691    pub(crate) fn take_focused_block(&mut self) -> Option<FocusedBlock> {
20692        self.focused_block.take()
20693    }
20694
20695    pub fn insert_creases(
20696        &mut self,
20697        creases: impl IntoIterator<Item = Crease<Anchor>>,
20698        cx: &mut Context<Self>,
20699    ) -> Vec<CreaseId> {
20700        self.display_map
20701            .update(cx, |map, cx| map.insert_creases(creases, cx))
20702    }
20703
20704    pub fn remove_creases(
20705        &mut self,
20706        ids: impl IntoIterator<Item = CreaseId>,
20707        cx: &mut Context<Self>,
20708    ) -> Vec<(CreaseId, Range<Anchor>)> {
20709        self.display_map
20710            .update(cx, |map, cx| map.remove_creases(ids, cx))
20711    }
20712
20713    pub fn longest_row(&self, cx: &mut App) -> DisplayRow {
20714        self.display_map
20715            .update(cx, |map, cx| map.snapshot(cx))
20716            .longest_row()
20717    }
20718
20719    pub fn max_point(&self, cx: &mut App) -> DisplayPoint {
20720        self.display_map
20721            .update(cx, |map, cx| map.snapshot(cx))
20722            .max_point()
20723    }
20724
20725    pub fn text(&self, cx: &App) -> String {
20726        self.buffer.read(cx).read(cx).text()
20727    }
20728
20729    pub fn is_empty(&self, cx: &App) -> bool {
20730        self.buffer.read(cx).read(cx).is_empty()
20731    }
20732
20733    pub fn text_option(&self, cx: &App) -> Option<String> {
20734        let text = self.text(cx);
20735        let text = text.trim();
20736
20737        if text.is_empty() {
20738            return None;
20739        }
20740
20741        Some(text.to_string())
20742    }
20743
20744    pub fn set_text(
20745        &mut self,
20746        text: impl Into<Arc<str>>,
20747        window: &mut Window,
20748        cx: &mut Context<Self>,
20749    ) {
20750        self.transact(window, cx, |this, _, cx| {
20751            this.buffer
20752                .read(cx)
20753                .as_singleton()
20754                .expect("you can only call set_text on editors for singleton buffers")
20755                .update(cx, |buffer, cx| buffer.set_text(text, cx));
20756        });
20757    }
20758
20759    pub fn display_text(&self, cx: &mut App) -> String {
20760        self.display_map
20761            .update(cx, |map, cx| map.snapshot(cx))
20762            .text()
20763    }
20764
20765    fn create_minimap(
20766        &self,
20767        minimap_settings: MinimapSettings,
20768        window: &mut Window,
20769        cx: &mut Context<Self>,
20770    ) -> Option<Entity<Self>> {
20771        (minimap_settings.minimap_enabled() && self.buffer_kind(cx) == ItemBufferKind::Singleton)
20772            .then(|| self.initialize_new_minimap(minimap_settings, window, cx))
20773    }
20774
20775    fn initialize_new_minimap(
20776        &self,
20777        minimap_settings: MinimapSettings,
20778        window: &mut Window,
20779        cx: &mut Context<Self>,
20780    ) -> Entity<Self> {
20781        const MINIMAP_FONT_WEIGHT: gpui::FontWeight = gpui::FontWeight::BLACK;
20782        const MINIMAP_FONT_FAMILY: SharedString = SharedString::new_static(".ZedMono");
20783
20784        let mut minimap = Editor::new_internal(
20785            EditorMode::Minimap {
20786                parent: cx.weak_entity(),
20787            },
20788            self.buffer.clone(),
20789            None,
20790            Some(self.display_map.clone()),
20791            window,
20792            cx,
20793        );
20794        let my_snapshot = self.display_map.update(cx, |map, cx| map.snapshot(cx));
20795        let minimap_snapshot = minimap.display_map.update(cx, |map, cx| map.snapshot(cx));
20796        minimap.scroll_manager.clone_state(
20797            &self.scroll_manager,
20798            &my_snapshot,
20799            &minimap_snapshot,
20800            cx,
20801        );
20802        minimap.set_text_style_refinement(TextStyleRefinement {
20803            font_size: Some(MINIMAP_FONT_SIZE),
20804            font_weight: Some(MINIMAP_FONT_WEIGHT),
20805            font_family: Some(MINIMAP_FONT_FAMILY),
20806            ..Default::default()
20807        });
20808        minimap.update_minimap_configuration(minimap_settings, cx);
20809        cx.new(|_| minimap)
20810    }
20811
20812    fn update_minimap_configuration(&mut self, minimap_settings: MinimapSettings, cx: &App) {
20813        let current_line_highlight = minimap_settings
20814            .current_line_highlight
20815            .unwrap_or_else(|| EditorSettings::get_global(cx).current_line_highlight);
20816        self.set_current_line_highlight(Some(current_line_highlight));
20817    }
20818
20819    pub fn minimap(&self) -> Option<&Entity<Self>> {
20820        self.minimap
20821            .as_ref()
20822            .filter(|_| self.minimap_visibility.visible())
20823    }
20824
20825    pub fn wrap_guides(&self, cx: &App) -> SmallVec<[(usize, bool); 2]> {
20826        let mut wrap_guides = smallvec![];
20827
20828        if self.show_wrap_guides == Some(false) {
20829            return wrap_guides;
20830        }
20831
20832        let settings = self.buffer.read(cx).language_settings(cx);
20833        if settings.show_wrap_guides {
20834            match self.soft_wrap_mode(cx) {
20835                SoftWrap::Column(soft_wrap) => {
20836                    wrap_guides.push((soft_wrap as usize, true));
20837                }
20838                SoftWrap::Bounded(soft_wrap) => {
20839                    wrap_guides.push((soft_wrap as usize, true));
20840                }
20841                SoftWrap::GitDiff | SoftWrap::None | SoftWrap::EditorWidth => {}
20842            }
20843            wrap_guides.extend(settings.wrap_guides.iter().map(|guide| (*guide, false)))
20844        }
20845
20846        wrap_guides
20847    }
20848
20849    pub fn soft_wrap_mode(&self, cx: &App) -> SoftWrap {
20850        let settings = self.buffer.read(cx).language_settings(cx);
20851        let mode = self.soft_wrap_mode_override.unwrap_or(settings.soft_wrap);
20852        match mode {
20853            language_settings::SoftWrap::PreferLine | language_settings::SoftWrap::None => {
20854                SoftWrap::None
20855            }
20856            language_settings::SoftWrap::EditorWidth => SoftWrap::EditorWidth,
20857            language_settings::SoftWrap::PreferredLineLength => {
20858                SoftWrap::Column(settings.preferred_line_length)
20859            }
20860            language_settings::SoftWrap::Bounded => {
20861                SoftWrap::Bounded(settings.preferred_line_length)
20862            }
20863        }
20864    }
20865
20866    pub fn set_soft_wrap_mode(
20867        &mut self,
20868        mode: language_settings::SoftWrap,
20869        cx: &mut Context<Self>,
20870    ) {
20871        self.soft_wrap_mode_override = Some(mode);
20872        cx.notify();
20873    }
20874
20875    pub fn set_hard_wrap(&mut self, hard_wrap: Option<usize>, cx: &mut Context<Self>) {
20876        self.hard_wrap = hard_wrap;
20877        cx.notify();
20878    }
20879
20880    pub fn set_text_style_refinement(&mut self, style: TextStyleRefinement) {
20881        self.text_style_refinement = Some(style);
20882    }
20883
20884    /// called by the Element so we know what style we were most recently rendered with.
20885    pub fn set_style(&mut self, style: EditorStyle, window: &mut Window, cx: &mut Context<Self>) {
20886        // We intentionally do not inform the display map about the minimap style
20887        // so that wrapping is not recalculated and stays consistent for the editor
20888        // and its linked minimap.
20889        if !self.mode.is_minimap() {
20890            let font = style.text.font();
20891            let font_size = style.text.font_size.to_pixels(window.rem_size());
20892            let display_map = self
20893                .placeholder_display_map
20894                .as_ref()
20895                .filter(|_| self.is_empty(cx))
20896                .unwrap_or(&self.display_map);
20897
20898            display_map.update(cx, |map, cx| map.set_font(font, font_size, cx));
20899        }
20900        self.style = Some(style);
20901    }
20902
20903    pub fn style(&mut self, cx: &App) -> &EditorStyle {
20904        if self.style.is_none() {
20905            self.style = Some(self.create_style(cx));
20906        }
20907        self.style.as_ref().unwrap()
20908    }
20909
20910    // Called by the element. This method is not designed to be called outside of the editor
20911    // element's layout code because it does not notify when rewrapping is computed synchronously.
20912    pub(crate) fn set_wrap_width(&self, width: Option<Pixels>, cx: &mut App) -> bool {
20913        if self.is_empty(cx) {
20914            self.placeholder_display_map
20915                .as_ref()
20916                .map_or(false, |display_map| {
20917                    display_map.update(cx, |map, cx| map.set_wrap_width(width, cx))
20918                })
20919        } else {
20920            self.display_map
20921                .update(cx, |map, cx| map.set_wrap_width(width, cx))
20922        }
20923    }
20924
20925    pub fn set_soft_wrap(&mut self) {
20926        self.soft_wrap_mode_override = Some(language_settings::SoftWrap::EditorWidth)
20927    }
20928
20929    pub fn toggle_soft_wrap(&mut self, _: &ToggleSoftWrap, _: &mut Window, cx: &mut Context<Self>) {
20930        if self.soft_wrap_mode_override.is_some() {
20931            self.soft_wrap_mode_override.take();
20932        } else {
20933            let soft_wrap = match self.soft_wrap_mode(cx) {
20934                SoftWrap::GitDiff => return,
20935                SoftWrap::None => language_settings::SoftWrap::EditorWidth,
20936                SoftWrap::EditorWidth | SoftWrap::Column(_) | SoftWrap::Bounded(_) => {
20937                    language_settings::SoftWrap::None
20938                }
20939            };
20940            self.soft_wrap_mode_override = Some(soft_wrap);
20941        }
20942        cx.notify();
20943    }
20944
20945    pub fn toggle_tab_bar(&mut self, _: &ToggleTabBar, _: &mut Window, cx: &mut Context<Self>) {
20946        let Some(workspace) = self.workspace() else {
20947            return;
20948        };
20949        let fs = workspace.read(cx).app_state().fs.clone();
20950        let current_show = TabBarSettings::get_global(cx).show;
20951        update_settings_file(fs, cx, move |setting, _| {
20952            setting.tab_bar.get_or_insert_default().show = Some(!current_show);
20953        });
20954    }
20955
20956    pub fn toggle_indent_guides(
20957        &mut self,
20958        _: &ToggleIndentGuides,
20959        _: &mut Window,
20960        cx: &mut Context<Self>,
20961    ) {
20962        let currently_enabled = self.should_show_indent_guides().unwrap_or_else(|| {
20963            self.buffer
20964                .read(cx)
20965                .language_settings(cx)
20966                .indent_guides
20967                .enabled
20968        });
20969        self.show_indent_guides = Some(!currently_enabled);
20970        cx.notify();
20971    }
20972
20973    fn should_show_indent_guides(&self) -> Option<bool> {
20974        self.show_indent_guides
20975    }
20976
20977    pub fn disable_indent_guides_for_buffer(
20978        &mut self,
20979        buffer_id: BufferId,
20980        cx: &mut Context<Self>,
20981    ) {
20982        self.buffers_with_disabled_indent_guides.insert(buffer_id);
20983        cx.notify();
20984    }
20985
20986    pub fn has_indent_guides_disabled_for_buffer(&self, buffer_id: BufferId) -> bool {
20987        self.buffers_with_disabled_indent_guides
20988            .contains(&buffer_id)
20989    }
20990
20991    pub fn toggle_line_numbers(
20992        &mut self,
20993        _: &ToggleLineNumbers,
20994        _: &mut Window,
20995        cx: &mut Context<Self>,
20996    ) {
20997        let mut editor_settings = EditorSettings::get_global(cx).clone();
20998        editor_settings.gutter.line_numbers = !editor_settings.gutter.line_numbers;
20999        EditorSettings::override_global(editor_settings, cx);
21000    }
21001
21002    pub fn line_numbers_enabled(&self, cx: &App) -> bool {
21003        if let Some(show_line_numbers) = self.show_line_numbers {
21004            return show_line_numbers;
21005        }
21006        EditorSettings::get_global(cx).gutter.line_numbers
21007    }
21008
21009    pub fn relative_line_numbers(&self, cx: &App) -> RelativeLineNumbers {
21010        match (
21011            self.use_relative_line_numbers,
21012            EditorSettings::get_global(cx).relative_line_numbers,
21013        ) {
21014            (None, setting) => setting,
21015            (Some(false), _) => RelativeLineNumbers::Disabled,
21016            (Some(true), RelativeLineNumbers::Wrapped) => RelativeLineNumbers::Wrapped,
21017            (Some(true), _) => RelativeLineNumbers::Enabled,
21018        }
21019    }
21020
21021    pub fn toggle_relative_line_numbers(
21022        &mut self,
21023        _: &ToggleRelativeLineNumbers,
21024        _: &mut Window,
21025        cx: &mut Context<Self>,
21026    ) {
21027        let is_relative = self.relative_line_numbers(cx);
21028        self.set_relative_line_number(Some(!is_relative.enabled()), cx)
21029    }
21030
21031    pub fn set_relative_line_number(&mut self, is_relative: Option<bool>, cx: &mut Context<Self>) {
21032        self.use_relative_line_numbers = is_relative;
21033        cx.notify();
21034    }
21035
21036    pub fn set_show_gutter(&mut self, show_gutter: bool, cx: &mut Context<Self>) {
21037        self.show_gutter = show_gutter;
21038        cx.notify();
21039    }
21040
21041    pub fn set_show_scrollbars(&mut self, show: bool, cx: &mut Context<Self>) {
21042        self.show_scrollbars = ScrollbarAxes {
21043            horizontal: show,
21044            vertical: show,
21045        };
21046        cx.notify();
21047    }
21048
21049    pub fn set_show_vertical_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21050        self.show_scrollbars.vertical = show;
21051        cx.notify();
21052    }
21053
21054    pub fn set_show_horizontal_scrollbar(&mut self, show: bool, cx: &mut Context<Self>) {
21055        self.show_scrollbars.horizontal = show;
21056        cx.notify();
21057    }
21058
21059    pub fn set_minimap_visibility(
21060        &mut self,
21061        minimap_visibility: MinimapVisibility,
21062        window: &mut Window,
21063        cx: &mut Context<Self>,
21064    ) {
21065        if self.minimap_visibility != minimap_visibility {
21066            if minimap_visibility.visible() && self.minimap.is_none() {
21067                let minimap_settings = EditorSettings::get_global(cx).minimap;
21068                self.minimap =
21069                    self.create_minimap(minimap_settings.with_show_override(), window, cx);
21070            }
21071            self.minimap_visibility = minimap_visibility;
21072            cx.notify();
21073        }
21074    }
21075
21076    pub fn disable_scrollbars_and_minimap(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21077        self.set_show_scrollbars(false, cx);
21078        self.set_minimap_visibility(MinimapVisibility::Disabled, window, cx);
21079    }
21080
21081    pub fn hide_minimap_by_default(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21082        self.set_minimap_visibility(self.minimap_visibility.hidden(), window, cx);
21083    }
21084
21085    /// Normally the text in full mode and auto height editors is padded on the
21086    /// left side by roughly half a character width for improved hit testing.
21087    ///
21088    /// Use this method to disable this for cases where this is not wanted (e.g.
21089    /// if you want to align the editor text with some other text above or below)
21090    /// or if you want to add this padding to single-line editors.
21091    pub fn set_offset_content(&mut self, offset_content: bool, cx: &mut Context<Self>) {
21092        self.offset_content = offset_content;
21093        cx.notify();
21094    }
21095
21096    pub fn set_show_line_numbers(&mut self, show_line_numbers: bool, cx: &mut Context<Self>) {
21097        self.show_line_numbers = Some(show_line_numbers);
21098        cx.notify();
21099    }
21100
21101    pub fn disable_expand_excerpt_buttons(&mut self, cx: &mut Context<Self>) {
21102        self.disable_expand_excerpt_buttons = true;
21103        cx.notify();
21104    }
21105
21106    pub fn set_number_deleted_lines(&mut self, number: bool, cx: &mut Context<Self>) {
21107        self.number_deleted_lines = number;
21108        cx.notify();
21109    }
21110
21111    pub fn set_delegate_expand_excerpts(&mut self, delegate: bool) {
21112        self.delegate_expand_excerpts = delegate;
21113    }
21114
21115    pub fn set_delegate_stage_and_restore(&mut self, delegate: bool) {
21116        self.delegate_stage_and_restore = delegate;
21117    }
21118
21119    pub fn set_delegate_open_excerpts(&mut self, delegate: bool) {
21120        self.delegate_open_excerpts = delegate;
21121    }
21122
21123    pub fn set_on_local_selections_changed(
21124        &mut self,
21125        callback: Option<Box<dyn Fn(Point, &mut Window, &mut Context<Self>) + 'static>>,
21126    ) {
21127        self.on_local_selections_changed = callback;
21128    }
21129
21130    pub fn set_suppress_selection_callback(&mut self, suppress: bool) {
21131        self.suppress_selection_callback = suppress;
21132    }
21133
21134    pub fn set_show_git_diff_gutter(&mut self, show_git_diff_gutter: bool, cx: &mut Context<Self>) {
21135        self.show_git_diff_gutter = Some(show_git_diff_gutter);
21136        cx.notify();
21137    }
21138
21139    pub fn set_show_code_actions(&mut self, show_code_actions: bool, cx: &mut Context<Self>) {
21140        self.show_code_actions = Some(show_code_actions);
21141        cx.notify();
21142    }
21143
21144    pub fn set_show_runnables(&mut self, show_runnables: bool, cx: &mut Context<Self>) {
21145        self.show_runnables = Some(show_runnables);
21146        cx.notify();
21147    }
21148
21149    pub fn set_show_breakpoints(&mut self, show_breakpoints: bool, cx: &mut Context<Self>) {
21150        self.show_breakpoints = Some(show_breakpoints);
21151        cx.notify();
21152    }
21153
21154    pub fn set_show_diff_review_button(&mut self, show: bool, cx: &mut Context<Self>) {
21155        self.show_diff_review_button = show;
21156        cx.notify();
21157    }
21158
21159    pub fn show_diff_review_button(&self) -> bool {
21160        self.show_diff_review_button
21161    }
21162
21163    pub fn render_diff_review_button(
21164        &self,
21165        display_row: DisplayRow,
21166        width: Pixels,
21167        cx: &mut Context<Self>,
21168    ) -> impl IntoElement {
21169        let text_color = cx.theme().colors().text;
21170        let icon_color = cx.theme().colors().icon_accent;
21171
21172        h_flex()
21173            .id("diff_review_button")
21174            .cursor_pointer()
21175            .w(width - px(1.))
21176            .h(relative(0.9))
21177            .justify_center()
21178            .rounded_sm()
21179            .border_1()
21180            .border_color(text_color.opacity(0.1))
21181            .bg(text_color.opacity(0.15))
21182            .hover(|s| {
21183                s.bg(icon_color.opacity(0.4))
21184                    .border_color(icon_color.opacity(0.5))
21185            })
21186            .child(Icon::new(IconName::Plus).size(IconSize::Small))
21187            .tooltip(Tooltip::text("Add Review (drag to select multiple lines)"))
21188            .on_mouse_down(
21189                gpui::MouseButton::Left,
21190                cx.listener(move |editor, _event: &gpui::MouseDownEvent, window, cx| {
21191                    editor.start_diff_review_drag(display_row, window, cx);
21192                }),
21193            )
21194    }
21195
21196    pub fn start_diff_review_drag(
21197        &mut self,
21198        display_row: DisplayRow,
21199        window: &mut Window,
21200        cx: &mut Context<Self>,
21201    ) {
21202        let snapshot = self.snapshot(window, cx);
21203        let point = snapshot
21204            .display_snapshot
21205            .display_point_to_point(DisplayPoint::new(display_row, 0), Bias::Left);
21206        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21207        self.diff_review_drag_state = Some(DiffReviewDragState {
21208            start_anchor: anchor,
21209            current_anchor: anchor,
21210        });
21211        cx.notify();
21212    }
21213
21214    pub fn update_diff_review_drag(
21215        &mut self,
21216        display_row: DisplayRow,
21217        window: &mut Window,
21218        cx: &mut Context<Self>,
21219    ) {
21220        if self.diff_review_drag_state.is_none() {
21221            return;
21222        }
21223        let snapshot = self.snapshot(window, cx);
21224        let point = snapshot
21225            .display_snapshot
21226            .display_point_to_point(display_row.as_display_point(), Bias::Left);
21227        let anchor = snapshot.buffer_snapshot().anchor_before(point);
21228        if let Some(drag_state) = &mut self.diff_review_drag_state {
21229            drag_state.current_anchor = anchor;
21230            cx.notify();
21231        }
21232    }
21233
21234    pub fn end_diff_review_drag(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21235        if let Some(drag_state) = self.diff_review_drag_state.take() {
21236            let snapshot = self.snapshot(window, cx);
21237            let range = drag_state.row_range(&snapshot.display_snapshot);
21238            self.show_diff_review_overlay(*range.start()..*range.end(), window, cx);
21239        }
21240        cx.notify();
21241    }
21242
21243    pub fn cancel_diff_review_drag(&mut self, cx: &mut Context<Self>) {
21244        self.diff_review_drag_state = None;
21245        cx.notify();
21246    }
21247
21248    /// Calculates the appropriate block height for the diff review overlay.
21249    /// Height is in lines: 2 for input row, 1 for header when comments exist,
21250    /// and 2 lines per comment when expanded.
21251    fn calculate_overlay_height(
21252        &self,
21253        hunk_key: &DiffHunkKey,
21254        comments_expanded: bool,
21255        snapshot: &MultiBufferSnapshot,
21256    ) -> u32 {
21257        let comment_count = self.hunk_comment_count(hunk_key, snapshot);
21258        let base_height: u32 = 2; // Input row with avatar and buttons
21259
21260        if comment_count == 0 {
21261            base_height
21262        } else if comments_expanded {
21263            // Header (1 line) + 2 lines per comment
21264            base_height + 1 + (comment_count as u32 * 2)
21265        } else {
21266            // Just header when collapsed
21267            base_height + 1
21268        }
21269    }
21270
21271    pub fn show_diff_review_overlay(
21272        &mut self,
21273        display_range: Range<DisplayRow>,
21274        window: &mut Window,
21275        cx: &mut Context<Self>,
21276    ) {
21277        let Range { start, end } = display_range.sorted();
21278
21279        let buffer_snapshot = self.buffer.read(cx).snapshot(cx);
21280        let editor_snapshot = self.snapshot(window, cx);
21281
21282        // Convert display rows to multibuffer points
21283        let start_point = editor_snapshot
21284            .display_snapshot
21285            .display_point_to_point(start.as_display_point(), Bias::Left);
21286        let end_point = editor_snapshot
21287            .display_snapshot
21288            .display_point_to_point(end.as_display_point(), Bias::Left);
21289        let end_multi_buffer_row = MultiBufferRow(end_point.row);
21290
21291        // Create anchor range for the selected lines (start of first line to end of last line)
21292        let line_end = Point::new(
21293            end_point.row,
21294            buffer_snapshot.line_len(end_multi_buffer_row),
21295        );
21296        let anchor_range =
21297            buffer_snapshot.anchor_after(start_point)..buffer_snapshot.anchor_before(line_end);
21298
21299        // Compute the hunk key for this display row
21300        let file_path = buffer_snapshot
21301            .file_at(start_point)
21302            .map(|file: &Arc<dyn language::File>| file.path().clone())
21303            .unwrap_or_else(|| Arc::from(util::rel_path::RelPath::empty()));
21304        let hunk_start_anchor = buffer_snapshot.anchor_before(start_point);
21305        let new_hunk_key = DiffHunkKey {
21306            file_path,
21307            hunk_start_anchor,
21308        };
21309
21310        // Check if we already have an overlay for this hunk
21311        if let Some(existing_overlay) = self.diff_review_overlays.iter().find(|overlay| {
21312            Self::hunk_keys_match(&overlay.hunk_key, &new_hunk_key, &buffer_snapshot)
21313        }) {
21314            // Just focus the existing overlay's prompt editor
21315            let focus_handle = existing_overlay.prompt_editor.focus_handle(cx);
21316            window.focus(&focus_handle, cx);
21317            return;
21318        }
21319
21320        // Dismiss overlays that have no comments for their hunks
21321        self.dismiss_overlays_without_comments(cx);
21322
21323        // Get the current user's avatar URI from the project's user_store
21324        let user_avatar_uri = self.project.as_ref().and_then(|project| {
21325            let user_store = project.read(cx).user_store();
21326            user_store
21327                .read(cx)
21328                .current_user()
21329                .map(|user| user.avatar_uri.clone())
21330        });
21331
21332        // Create anchor at the end of the last row so the block appears immediately below it
21333        // Use multibuffer coordinates for anchor creation
21334        let line_len = buffer_snapshot.line_len(end_multi_buffer_row);
21335        let anchor = buffer_snapshot.anchor_after(Point::new(end_multi_buffer_row.0, line_len));
21336
21337        // Use the hunk key we already computed
21338        let hunk_key = new_hunk_key;
21339
21340        // Create the prompt editor for the review input
21341        let prompt_editor = cx.new(|cx| {
21342            let mut editor = Editor::single_line(window, cx);
21343            editor.set_placeholder_text("Add a review comment...", window, cx);
21344            editor
21345        });
21346
21347        // Register the Newline action on the prompt editor to submit the review
21348        let parent_editor = cx.entity().downgrade();
21349        let subscription = prompt_editor.update(cx, |prompt_editor, _cx| {
21350            prompt_editor.register_action({
21351                let parent_editor = parent_editor.clone();
21352                move |_: &crate::actions::Newline, window, cx| {
21353                    if let Some(editor) = parent_editor.upgrade() {
21354                        editor.update(cx, |editor, cx| {
21355                            editor.submit_diff_review_comment(window, cx);
21356                        });
21357                    }
21358                }
21359            })
21360        });
21361
21362        // Calculate initial height based on existing comments for this hunk
21363        let initial_height = self.calculate_overlay_height(&hunk_key, true, &buffer_snapshot);
21364
21365        // Create the overlay block
21366        let prompt_editor_for_render = prompt_editor.clone();
21367        let hunk_key_for_render = hunk_key.clone();
21368        let editor_handle = cx.entity().downgrade();
21369        let block = BlockProperties {
21370            style: BlockStyle::Sticky,
21371            placement: BlockPlacement::Below(anchor),
21372            height: Some(initial_height),
21373            render: Arc::new(move |cx| {
21374                Self::render_diff_review_overlay(
21375                    &prompt_editor_for_render,
21376                    &hunk_key_for_render,
21377                    &editor_handle,
21378                    cx,
21379                )
21380            }),
21381            priority: 0,
21382        };
21383
21384        let block_ids = self.insert_blocks([block], None, cx);
21385        let Some(block_id) = block_ids.into_iter().next() else {
21386            log::error!("Failed to insert diff review overlay block");
21387            return;
21388        };
21389
21390        self.diff_review_overlays.push(DiffReviewOverlay {
21391            anchor_range,
21392            block_id,
21393            prompt_editor: prompt_editor.clone(),
21394            hunk_key,
21395            comments_expanded: true,
21396            inline_edit_editors: HashMap::default(),
21397            inline_edit_subscriptions: HashMap::default(),
21398            user_avatar_uri,
21399            _subscription: subscription,
21400        });
21401
21402        // Focus the prompt editor
21403        let focus_handle = prompt_editor.focus_handle(cx);
21404        window.focus(&focus_handle, cx);
21405
21406        cx.notify();
21407    }
21408
21409    /// Dismisses all diff review overlays.
21410    pub fn dismiss_all_diff_review_overlays(&mut self, cx: &mut Context<Self>) {
21411        if self.diff_review_overlays.is_empty() {
21412            return;
21413        }
21414        let block_ids: HashSet<_> = self
21415            .diff_review_overlays
21416            .drain(..)
21417            .map(|overlay| overlay.block_id)
21418            .collect();
21419        self.remove_blocks(block_ids, None, cx);
21420        cx.notify();
21421    }
21422
21423    /// Dismisses overlays that have no comments stored for their hunks.
21424    /// Keeps overlays that have at least one comment.
21425    fn dismiss_overlays_without_comments(&mut self, cx: &mut Context<Self>) {
21426        let snapshot = self.buffer.read(cx).snapshot(cx);
21427
21428        // First, compute which overlays have comments (to avoid borrow issues with retain)
21429        let overlays_with_comments: Vec<bool> = self
21430            .diff_review_overlays
21431            .iter()
21432            .map(|overlay| self.hunk_comment_count(&overlay.hunk_key, &snapshot) > 0)
21433            .collect();
21434
21435        // Now collect block IDs to remove and retain overlays
21436        let mut block_ids_to_remove = HashSet::default();
21437        let mut index = 0;
21438        self.diff_review_overlays.retain(|overlay| {
21439            let has_comments = overlays_with_comments[index];
21440            index += 1;
21441            if !has_comments {
21442                block_ids_to_remove.insert(overlay.block_id);
21443            }
21444            has_comments
21445        });
21446
21447        if !block_ids_to_remove.is_empty() {
21448            self.remove_blocks(block_ids_to_remove, None, cx);
21449            cx.notify();
21450        }
21451    }
21452
21453    /// Refreshes the diff review overlay block to update its height and render function.
21454    /// Uses resize_blocks and replace_blocks to avoid visual flicker from remove+insert.
21455    fn refresh_diff_review_overlay_height(
21456        &mut self,
21457        hunk_key: &DiffHunkKey,
21458        _window: &mut Window,
21459        cx: &mut Context<Self>,
21460    ) {
21461        // Extract all needed data from overlay first to avoid borrow conflicts
21462        let snapshot = self.buffer.read(cx).snapshot(cx);
21463        let (comments_expanded, block_id, prompt_editor) = {
21464            let Some(overlay) = self
21465                .diff_review_overlays
21466                .iter()
21467                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21468            else {
21469                return;
21470            };
21471
21472            (
21473                overlay.comments_expanded,
21474                overlay.block_id,
21475                overlay.prompt_editor.clone(),
21476            )
21477        };
21478
21479        // Calculate new height
21480        let snapshot = self.buffer.read(cx).snapshot(cx);
21481        let new_height = self.calculate_overlay_height(hunk_key, comments_expanded, &snapshot);
21482
21483        // Update the block height using resize_blocks (avoids flicker)
21484        let mut heights = HashMap::default();
21485        heights.insert(block_id, new_height);
21486        self.resize_blocks(heights, None, cx);
21487
21488        // Update the render function using replace_blocks (avoids flicker)
21489        let hunk_key_for_render = hunk_key.clone();
21490        let editor_handle = cx.entity().downgrade();
21491        let render: Arc<dyn Fn(&mut BlockContext) -> AnyElement + Send + Sync> =
21492            Arc::new(move |cx| {
21493                Self::render_diff_review_overlay(
21494                    &prompt_editor,
21495                    &hunk_key_for_render,
21496                    &editor_handle,
21497                    cx,
21498                )
21499            });
21500
21501        let mut renderers = HashMap::default();
21502        renderers.insert(block_id, render);
21503        self.replace_blocks(renderers, None, cx);
21504    }
21505
21506    /// Action handler for SubmitDiffReviewComment.
21507    pub fn submit_diff_review_comment_action(
21508        &mut self,
21509        _: &SubmitDiffReviewComment,
21510        window: &mut Window,
21511        cx: &mut Context<Self>,
21512    ) {
21513        self.submit_diff_review_comment(window, cx);
21514    }
21515
21516    /// Stores the diff review comment locally.
21517    /// Comments are stored per-hunk and can later be batch-submitted to the Agent panel.
21518    pub fn submit_diff_review_comment(&mut self, window: &mut Window, cx: &mut Context<Self>) {
21519        // Find the overlay that currently has focus
21520        let overlay_index = self
21521            .diff_review_overlays
21522            .iter()
21523            .position(|overlay| overlay.prompt_editor.focus_handle(cx).is_focused(window));
21524        let Some(overlay_index) = overlay_index else {
21525            return;
21526        };
21527        let overlay = &self.diff_review_overlays[overlay_index];
21528
21529        let comment_text = overlay.prompt_editor.read(cx).text(cx).trim().to_string();
21530        if comment_text.is_empty() {
21531            return;
21532        }
21533
21534        let anchor_range = overlay.anchor_range.clone();
21535        let hunk_key = overlay.hunk_key.clone();
21536
21537        self.add_review_comment(hunk_key.clone(), comment_text, anchor_range, cx);
21538
21539        // Clear the prompt editor but keep the overlay open
21540        if let Some(overlay) = self.diff_review_overlays.get(overlay_index) {
21541            overlay.prompt_editor.update(cx, |editor, cx| {
21542                editor.clear(window, cx);
21543            });
21544        }
21545
21546        // Refresh the overlay to update the block height for the new comment
21547        self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21548
21549        cx.notify();
21550    }
21551
21552    /// Returns the prompt editor for the diff review overlay, if one is active.
21553    /// This is primarily used for testing.
21554    pub fn diff_review_prompt_editor(&self) -> Option<&Entity<Editor>> {
21555        self.diff_review_overlays
21556            .first()
21557            .map(|overlay| &overlay.prompt_editor)
21558    }
21559
21560    /// Returns the line range for the first diff review overlay, if one is active.
21561    /// Returns (start_row, end_row) as physical line numbers in the underlying file.
21562    pub fn diff_review_line_range(&self, cx: &App) -> Option<(u32, u32)> {
21563        let overlay = self.diff_review_overlays.first()?;
21564        let snapshot = self.buffer.read(cx).snapshot(cx);
21565        let start_point = overlay.anchor_range.start.to_point(&snapshot);
21566        let end_point = overlay.anchor_range.end.to_point(&snapshot);
21567        let start_row = snapshot
21568            .point_to_buffer_point(start_point)
21569            .map(|(_, p, _)| p.row)
21570            .unwrap_or(start_point.row);
21571        let end_row = snapshot
21572            .point_to_buffer_point(end_point)
21573            .map(|(_, p, _)| p.row)
21574            .unwrap_or(end_point.row);
21575        Some((start_row, end_row))
21576    }
21577
21578    /// Sets whether the comments section is expanded in the diff review overlay.
21579    /// This is primarily used for testing.
21580    pub fn set_diff_review_comments_expanded(&mut self, expanded: bool, cx: &mut Context<Self>) {
21581        for overlay in &mut self.diff_review_overlays {
21582            overlay.comments_expanded = expanded;
21583        }
21584        cx.notify();
21585    }
21586
21587    /// Compares two DiffHunkKeys for equality by resolving their anchors.
21588    fn hunk_keys_match(a: &DiffHunkKey, b: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> bool {
21589        a.file_path == b.file_path
21590            && a.hunk_start_anchor.to_point(snapshot) == b.hunk_start_anchor.to_point(snapshot)
21591    }
21592
21593    /// Returns comments for a specific hunk, ordered by creation time.
21594    pub fn comments_for_hunk<'a>(
21595        &'a self,
21596        key: &DiffHunkKey,
21597        snapshot: &MultiBufferSnapshot,
21598    ) -> &'a [StoredReviewComment] {
21599        let key_point = key.hunk_start_anchor.to_point(snapshot);
21600        self.stored_review_comments
21601            .iter()
21602            .find(|(k, _)| {
21603                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21604            })
21605            .map(|(_, comments)| comments.as_slice())
21606            .unwrap_or(&[])
21607    }
21608
21609    /// Returns the total count of stored review comments across all hunks.
21610    pub fn total_review_comment_count(&self) -> usize {
21611        self.stored_review_comments
21612            .iter()
21613            .map(|(_, v)| v.len())
21614            .sum()
21615    }
21616
21617    /// Returns the count of comments for a specific hunk.
21618    pub fn hunk_comment_count(&self, key: &DiffHunkKey, snapshot: &MultiBufferSnapshot) -> usize {
21619        let key_point = key.hunk_start_anchor.to_point(snapshot);
21620        self.stored_review_comments
21621            .iter()
21622            .find(|(k, _)| {
21623                k.file_path == key.file_path && k.hunk_start_anchor.to_point(snapshot) == key_point
21624            })
21625            .map(|(_, v)| v.len())
21626            .unwrap_or(0)
21627    }
21628
21629    /// Adds a new review comment to a specific hunk.
21630    pub fn add_review_comment(
21631        &mut self,
21632        hunk_key: DiffHunkKey,
21633        comment: String,
21634        anchor_range: Range<Anchor>,
21635        cx: &mut Context<Self>,
21636    ) -> usize {
21637        let id = self.next_review_comment_id;
21638        self.next_review_comment_id += 1;
21639
21640        let stored_comment = StoredReviewComment::new(id, comment, anchor_range);
21641
21642        let snapshot = self.buffer.read(cx).snapshot(cx);
21643        let key_point = hunk_key.hunk_start_anchor.to_point(&snapshot);
21644
21645        // Find existing entry for this hunk or add a new one
21646        if let Some((_, comments)) = self.stored_review_comments.iter_mut().find(|(k, _)| {
21647            k.file_path == hunk_key.file_path
21648                && k.hunk_start_anchor.to_point(&snapshot) == key_point
21649        }) {
21650            comments.push(stored_comment);
21651        } else {
21652            self.stored_review_comments
21653                .push((hunk_key, vec![stored_comment]));
21654        }
21655
21656        cx.emit(EditorEvent::ReviewCommentsChanged {
21657            total_count: self.total_review_comment_count(),
21658        });
21659        cx.notify();
21660        id
21661    }
21662
21663    /// Removes a review comment by ID from any hunk.
21664    pub fn remove_review_comment(&mut self, id: usize, cx: &mut Context<Self>) -> bool {
21665        for (_, comments) in self.stored_review_comments.iter_mut() {
21666            if let Some(index) = comments.iter().position(|c| c.id == id) {
21667                comments.remove(index);
21668                cx.emit(EditorEvent::ReviewCommentsChanged {
21669                    total_count: self.total_review_comment_count(),
21670                });
21671                cx.notify();
21672                return true;
21673            }
21674        }
21675        false
21676    }
21677
21678    /// Updates a review comment's text by ID.
21679    pub fn update_review_comment(
21680        &mut self,
21681        id: usize,
21682        new_comment: String,
21683        cx: &mut Context<Self>,
21684    ) -> bool {
21685        for (_, comments) in self.stored_review_comments.iter_mut() {
21686            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21687                comment.comment = new_comment;
21688                comment.is_editing = false;
21689                cx.emit(EditorEvent::ReviewCommentsChanged {
21690                    total_count: self.total_review_comment_count(),
21691                });
21692                cx.notify();
21693                return true;
21694            }
21695        }
21696        false
21697    }
21698
21699    /// Sets a comment's editing state.
21700    pub fn set_comment_editing(&mut self, id: usize, is_editing: bool, cx: &mut Context<Self>) {
21701        for (_, comments) in self.stored_review_comments.iter_mut() {
21702            if let Some(comment) = comments.iter_mut().find(|c| c.id == id) {
21703                comment.is_editing = is_editing;
21704                cx.notify();
21705                return;
21706            }
21707        }
21708    }
21709
21710    /// Takes all stored comments from all hunks, clearing the storage.
21711    /// Returns a Vec of (hunk_key, comments) pairs.
21712    pub fn take_all_review_comments(
21713        &mut self,
21714        cx: &mut Context<Self>,
21715    ) -> Vec<(DiffHunkKey, Vec<StoredReviewComment>)> {
21716        // Dismiss all overlays when taking comments (e.g., when sending to agent)
21717        self.dismiss_all_diff_review_overlays(cx);
21718        let comments = std::mem::take(&mut self.stored_review_comments);
21719        // Reset the ID counter since all comments have been taken
21720        self.next_review_comment_id = 0;
21721        cx.emit(EditorEvent::ReviewCommentsChanged { total_count: 0 });
21722        cx.notify();
21723        comments
21724    }
21725
21726    /// Removes review comments whose anchors are no longer valid or whose
21727    /// associated diff hunks no longer exist.
21728    ///
21729    /// This should be called when the buffer changes to prevent orphaned comments
21730    /// from accumulating.
21731    pub fn cleanup_orphaned_review_comments(&mut self, cx: &mut Context<Self>) {
21732        let snapshot = self.buffer.read(cx).snapshot(cx);
21733        let original_count = self.total_review_comment_count();
21734
21735        // Remove comments with invalid hunk anchors
21736        self.stored_review_comments
21737            .retain(|(hunk_key, _)| hunk_key.hunk_start_anchor.is_valid(&snapshot));
21738
21739        // Also clean up individual comments with invalid anchor ranges
21740        for (_, comments) in &mut self.stored_review_comments {
21741            comments.retain(|comment| {
21742                comment.range.start.is_valid(&snapshot) && comment.range.end.is_valid(&snapshot)
21743            });
21744        }
21745
21746        // Remove empty hunk entries
21747        self.stored_review_comments
21748            .retain(|(_, comments)| !comments.is_empty());
21749
21750        let new_count = self.total_review_comment_count();
21751        if new_count != original_count {
21752            cx.emit(EditorEvent::ReviewCommentsChanged {
21753                total_count: new_count,
21754            });
21755            cx.notify();
21756        }
21757    }
21758
21759    /// Toggles the expanded state of the comments section in the overlay.
21760    pub fn toggle_review_comments_expanded(
21761        &mut self,
21762        _: &ToggleReviewCommentsExpanded,
21763        window: &mut Window,
21764        cx: &mut Context<Self>,
21765    ) {
21766        // Find the overlay that currently has focus, or use the first one
21767        let overlay_info = self.diff_review_overlays.iter_mut().find_map(|overlay| {
21768            if overlay.prompt_editor.focus_handle(cx).is_focused(window) {
21769                overlay.comments_expanded = !overlay.comments_expanded;
21770                Some(overlay.hunk_key.clone())
21771            } else {
21772                None
21773            }
21774        });
21775
21776        // If no focused overlay found, toggle the first one
21777        let hunk_key = overlay_info.or_else(|| {
21778            self.diff_review_overlays.first_mut().map(|overlay| {
21779                overlay.comments_expanded = !overlay.comments_expanded;
21780                overlay.hunk_key.clone()
21781            })
21782        });
21783
21784        if let Some(hunk_key) = hunk_key {
21785            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
21786            cx.notify();
21787        }
21788    }
21789
21790    /// Handles the EditReviewComment action - sets a comment into editing mode.
21791    pub fn edit_review_comment(
21792        &mut self,
21793        action: &EditReviewComment,
21794        window: &mut Window,
21795        cx: &mut Context<Self>,
21796    ) {
21797        let comment_id = action.id;
21798
21799        // Set the comment to editing mode
21800        self.set_comment_editing(comment_id, true, cx);
21801
21802        // Find the overlay that contains this comment and create an inline editor if needed
21803        // First, find which hunk this comment belongs to
21804        let hunk_key = self
21805            .stored_review_comments
21806            .iter()
21807            .find_map(|(key, comments)| {
21808                if comments.iter().any(|c| c.id == comment_id) {
21809                    Some(key.clone())
21810                } else {
21811                    None
21812                }
21813            });
21814
21815        let snapshot = self.buffer.read(cx).snapshot(cx);
21816        if let Some(hunk_key) = hunk_key {
21817            if let Some(overlay) = self
21818                .diff_review_overlays
21819                .iter_mut()
21820                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21821            {
21822                if let std::collections::hash_map::Entry::Vacant(entry) =
21823                    overlay.inline_edit_editors.entry(comment_id)
21824                {
21825                    // Find the comment text
21826                    let comment_text = self
21827                        .stored_review_comments
21828                        .iter()
21829                        .flat_map(|(_, comments)| comments)
21830                        .find(|c| c.id == comment_id)
21831                        .map(|c| c.comment.clone())
21832                        .unwrap_or_default();
21833
21834                    // Create inline editor
21835                    let parent_editor = cx.entity().downgrade();
21836                    let inline_editor = cx.new(|cx| {
21837                        let mut editor = Editor::single_line(window, cx);
21838                        editor.set_text(&*comment_text, window, cx);
21839                        // Select all text for easy replacement
21840                        editor.select_all(&crate::actions::SelectAll, window, cx);
21841                        editor
21842                    });
21843
21844                    // Register the Newline action to confirm the edit
21845                    let subscription = inline_editor.update(cx, |inline_editor, _cx| {
21846                        inline_editor.register_action({
21847                            let parent_editor = parent_editor.clone();
21848                            move |_: &crate::actions::Newline, window, cx| {
21849                                if let Some(editor) = parent_editor.upgrade() {
21850                                    editor.update(cx, |editor, cx| {
21851                                        editor.confirm_edit_review_comment(comment_id, window, cx);
21852                                    });
21853                                }
21854                            }
21855                        })
21856                    });
21857
21858                    // Store the subscription to keep the action handler alive
21859                    overlay
21860                        .inline_edit_subscriptions
21861                        .insert(comment_id, subscription);
21862
21863                    // Focus the inline editor
21864                    let focus_handle = inline_editor.focus_handle(cx);
21865                    window.focus(&focus_handle, cx);
21866
21867                    entry.insert(inline_editor);
21868                }
21869            }
21870        }
21871
21872        cx.notify();
21873    }
21874
21875    /// Confirms an inline edit of a review comment.
21876    pub fn confirm_edit_review_comment(
21877        &mut self,
21878        comment_id: usize,
21879        _window: &mut Window,
21880        cx: &mut Context<Self>,
21881    ) {
21882        // Get the new text from the inline editor
21883        // Find the overlay containing this comment's inline editor
21884        let snapshot = self.buffer.read(cx).snapshot(cx);
21885        let hunk_key = self
21886            .stored_review_comments
21887            .iter()
21888            .find_map(|(key, comments)| {
21889                if comments.iter().any(|c| c.id == comment_id) {
21890                    Some(key.clone())
21891                } else {
21892                    None
21893                }
21894            });
21895
21896        let new_text = hunk_key
21897            .as_ref()
21898            .and_then(|hunk_key| {
21899                self.diff_review_overlays
21900                    .iter()
21901                    .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot))
21902            })
21903            .as_ref()
21904            .and_then(|overlay| overlay.inline_edit_editors.get(&comment_id))
21905            .map(|editor| editor.read(cx).text(cx).trim().to_string());
21906
21907        if let Some(new_text) = new_text {
21908            if !new_text.is_empty() {
21909                self.update_review_comment(comment_id, new_text, cx);
21910            }
21911        }
21912
21913        // Remove the inline editor and its subscription
21914        if let Some(hunk_key) = hunk_key {
21915            if let Some(overlay) = self
21916                .diff_review_overlays
21917                .iter_mut()
21918                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21919            {
21920                overlay.inline_edit_editors.remove(&comment_id);
21921                overlay.inline_edit_subscriptions.remove(&comment_id);
21922            }
21923        }
21924
21925        // Clear editing state
21926        self.set_comment_editing(comment_id, false, cx);
21927    }
21928
21929    /// Cancels an inline edit of a review comment.
21930    pub fn cancel_edit_review_comment(
21931        &mut self,
21932        comment_id: usize,
21933        _window: &mut Window,
21934        cx: &mut Context<Self>,
21935    ) {
21936        // Find which hunk this comment belongs to
21937        let hunk_key = self
21938            .stored_review_comments
21939            .iter()
21940            .find_map(|(key, comments)| {
21941                if comments.iter().any(|c| c.id == comment_id) {
21942                    Some(key.clone())
21943                } else {
21944                    None
21945                }
21946            });
21947
21948        // Remove the inline editor and its subscription
21949        if let Some(hunk_key) = hunk_key {
21950            let snapshot = self.buffer.read(cx).snapshot(cx);
21951            if let Some(overlay) = self
21952                .diff_review_overlays
21953                .iter_mut()
21954                .find(|overlay| Self::hunk_keys_match(&overlay.hunk_key, &hunk_key, &snapshot))
21955            {
21956                overlay.inline_edit_editors.remove(&comment_id);
21957                overlay.inline_edit_subscriptions.remove(&comment_id);
21958            }
21959        }
21960
21961        // Clear editing state
21962        self.set_comment_editing(comment_id, false, cx);
21963    }
21964
21965    /// Action handler for ConfirmEditReviewComment.
21966    pub fn confirm_edit_review_comment_action(
21967        &mut self,
21968        action: &ConfirmEditReviewComment,
21969        window: &mut Window,
21970        cx: &mut Context<Self>,
21971    ) {
21972        self.confirm_edit_review_comment(action.id, window, cx);
21973    }
21974
21975    /// Action handler for CancelEditReviewComment.
21976    pub fn cancel_edit_review_comment_action(
21977        &mut self,
21978        action: &CancelEditReviewComment,
21979        window: &mut Window,
21980        cx: &mut Context<Self>,
21981    ) {
21982        self.cancel_edit_review_comment(action.id, window, cx);
21983    }
21984
21985    /// Handles the DeleteReviewComment action - removes a comment.
21986    pub fn delete_review_comment(
21987        &mut self,
21988        action: &DeleteReviewComment,
21989        window: &mut Window,
21990        cx: &mut Context<Self>,
21991    ) {
21992        // Get the hunk key before removing the comment
21993        // Find the hunk key from the comment itself
21994        let comment_id = action.id;
21995        let hunk_key = self
21996            .stored_review_comments
21997            .iter()
21998            .find_map(|(key, comments)| {
21999                if comments.iter().any(|c| c.id == comment_id) {
22000                    Some(key.clone())
22001                } else {
22002                    None
22003                }
22004            });
22005
22006        // Also get it from the overlay for refresh purposes
22007        let overlay_hunk_key = self
22008            .diff_review_overlays
22009            .first()
22010            .map(|o| o.hunk_key.clone());
22011
22012        self.remove_review_comment(action.id, cx);
22013
22014        // Refresh the overlay height after removing a comment
22015        if let Some(hunk_key) = hunk_key.or(overlay_hunk_key) {
22016            self.refresh_diff_review_overlay_height(&hunk_key, window, cx);
22017        }
22018    }
22019
22020    fn render_diff_review_overlay(
22021        prompt_editor: &Entity<Editor>,
22022        hunk_key: &DiffHunkKey,
22023        editor_handle: &WeakEntity<Editor>,
22024        cx: &mut BlockContext,
22025    ) -> AnyElement {
22026        fn format_line_ranges(ranges: &[(u32, u32)]) -> Option<String> {
22027            if ranges.is_empty() {
22028                return None;
22029            }
22030            let formatted: Vec<String> = ranges
22031                .iter()
22032                .map(|(start, end)| {
22033                    let start_line = start + 1;
22034                    let end_line = end + 1;
22035                    if start_line == end_line {
22036                        format!("Line {start_line}")
22037                    } else {
22038                        format!("Lines {start_line}-{end_line}")
22039                    }
22040                })
22041                .collect();
22042            // Don't show label for single line in single excerpt
22043            if ranges.len() == 1 && ranges[0].0 == ranges[0].1 {
22044                return None;
22045            }
22046            Some(formatted.join(""))
22047        }
22048
22049        let theme = cx.theme();
22050        let colors = theme.colors();
22051
22052        let (comments, comments_expanded, inline_editors, user_avatar_uri, line_ranges) =
22053            editor_handle
22054                .upgrade()
22055                .map(|editor| {
22056                    let editor = editor.read(cx);
22057                    let snapshot = editor.buffer().read(cx).snapshot(cx);
22058                    let comments = editor.comments_for_hunk(hunk_key, &snapshot).to_vec();
22059                    let (expanded, editors, avatar_uri, line_ranges) = editor
22060                        .diff_review_overlays
22061                        .iter()
22062                        .find(|overlay| {
22063                            Editor::hunk_keys_match(&overlay.hunk_key, hunk_key, &snapshot)
22064                        })
22065                        .map(|o| {
22066                            let start_point = o.anchor_range.start.to_point(&snapshot);
22067                            let end_point = o.anchor_range.end.to_point(&snapshot);
22068                            // Get line ranges per excerpt to detect discontinuities
22069                            let buffer_ranges =
22070                                snapshot.range_to_buffer_ranges(start_point..end_point);
22071                            let ranges: Vec<(u32, u32)> = buffer_ranges
22072                                .iter()
22073                                .map(|(buffer, range, _)| {
22074                                    let start = buffer.offset_to_point(range.start.0).row;
22075                                    let end = buffer.offset_to_point(range.end.0).row;
22076                                    (start, end)
22077                                })
22078                                .collect();
22079                            (
22080                                o.comments_expanded,
22081                                o.inline_edit_editors.clone(),
22082                                o.user_avatar_uri.clone(),
22083                                if ranges.is_empty() {
22084                                    None
22085                                } else {
22086                                    Some(ranges)
22087                                },
22088                            )
22089                        })
22090                        .unwrap_or((true, HashMap::default(), None, None));
22091                    (comments, expanded, editors, avatar_uri, line_ranges)
22092                })
22093                .unwrap_or((Vec::new(), true, HashMap::default(), None, None));
22094
22095        let comment_count = comments.len();
22096        let avatar_size = px(20.);
22097        let action_icon_size = IconSize::XSmall;
22098
22099        v_flex()
22100            .w_full()
22101            .bg(colors.editor_background)
22102            .border_b_1()
22103            .border_color(colors.border)
22104            .px_2()
22105            .pb_2()
22106            .gap_2()
22107            // Line range indicator (only shown for multi-line selections or multiple excerpts)
22108            .when_some(line_ranges, |el, ranges| {
22109                let label = format_line_ranges(&ranges);
22110                if let Some(label) = label {
22111                    el.child(
22112                        h_flex()
22113                            .w_full()
22114                            .px_2()
22115                            .child(Label::new(label).size(LabelSize::Small).color(Color::Muted)),
22116                    )
22117                } else {
22118                    el
22119                }
22120            })
22121            // Top row: editable input with user's avatar
22122            .child(
22123                h_flex()
22124                    .w_full()
22125                    .items_center()
22126                    .gap_2()
22127                    .px_2()
22128                    .py_1p5()
22129                    .rounded_md()
22130                    .bg(colors.surface_background)
22131                    .child(
22132                        div()
22133                            .size(avatar_size)
22134                            .flex_shrink_0()
22135                            .rounded_full()
22136                            .overflow_hidden()
22137                            .child(if let Some(ref avatar_uri) = user_avatar_uri {
22138                                Avatar::new(avatar_uri.clone())
22139                                    .size(avatar_size)
22140                                    .into_any_element()
22141                            } else {
22142                                Icon::new(IconName::Person)
22143                                    .size(IconSize::Small)
22144                                    .color(ui::Color::Muted)
22145                                    .into_any_element()
22146                            }),
22147                    )
22148                    .child(
22149                        div()
22150                            .flex_1()
22151                            .border_1()
22152                            .border_color(colors.border)
22153                            .rounded_md()
22154                            .bg(colors.editor_background)
22155                            .px_2()
22156                            .py_1()
22157                            .child(prompt_editor.clone()),
22158                    )
22159                    .child(
22160                        h_flex()
22161                            .flex_shrink_0()
22162                            .gap_1()
22163                            .child(
22164                                IconButton::new("diff-review-close", IconName::Close)
22165                                    .icon_color(ui::Color::Muted)
22166                                    .icon_size(action_icon_size)
22167                                    .tooltip(Tooltip::text("Close"))
22168                                    .on_click(|_, window, cx| {
22169                                        window
22170                                            .dispatch_action(Box::new(crate::actions::Cancel), cx);
22171                                    }),
22172                            )
22173                            .child(
22174                                IconButton::new("diff-review-add", IconName::Return)
22175                                    .icon_color(ui::Color::Muted)
22176                                    .icon_size(action_icon_size)
22177                                    .tooltip(Tooltip::text("Add comment"))
22178                                    .on_click(|_, window, cx| {
22179                                        window.dispatch_action(
22180                                            Box::new(crate::actions::SubmitDiffReviewComment),
22181                                            cx,
22182                                        );
22183                                    }),
22184                            ),
22185                    ),
22186            )
22187            // Expandable comments section (only shown when there are comments)
22188            .when(comment_count > 0, |el| {
22189                el.child(Self::render_comments_section(
22190                    comments,
22191                    comments_expanded,
22192                    inline_editors,
22193                    user_avatar_uri,
22194                    avatar_size,
22195                    action_icon_size,
22196                    colors,
22197                ))
22198            })
22199            .into_any_element()
22200    }
22201
22202    fn render_comments_section(
22203        comments: Vec<StoredReviewComment>,
22204        expanded: bool,
22205        inline_editors: HashMap<usize, Entity<Editor>>,
22206        user_avatar_uri: Option<SharedUri>,
22207        avatar_size: Pixels,
22208        action_icon_size: IconSize,
22209        colors: &theme::ThemeColors,
22210    ) -> impl IntoElement {
22211        let comment_count = comments.len();
22212
22213        v_flex()
22214            .w_full()
22215            .gap_1()
22216            // Header with expand/collapse toggle
22217            .child(
22218                h_flex()
22219                    .id("review-comments-header")
22220                    .w_full()
22221                    .items_center()
22222                    .gap_1()
22223                    .px_2()
22224                    .py_1()
22225                    .cursor_pointer()
22226                    .rounded_md()
22227                    .hover(|style| style.bg(colors.ghost_element_hover))
22228                    .on_click(|_, window: &mut Window, cx| {
22229                        window.dispatch_action(
22230                            Box::new(crate::actions::ToggleReviewCommentsExpanded),
22231                            cx,
22232                        );
22233                    })
22234                    .child(
22235                        Icon::new(if expanded {
22236                            IconName::ChevronDown
22237                        } else {
22238                            IconName::ChevronRight
22239                        })
22240                        .size(IconSize::Small)
22241                        .color(ui::Color::Muted),
22242                    )
22243                    .child(
22244                        Label::new(format!(
22245                            "{} Comment{}",
22246                            comment_count,
22247                            if comment_count == 1 { "" } else { "s" }
22248                        ))
22249                        .size(LabelSize::Small)
22250                        .color(Color::Muted),
22251                    ),
22252            )
22253            // Comments list (when expanded)
22254            .when(expanded, |el| {
22255                el.children(comments.into_iter().map(|comment| {
22256                    let inline_editor = inline_editors.get(&comment.id).cloned();
22257                    Self::render_comment_row(
22258                        comment,
22259                        inline_editor,
22260                        user_avatar_uri.clone(),
22261                        avatar_size,
22262                        action_icon_size,
22263                        colors,
22264                    )
22265                }))
22266            })
22267    }
22268
22269    fn render_comment_row(
22270        comment: StoredReviewComment,
22271        inline_editor: Option<Entity<Editor>>,
22272        user_avatar_uri: Option<SharedUri>,
22273        avatar_size: Pixels,
22274        action_icon_size: IconSize,
22275        colors: &theme::ThemeColors,
22276    ) -> impl IntoElement {
22277        let comment_id = comment.id;
22278        let is_editing = inline_editor.is_some();
22279
22280        h_flex()
22281            .w_full()
22282            .items_center()
22283            .gap_2()
22284            .px_2()
22285            .py_1p5()
22286            .rounded_md()
22287            .bg(colors.surface_background)
22288            .child(
22289                div()
22290                    .size(avatar_size)
22291                    .flex_shrink_0()
22292                    .rounded_full()
22293                    .overflow_hidden()
22294                    .child(if let Some(ref avatar_uri) = user_avatar_uri {
22295                        Avatar::new(avatar_uri.clone())
22296                            .size(avatar_size)
22297                            .into_any_element()
22298                    } else {
22299                        Icon::new(IconName::Person)
22300                            .size(IconSize::Small)
22301                            .color(ui::Color::Muted)
22302                            .into_any_element()
22303                    }),
22304            )
22305            .child(if let Some(editor) = inline_editor {
22306                // Inline edit mode: show an editable text field
22307                div()
22308                    .flex_1()
22309                    .border_1()
22310                    .border_color(colors.border)
22311                    .rounded_md()
22312                    .bg(colors.editor_background)
22313                    .px_2()
22314                    .py_1()
22315                    .child(editor)
22316                    .into_any_element()
22317            } else {
22318                // Display mode: show the comment text
22319                div()
22320                    .flex_1()
22321                    .text_sm()
22322                    .text_color(colors.text)
22323                    .child(comment.comment)
22324                    .into_any_element()
22325            })
22326            .child(if is_editing {
22327                // Editing mode: show close and confirm buttons
22328                h_flex()
22329                    .gap_1()
22330                    .child(
22331                        IconButton::new(
22332                            format!("diff-review-cancel-edit-{comment_id}"),
22333                            IconName::Close,
22334                        )
22335                        .icon_color(ui::Color::Muted)
22336                        .icon_size(action_icon_size)
22337                        .tooltip(Tooltip::text("Cancel"))
22338                        .on_click(move |_, window, cx| {
22339                            window.dispatch_action(
22340                                Box::new(crate::actions::CancelEditReviewComment {
22341                                    id: comment_id,
22342                                }),
22343                                cx,
22344                            );
22345                        }),
22346                    )
22347                    .child(
22348                        IconButton::new(
22349                            format!("diff-review-confirm-edit-{comment_id}"),
22350                            IconName::Return,
22351                        )
22352                        .icon_color(ui::Color::Muted)
22353                        .icon_size(action_icon_size)
22354                        .tooltip(Tooltip::text("Confirm"))
22355                        .on_click(move |_, window, cx| {
22356                            window.dispatch_action(
22357                                Box::new(crate::actions::ConfirmEditReviewComment {
22358                                    id: comment_id,
22359                                }),
22360                                cx,
22361                            );
22362                        }),
22363                    )
22364                    .into_any_element()
22365            } else {
22366                // Display mode: no action buttons for now (edit/delete not yet implemented)
22367                gpui::Empty.into_any_element()
22368            })
22369    }
22370
22371    pub fn set_masked(&mut self, masked: bool, cx: &mut Context<Self>) {
22372        if self.display_map.read(cx).masked != masked {
22373            self.display_map.update(cx, |map, _| map.masked = masked);
22374        }
22375        cx.notify()
22376    }
22377
22378    pub fn set_show_wrap_guides(&mut self, show_wrap_guides: bool, cx: &mut Context<Self>) {
22379        self.show_wrap_guides = Some(show_wrap_guides);
22380        cx.notify();
22381    }
22382
22383    pub fn set_show_indent_guides(&mut self, show_indent_guides: bool, cx: &mut Context<Self>) {
22384        self.show_indent_guides = Some(show_indent_guides);
22385        cx.notify();
22386    }
22387
22388    pub fn working_directory(&self, cx: &App) -> Option<PathBuf> {
22389        if let Some(buffer) = self.buffer().read(cx).as_singleton() {
22390            if let Some(file) = buffer.read(cx).file().and_then(|f| f.as_local())
22391                && let Some(dir) = file.abs_path(cx).parent()
22392            {
22393                return Some(dir.to_owned());
22394            }
22395        }
22396
22397        None
22398    }
22399
22400    fn target_file<'a>(&self, cx: &'a App) -> Option<&'a dyn language::LocalFile> {
22401        self.active_excerpt(cx)?
22402            .1
22403            .read(cx)
22404            .file()
22405            .and_then(|f| f.as_local())
22406    }
22407
22408    pub fn target_file_abs_path(&self, cx: &mut Context<Self>) -> Option<PathBuf> {
22409        self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22410            let buffer = buffer.read(cx);
22411            if let Some(project_path) = buffer.project_path(cx) {
22412                let project = self.project()?.read(cx);
22413                project.absolute_path(&project_path, cx)
22414            } else {
22415                buffer
22416                    .file()
22417                    .and_then(|file| file.as_local().map(|file| file.abs_path(cx)))
22418            }
22419        })
22420    }
22421
22422    pub fn reveal_in_finder(
22423        &mut self,
22424        _: &RevealInFileManager,
22425        _window: &mut Window,
22426        cx: &mut Context<Self>,
22427    ) {
22428        if let Some(path) = self.target_file_abs_path(cx) {
22429            if let Some(project) = self.project() {
22430                project.update(cx, |project, cx| project.reveal_path(&path, cx));
22431            } else {
22432                cx.reveal_path(&path);
22433            }
22434        }
22435    }
22436
22437    pub fn copy_path(
22438        &mut self,
22439        _: &zed_actions::workspace::CopyPath,
22440        _window: &mut Window,
22441        cx: &mut Context<Self>,
22442    ) {
22443        if let Some(path) = self.target_file_abs_path(cx)
22444            && let Some(path) = path.to_str()
22445        {
22446            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22447        } else {
22448            cx.propagate();
22449        }
22450    }
22451
22452    pub fn copy_relative_path(
22453        &mut self,
22454        _: &zed_actions::workspace::CopyRelativePath,
22455        _window: &mut Window,
22456        cx: &mut Context<Self>,
22457    ) {
22458        if let Some(path) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22459            let project = self.project()?.read(cx);
22460            let path = buffer.read(cx).file()?.path();
22461            let path = path.display(project.path_style(cx));
22462            Some(path)
22463        }) {
22464            cx.write_to_clipboard(ClipboardItem::new_string(path.to_string()));
22465        } else {
22466            cx.propagate();
22467        }
22468    }
22469
22470    /// Returns the project path for the editor's buffer, if any buffer is
22471    /// opened in the editor.
22472    pub fn project_path(&self, cx: &App) -> Option<ProjectPath> {
22473        if let Some(buffer) = self.buffer.read(cx).as_singleton() {
22474            buffer.read(cx).project_path(cx)
22475        } else {
22476            None
22477        }
22478    }
22479
22480    // Returns true if the editor handled a go-to-line request
22481    pub fn go_to_active_debug_line(&mut self, window: &mut Window, cx: &mut Context<Self>) -> bool {
22482        maybe!({
22483            let breakpoint_store = self.breakpoint_store.as_ref()?;
22484
22485            let (active_stack_frame, debug_line_pane_id) = {
22486                let store = breakpoint_store.read(cx);
22487                let active_stack_frame = store.active_position().cloned();
22488                let debug_line_pane_id = store.active_debug_line_pane_id();
22489                (active_stack_frame, debug_line_pane_id)
22490            };
22491
22492            let Some(active_stack_frame) = active_stack_frame else {
22493                self.clear_row_highlights::<ActiveDebugLine>();
22494                return None;
22495            };
22496
22497            if let Some(debug_line_pane_id) = debug_line_pane_id {
22498                if let Some(workspace) = self
22499                    .workspace
22500                    .as_ref()
22501                    .and_then(|(workspace, _)| workspace.upgrade())
22502                {
22503                    let editor_pane_id = workspace
22504                        .read(cx)
22505                        .pane_for_item_id(cx.entity_id())
22506                        .map(|pane| pane.entity_id());
22507
22508                    if editor_pane_id.is_some_and(|id| id != debug_line_pane_id) {
22509                        self.clear_row_highlights::<ActiveDebugLine>();
22510                        return None;
22511                    }
22512                }
22513            }
22514
22515            let position = active_stack_frame.position;
22516            let buffer_id = position.buffer_id?;
22517            let snapshot = self
22518                .project
22519                .as_ref()?
22520                .read(cx)
22521                .buffer_for_id(buffer_id, cx)?
22522                .read(cx)
22523                .snapshot();
22524
22525            let mut handled = false;
22526            for (id, _, ExcerptRange { context, .. }) in
22527                self.buffer.read(cx).excerpts_for_buffer(buffer_id, cx)
22528            {
22529                if context.start.cmp(&position, &snapshot).is_ge()
22530                    || context.end.cmp(&position, &snapshot).is_lt()
22531                {
22532                    continue;
22533                }
22534                let snapshot = self.buffer.read(cx).snapshot(cx);
22535                let multibuffer_anchor = snapshot.anchor_in_excerpt(id, position)?;
22536
22537                handled = true;
22538                self.clear_row_highlights::<ActiveDebugLine>();
22539
22540                self.go_to_line::<ActiveDebugLine>(
22541                    multibuffer_anchor,
22542                    Some(cx.theme().colors().editor_debugger_active_line_background),
22543                    window,
22544                    cx,
22545                );
22546
22547                cx.notify();
22548            }
22549
22550            handled.then_some(())
22551        })
22552        .is_some()
22553    }
22554
22555    pub fn copy_file_name_without_extension(
22556        &mut self,
22557        _: &CopyFileNameWithoutExtension,
22558        _: &mut Window,
22559        cx: &mut Context<Self>,
22560    ) {
22561        if let Some(file_stem) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22562            let file = buffer.read(cx).file()?;
22563            file.path().file_stem()
22564        }) {
22565            cx.write_to_clipboard(ClipboardItem::new_string(file_stem.to_string()));
22566        }
22567    }
22568
22569    pub fn copy_file_name(&mut self, _: &CopyFileName, _: &mut Window, cx: &mut Context<Self>) {
22570        if let Some(file_name) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22571            let file = buffer.read(cx).file()?;
22572            Some(file.file_name(cx))
22573        }) {
22574            cx.write_to_clipboard(ClipboardItem::new_string(file_name.to_string()));
22575        }
22576    }
22577
22578    pub fn toggle_git_blame(
22579        &mut self,
22580        _: &::git::Blame,
22581        window: &mut Window,
22582        cx: &mut Context<Self>,
22583    ) {
22584        self.show_git_blame_gutter = !self.show_git_blame_gutter;
22585
22586        if self.show_git_blame_gutter && !self.has_blame_entries(cx) {
22587            self.start_git_blame(true, window, cx);
22588        }
22589
22590        cx.notify();
22591    }
22592
22593    pub fn toggle_git_blame_inline(
22594        &mut self,
22595        _: &ToggleGitBlameInline,
22596        window: &mut Window,
22597        cx: &mut Context<Self>,
22598    ) {
22599        self.toggle_git_blame_inline_internal(true, window, cx);
22600        cx.notify();
22601    }
22602
22603    pub fn open_git_blame_commit(
22604        &mut self,
22605        _: &OpenGitBlameCommit,
22606        window: &mut Window,
22607        cx: &mut Context<Self>,
22608    ) {
22609        self.open_git_blame_commit_internal(window, cx);
22610    }
22611
22612    fn open_git_blame_commit_internal(
22613        &mut self,
22614        window: &mut Window,
22615        cx: &mut Context<Self>,
22616    ) -> Option<()> {
22617        let blame = self.blame.as_ref()?;
22618        let snapshot = self.snapshot(window, cx);
22619        let cursor = self
22620            .selections
22621            .newest::<Point>(&snapshot.display_snapshot)
22622            .head();
22623        let (buffer, point, _) = snapshot.buffer_snapshot().point_to_buffer_point(cursor)?;
22624        let (_, blame_entry) = blame
22625            .update(cx, |blame, cx| {
22626                blame
22627                    .blame_for_rows(
22628                        &[RowInfo {
22629                            buffer_id: Some(buffer.remote_id()),
22630                            buffer_row: Some(point.row),
22631                            ..Default::default()
22632                        }],
22633                        cx,
22634                    )
22635                    .next()
22636            })
22637            .flatten()?;
22638        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
22639        let repo = blame.read(cx).repository(cx, buffer.remote_id())?;
22640        let workspace = self.workspace()?.downgrade();
22641        renderer.open_blame_commit(blame_entry, repo, workspace, window, cx);
22642        None
22643    }
22644
22645    pub fn git_blame_inline_enabled(&self) -> bool {
22646        self.git_blame_inline_enabled
22647    }
22648
22649    pub fn toggle_selection_menu(
22650        &mut self,
22651        _: &ToggleSelectionMenu,
22652        _: &mut Window,
22653        cx: &mut Context<Self>,
22654    ) {
22655        self.show_selection_menu = self
22656            .show_selection_menu
22657            .map(|show_selections_menu| !show_selections_menu)
22658            .or_else(|| Some(!EditorSettings::get_global(cx).toolbar.selections_menu));
22659
22660        cx.notify();
22661    }
22662
22663    pub fn selection_menu_enabled(&self, cx: &App) -> bool {
22664        self.show_selection_menu
22665            .unwrap_or_else(|| EditorSettings::get_global(cx).toolbar.selections_menu)
22666    }
22667
22668    fn start_git_blame(
22669        &mut self,
22670        user_triggered: bool,
22671        window: &mut Window,
22672        cx: &mut Context<Self>,
22673    ) {
22674        if let Some(project) = self.project() {
22675            if let Some(buffer) = self.buffer().read(cx).as_singleton()
22676                && buffer.read(cx).file().is_none()
22677            {
22678                return;
22679            }
22680
22681            let focused = self.focus_handle(cx).contains_focused(window, cx);
22682
22683            let project = project.clone();
22684            let blame = cx
22685                .new(|cx| GitBlame::new(self.buffer.clone(), project, user_triggered, focused, cx));
22686            self.blame_subscription =
22687                Some(cx.observe_in(&blame, window, |_, _, _, cx| cx.notify()));
22688            self.blame = Some(blame);
22689        }
22690    }
22691
22692    fn toggle_git_blame_inline_internal(
22693        &mut self,
22694        user_triggered: bool,
22695        window: &mut Window,
22696        cx: &mut Context<Self>,
22697    ) {
22698        if self.git_blame_inline_enabled {
22699            self.git_blame_inline_enabled = false;
22700            self.show_git_blame_inline = false;
22701            self.show_git_blame_inline_delay_task.take();
22702        } else {
22703            self.git_blame_inline_enabled = true;
22704            self.start_git_blame_inline(user_triggered, window, cx);
22705        }
22706
22707        cx.notify();
22708    }
22709
22710    fn start_git_blame_inline(
22711        &mut self,
22712        user_triggered: bool,
22713        window: &mut Window,
22714        cx: &mut Context<Self>,
22715    ) {
22716        self.start_git_blame(user_triggered, window, cx);
22717
22718        if ProjectSettings::get_global(cx)
22719            .git
22720            .inline_blame_delay()
22721            .is_some()
22722        {
22723            self.start_inline_blame_timer(window, cx);
22724        } else {
22725            self.show_git_blame_inline = true
22726        }
22727    }
22728
22729    pub fn blame(&self) -> Option<&Entity<GitBlame>> {
22730        self.blame.as_ref()
22731    }
22732
22733    pub fn show_git_blame_gutter(&self) -> bool {
22734        self.show_git_blame_gutter
22735    }
22736
22737    pub fn render_git_blame_gutter(&self, cx: &App) -> bool {
22738        !self.mode().is_minimap() && self.show_git_blame_gutter && self.has_blame_entries(cx)
22739    }
22740
22741    pub fn render_git_blame_inline(&self, window: &Window, cx: &App) -> bool {
22742        self.show_git_blame_inline
22743            && (self.focus_handle.is_focused(window) || self.inline_blame_popover.is_some())
22744            && !self.newest_selection_head_on_empty_line(cx)
22745            && self.has_blame_entries(cx)
22746    }
22747
22748    fn has_blame_entries(&self, cx: &App) -> bool {
22749        self.blame()
22750            .is_some_and(|blame| blame.read(cx).has_generated_entries())
22751    }
22752
22753    fn newest_selection_head_on_empty_line(&self, cx: &App) -> bool {
22754        let cursor_anchor = self.selections.newest_anchor().head();
22755
22756        let snapshot = self.buffer.read(cx).snapshot(cx);
22757        let buffer_row = MultiBufferRow(cursor_anchor.to_point(&snapshot).row);
22758
22759        snapshot.line_len(buffer_row) == 0
22760    }
22761
22762    fn get_permalink_to_line(&self, cx: &mut Context<Self>) -> Task<Result<url::Url>> {
22763        let buffer_and_selection = maybe!({
22764            let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22765            let selection_range = selection.range();
22766
22767            let multi_buffer = self.buffer().read(cx);
22768            let multi_buffer_snapshot = multi_buffer.snapshot(cx);
22769            let buffer_ranges = multi_buffer_snapshot
22770                .range_to_buffer_ranges(selection_range.start..=selection_range.end);
22771
22772            let (buffer, range, _) = if selection.reversed {
22773                buffer_ranges.first()
22774            } else {
22775                buffer_ranges.last()
22776            }?;
22777
22778            let buffer_range = range.to_point(buffer);
22779
22780            let Some(buffer_diff) = multi_buffer.diff_for(buffer.remote_id()) else {
22781                return Some((
22782                    multi_buffer.buffer(buffer.remote_id()).unwrap(),
22783                    buffer_range.start.row..buffer_range.end.row,
22784                ));
22785            };
22786
22787            let buffer_diff_snapshot = buffer_diff.read(cx).snapshot(cx);
22788            let start =
22789                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.start, buffer);
22790            let end =
22791                buffer_diff_snapshot.buffer_point_to_base_text_point(buffer_range.end, buffer);
22792
22793            Some((
22794                multi_buffer.buffer(buffer.remote_id()).unwrap(),
22795                start.row..end.row,
22796            ))
22797        });
22798
22799        let Some((buffer, selection)) = buffer_and_selection else {
22800            return Task::ready(Err(anyhow!("failed to determine buffer and selection")));
22801        };
22802
22803        let Some(project) = self.project() else {
22804            return Task::ready(Err(anyhow!("editor does not have project")));
22805        };
22806
22807        project.update(cx, |project, cx| {
22808            project.get_permalink_to_line(&buffer, selection, cx)
22809        })
22810    }
22811
22812    pub fn copy_permalink_to_line(
22813        &mut self,
22814        _: &CopyPermalinkToLine,
22815        window: &mut Window,
22816        cx: &mut Context<Self>,
22817    ) {
22818        let permalink_task = self.get_permalink_to_line(cx);
22819        let workspace = self.workspace();
22820
22821        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22822            Ok(permalink) => {
22823                cx.update(|_, cx| {
22824                    cx.write_to_clipboard(ClipboardItem::new_string(permalink.to_string()));
22825                })
22826                .ok();
22827            }
22828            Err(err) => {
22829                let message = format!("Failed to copy permalink: {err}");
22830
22831                anyhow::Result::<()>::Err(err).log_err();
22832
22833                if let Some(workspace) = workspace {
22834                    workspace
22835                        .update_in(cx, |workspace, _, cx| {
22836                            struct CopyPermalinkToLine;
22837
22838                            workspace.show_toast(
22839                                Toast::new(
22840                                    NotificationId::unique::<CopyPermalinkToLine>(),
22841                                    message,
22842                                ),
22843                                cx,
22844                            )
22845                        })
22846                        .ok();
22847                }
22848            }
22849        })
22850        .detach();
22851    }
22852
22853    pub fn copy_file_location(
22854        &mut self,
22855        _: &CopyFileLocation,
22856        _: &mut Window,
22857        cx: &mut Context<Self>,
22858    ) {
22859        let selection = self.selections.newest::<Point>(&self.display_snapshot(cx));
22860
22861        let start_line = selection.start.row + 1;
22862        let end_line = selection.end.row + 1;
22863
22864        let end_line = if selection.end.column == 0 && end_line > start_line {
22865            end_line - 1
22866        } else {
22867            end_line
22868        };
22869
22870        if let Some(file_location) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
22871            let project = self.project()?.read(cx);
22872            let file = buffer.read(cx).file()?;
22873            let path = file.path().display(project.path_style(cx));
22874
22875            let location = if start_line == end_line {
22876                format!("{path}:{start_line}")
22877            } else {
22878                format!("{path}:{start_line}-{end_line}")
22879            };
22880            Some(location)
22881        }) {
22882            cx.write_to_clipboard(ClipboardItem::new_string(file_location));
22883        }
22884    }
22885
22886    pub fn open_permalink_to_line(
22887        &mut self,
22888        _: &OpenPermalinkToLine,
22889        window: &mut Window,
22890        cx: &mut Context<Self>,
22891    ) {
22892        let permalink_task = self.get_permalink_to_line(cx);
22893        let workspace = self.workspace();
22894
22895        cx.spawn_in(window, async move |_, cx| match permalink_task.await {
22896            Ok(permalink) => {
22897                cx.update(|_, cx| {
22898                    cx.open_url(permalink.as_ref());
22899                })
22900                .ok();
22901            }
22902            Err(err) => {
22903                let message = format!("Failed to open permalink: {err}");
22904
22905                anyhow::Result::<()>::Err(err).log_err();
22906
22907                if let Some(workspace) = workspace {
22908                    workspace.update(cx, |workspace, cx| {
22909                        struct OpenPermalinkToLine;
22910
22911                        workspace.show_toast(
22912                            Toast::new(NotificationId::unique::<OpenPermalinkToLine>(), message),
22913                            cx,
22914                        )
22915                    });
22916                }
22917            }
22918        })
22919        .detach();
22920    }
22921
22922    pub fn insert_uuid_v4(
22923        &mut self,
22924        _: &InsertUuidV4,
22925        window: &mut Window,
22926        cx: &mut Context<Self>,
22927    ) {
22928        self.insert_uuid(UuidVersion::V4, window, cx);
22929    }
22930
22931    pub fn insert_uuid_v7(
22932        &mut self,
22933        _: &InsertUuidV7,
22934        window: &mut Window,
22935        cx: &mut Context<Self>,
22936    ) {
22937        self.insert_uuid(UuidVersion::V7, window, cx);
22938    }
22939
22940    fn insert_uuid(&mut self, version: UuidVersion, window: &mut Window, cx: &mut Context<Self>) {
22941        self.hide_mouse_cursor(HideMouseCursorOrigin::TypingAction, cx);
22942        self.transact(window, cx, |this, window, cx| {
22943            let edits = this
22944                .selections
22945                .all::<Point>(&this.display_snapshot(cx))
22946                .into_iter()
22947                .map(|selection| {
22948                    let uuid = match version {
22949                        UuidVersion::V4 => uuid::Uuid::new_v4(),
22950                        UuidVersion::V7 => uuid::Uuid::now_v7(),
22951                    };
22952
22953                    (selection.range(), uuid.to_string())
22954                });
22955            this.edit(edits, cx);
22956            this.refresh_edit_prediction(true, false, window, cx);
22957        });
22958    }
22959
22960    pub fn open_selections_in_multibuffer(
22961        &mut self,
22962        _: &OpenSelectionsInMultibuffer,
22963        window: &mut Window,
22964        cx: &mut Context<Self>,
22965    ) {
22966        let multibuffer = self.buffer.read(cx);
22967
22968        let Some(buffer) = multibuffer.as_singleton() else {
22969            return;
22970        };
22971
22972        let Some(workspace) = self.workspace() else {
22973            return;
22974        };
22975
22976        let title = multibuffer.title(cx).to_string();
22977
22978        let locations = self
22979            .selections
22980            .all_anchors(&self.display_snapshot(cx))
22981            .iter()
22982            .map(|selection| {
22983                (
22984                    buffer.clone(),
22985                    (selection.start.text_anchor..selection.end.text_anchor)
22986                        .to_point(buffer.read(cx)),
22987                )
22988            })
22989            .into_group_map();
22990
22991        cx.spawn_in(window, async move |_, cx| {
22992            workspace.update_in(cx, |workspace, window, cx| {
22993                Self::open_locations_in_multibuffer(
22994                    workspace,
22995                    locations,
22996                    format!("Selections for '{title}'"),
22997                    false,
22998                    false,
22999                    MultibufferSelectionMode::All,
23000                    window,
23001                    cx,
23002                );
23003            })
23004        })
23005        .detach();
23006    }
23007
23008    /// Adds a row highlight for the given range. If a row has multiple highlights, the
23009    /// last highlight added will be used.
23010    ///
23011    /// If the range ends at the beginning of a line, then that line will not be highlighted.
23012    pub fn highlight_rows<T: 'static>(
23013        &mut self,
23014        range: Range<Anchor>,
23015        color: Hsla,
23016        options: RowHighlightOptions,
23017        cx: &mut Context<Self>,
23018    ) {
23019        let snapshot = self.buffer().read(cx).snapshot(cx);
23020        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23021        let ix = row_highlights.binary_search_by(|highlight| {
23022            Ordering::Equal
23023                .then_with(|| highlight.range.start.cmp(&range.start, &snapshot))
23024                .then_with(|| highlight.range.end.cmp(&range.end, &snapshot))
23025        });
23026
23027        if let Err(mut ix) = ix {
23028            let index = post_inc(&mut self.highlight_order);
23029
23030            // If this range intersects with the preceding highlight, then merge it with
23031            // the preceding highlight. Otherwise insert a new highlight.
23032            let mut merged = false;
23033            if ix > 0 {
23034                let prev_highlight = &mut row_highlights[ix - 1];
23035                if prev_highlight
23036                    .range
23037                    .end
23038                    .cmp(&range.start, &snapshot)
23039                    .is_ge()
23040                {
23041                    ix -= 1;
23042                    if prev_highlight.range.end.cmp(&range.end, &snapshot).is_lt() {
23043                        prev_highlight.range.end = range.end;
23044                    }
23045                    merged = true;
23046                    prev_highlight.index = index;
23047                    prev_highlight.color = color;
23048                    prev_highlight.options = options;
23049                }
23050            }
23051
23052            if !merged {
23053                row_highlights.insert(
23054                    ix,
23055                    RowHighlight {
23056                        range,
23057                        index,
23058                        color,
23059                        options,
23060                        type_id: TypeId::of::<T>(),
23061                    },
23062                );
23063            }
23064
23065            // If any of the following highlights intersect with this one, merge them.
23066            while let Some(next_highlight) = row_highlights.get(ix + 1) {
23067                let highlight = &row_highlights[ix];
23068                if next_highlight
23069                    .range
23070                    .start
23071                    .cmp(&highlight.range.end, &snapshot)
23072                    .is_le()
23073                {
23074                    if next_highlight
23075                        .range
23076                        .end
23077                        .cmp(&highlight.range.end, &snapshot)
23078                        .is_gt()
23079                    {
23080                        row_highlights[ix].range.end = next_highlight.range.end;
23081                    }
23082                    row_highlights.remove(ix + 1);
23083                } else {
23084                    break;
23085                }
23086            }
23087        }
23088    }
23089
23090    /// Remove any highlighted row ranges of the given type that intersect the
23091    /// given ranges.
23092    pub fn remove_highlighted_rows<T: 'static>(
23093        &mut self,
23094        ranges_to_remove: Vec<Range<Anchor>>,
23095        cx: &mut Context<Self>,
23096    ) {
23097        let snapshot = self.buffer().read(cx).snapshot(cx);
23098        let row_highlights = self.highlighted_rows.entry(TypeId::of::<T>()).or_default();
23099        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23100        row_highlights.retain(|highlight| {
23101            while let Some(range_to_remove) = ranges_to_remove.peek() {
23102                match range_to_remove.end.cmp(&highlight.range.start, &snapshot) {
23103                    Ordering::Less | Ordering::Equal => {
23104                        ranges_to_remove.next();
23105                    }
23106                    Ordering::Greater => {
23107                        match range_to_remove.start.cmp(&highlight.range.end, &snapshot) {
23108                            Ordering::Less | Ordering::Equal => {
23109                                return false;
23110                            }
23111                            Ordering::Greater => break,
23112                        }
23113                    }
23114                }
23115            }
23116
23117            true
23118        })
23119    }
23120
23121    /// Clear all anchor ranges for a certain highlight context type, so no corresponding rows will be highlighted.
23122    pub fn clear_row_highlights<T: 'static>(&mut self) {
23123        self.highlighted_rows.remove(&TypeId::of::<T>());
23124    }
23125
23126    /// For a highlight given context type, gets all anchor ranges that will be used for row highlighting.
23127    pub fn highlighted_rows<T: 'static>(&self) -> impl '_ + Iterator<Item = (Range<Anchor>, Hsla)> {
23128        self.highlighted_rows
23129            .get(&TypeId::of::<T>())
23130            .map_or(&[] as &[_], |vec| vec.as_slice())
23131            .iter()
23132            .map(|highlight| (highlight.range.clone(), highlight.color))
23133    }
23134
23135    /// Merges all anchor ranges for all context types ever set, picking the last highlight added in case of a row conflict.
23136    /// Returns a map of display rows that are highlighted and their corresponding highlight color.
23137    /// Allows to ignore certain kinds of highlights.
23138    pub fn highlighted_display_rows(
23139        &self,
23140        window: &mut Window,
23141        cx: &mut App,
23142    ) -> BTreeMap<DisplayRow, LineHighlight> {
23143        let snapshot = self.snapshot(window, cx);
23144        let mut used_highlight_orders = HashMap::default();
23145        self.highlighted_rows
23146            .iter()
23147            .flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
23148            .fold(
23149                BTreeMap::<DisplayRow, LineHighlight>::new(),
23150                |mut unique_rows, highlight| {
23151                    let start = highlight.range.start.to_display_point(&snapshot);
23152                    let end = highlight.range.end.to_display_point(&snapshot);
23153                    let start_row = start.row().0;
23154                    let end_row = if !highlight.range.end.text_anchor.is_max() && end.column() == 0
23155                    {
23156                        end.row().0.saturating_sub(1)
23157                    } else {
23158                        end.row().0
23159                    };
23160                    for row in start_row..=end_row {
23161                        let used_index =
23162                            used_highlight_orders.entry(row).or_insert(highlight.index);
23163                        if highlight.index >= *used_index {
23164                            *used_index = highlight.index;
23165                            unique_rows.insert(
23166                                DisplayRow(row),
23167                                LineHighlight {
23168                                    include_gutter: highlight.options.include_gutter,
23169                                    border: None,
23170                                    background: highlight.color.into(),
23171                                    type_id: Some(highlight.type_id),
23172                                },
23173                            );
23174                        }
23175                    }
23176                    unique_rows
23177                },
23178            )
23179    }
23180
23181    pub fn highlighted_display_row_for_autoscroll(
23182        &self,
23183        snapshot: &DisplaySnapshot,
23184    ) -> Option<DisplayRow> {
23185        self.highlighted_rows
23186            .values()
23187            .flat_map(|highlighted_rows| highlighted_rows.iter())
23188            .filter_map(|highlight| {
23189                if highlight.options.autoscroll {
23190                    Some(highlight.range.start.to_display_point(snapshot).row())
23191                } else {
23192                    None
23193                }
23194            })
23195            .min()
23196    }
23197
23198    pub fn set_search_within_ranges(&mut self, ranges: &[Range<Anchor>], cx: &mut Context<Self>) {
23199        self.highlight_background(
23200            HighlightKey::SearchWithinRange,
23201            ranges,
23202            |_, colors| colors.colors().editor_document_highlight_read_background,
23203            cx,
23204        )
23205    }
23206
23207    pub fn set_breadcrumb_header(&mut self, new_header: String) {
23208        self.breadcrumb_header = Some(new_header);
23209    }
23210
23211    pub fn clear_search_within_ranges(&mut self, cx: &mut Context<Self>) {
23212        self.clear_background_highlights(HighlightKey::SearchWithinRange, cx);
23213    }
23214
23215    pub fn highlight_background(
23216        &mut self,
23217        key: HighlightKey,
23218        ranges: &[Range<Anchor>],
23219        color_fetcher: impl Fn(&usize, &Theme) -> Hsla + Send + Sync + 'static,
23220        cx: &mut Context<Self>,
23221    ) {
23222        self.background_highlights
23223            .insert(key, (Arc::new(color_fetcher), Arc::from(ranges)));
23224        self.scrollbar_marker_state.dirty = true;
23225        cx.notify();
23226    }
23227
23228    pub fn clear_background_highlights(
23229        &mut self,
23230        key: HighlightKey,
23231        cx: &mut Context<Self>,
23232    ) -> Option<BackgroundHighlight> {
23233        let text_highlights = self.background_highlights.remove(&key)?;
23234        if !text_highlights.1.is_empty() {
23235            self.scrollbar_marker_state.dirty = true;
23236            cx.notify();
23237        }
23238        Some(text_highlights)
23239    }
23240
23241    pub fn highlight_gutter<T: 'static>(
23242        &mut self,
23243        ranges: impl Into<Vec<Range<Anchor>>>,
23244        color_fetcher: fn(&App) -> Hsla,
23245        cx: &mut Context<Self>,
23246    ) {
23247        self.gutter_highlights
23248            .insert(TypeId::of::<T>(), (color_fetcher, ranges.into()));
23249        cx.notify();
23250    }
23251
23252    pub fn clear_gutter_highlights<T: 'static>(
23253        &mut self,
23254        cx: &mut Context<Self>,
23255    ) -> Option<GutterHighlight> {
23256        cx.notify();
23257        self.gutter_highlights.remove(&TypeId::of::<T>())
23258    }
23259
23260    pub fn insert_gutter_highlight<T: 'static>(
23261        &mut self,
23262        range: Range<Anchor>,
23263        color_fetcher: fn(&App) -> Hsla,
23264        cx: &mut Context<Self>,
23265    ) {
23266        let snapshot = self.buffer().read(cx).snapshot(cx);
23267        let mut highlights = self
23268            .gutter_highlights
23269            .remove(&TypeId::of::<T>())
23270            .map(|(_, highlights)| highlights)
23271            .unwrap_or_default();
23272        let ix = highlights.binary_search_by(|highlight| {
23273            Ordering::Equal
23274                .then_with(|| highlight.start.cmp(&range.start, &snapshot))
23275                .then_with(|| highlight.end.cmp(&range.end, &snapshot))
23276        });
23277        if let Err(ix) = ix {
23278            highlights.insert(ix, range);
23279        }
23280        self.gutter_highlights
23281            .insert(TypeId::of::<T>(), (color_fetcher, highlights));
23282    }
23283
23284    pub fn remove_gutter_highlights<T: 'static>(
23285        &mut self,
23286        ranges_to_remove: Vec<Range<Anchor>>,
23287        cx: &mut Context<Self>,
23288    ) {
23289        let snapshot = self.buffer().read(cx).snapshot(cx);
23290        let Some((color_fetcher, mut gutter_highlights)) =
23291            self.gutter_highlights.remove(&TypeId::of::<T>())
23292        else {
23293            return;
23294        };
23295        let mut ranges_to_remove = ranges_to_remove.iter().peekable();
23296        gutter_highlights.retain(|highlight| {
23297            while let Some(range_to_remove) = ranges_to_remove.peek() {
23298                match range_to_remove.end.cmp(&highlight.start, &snapshot) {
23299                    Ordering::Less | Ordering::Equal => {
23300                        ranges_to_remove.next();
23301                    }
23302                    Ordering::Greater => {
23303                        match range_to_remove.start.cmp(&highlight.end, &snapshot) {
23304                            Ordering::Less | Ordering::Equal => {
23305                                return false;
23306                            }
23307                            Ordering::Greater => break,
23308                        }
23309                    }
23310                }
23311            }
23312
23313            true
23314        });
23315        self.gutter_highlights
23316            .insert(TypeId::of::<T>(), (color_fetcher, gutter_highlights));
23317    }
23318
23319    #[cfg(any(test, feature = "test-support"))]
23320    pub fn all_text_highlights(
23321        &self,
23322        window: &mut Window,
23323        cx: &mut Context<Self>,
23324    ) -> Vec<(HighlightStyle, Vec<Range<DisplayPoint>>)> {
23325        let snapshot = self.snapshot(window, cx);
23326        self.display_map.update(cx, |display_map, _| {
23327            display_map
23328                .all_text_highlights()
23329                .map(|(_, highlight)| {
23330                    let (style, ranges) = highlight.as_ref();
23331                    (
23332                        *style,
23333                        ranges
23334                            .iter()
23335                            .map(|range| range.clone().to_display_points(&snapshot))
23336                            .collect(),
23337                    )
23338                })
23339                .collect()
23340        })
23341    }
23342
23343    #[cfg(any(test, feature = "test-support"))]
23344    pub fn all_text_background_highlights(
23345        &self,
23346        window: &mut Window,
23347        cx: &mut Context<Self>,
23348    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23349        let snapshot = self.snapshot(window, cx);
23350        let buffer = &snapshot.buffer_snapshot();
23351        let start = buffer.anchor_before(MultiBufferOffset(0));
23352        let end = buffer.anchor_after(buffer.len());
23353        self.sorted_background_highlights_in_range(start..end, &snapshot, cx.theme())
23354    }
23355
23356    #[cfg(any(test, feature = "test-support"))]
23357    pub fn sorted_background_highlights_in_range(
23358        &self,
23359        search_range: Range<Anchor>,
23360        display_snapshot: &DisplaySnapshot,
23361        theme: &Theme,
23362    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23363        let mut res = self.background_highlights_in_range(search_range, display_snapshot, theme);
23364        res.sort_by(|a, b| {
23365            a.0.start
23366                .cmp(&b.0.start)
23367                .then_with(|| a.0.end.cmp(&b.0.end))
23368                .then_with(|| a.1.cmp(&b.1))
23369        });
23370        res
23371    }
23372
23373    #[cfg(any(test, feature = "test-support"))]
23374    pub fn search_background_highlights(&mut self, cx: &mut Context<Self>) -> Vec<Range<Point>> {
23375        let snapshot = self.buffer().read(cx).snapshot(cx);
23376
23377        let highlights = self
23378            .background_highlights
23379            .get(&HighlightKey::BufferSearchHighlights);
23380
23381        if let Some((_color, ranges)) = highlights {
23382            ranges
23383                .iter()
23384                .map(|range| range.start.to_point(&snapshot)..range.end.to_point(&snapshot))
23385                .collect_vec()
23386        } else {
23387            vec![]
23388        }
23389    }
23390
23391    fn document_highlights_for_position<'a>(
23392        &'a self,
23393        position: Anchor,
23394        buffer: &'a MultiBufferSnapshot,
23395    ) -> impl 'a + Iterator<Item = &'a Range<Anchor>> {
23396        let read_highlights = self
23397            .background_highlights
23398            .get(&HighlightKey::DocumentHighlightRead)
23399            .map(|h| &h.1);
23400        let write_highlights = self
23401            .background_highlights
23402            .get(&HighlightKey::DocumentHighlightWrite)
23403            .map(|h| &h.1);
23404        let left_position = position.bias_left(buffer);
23405        let right_position = position.bias_right(buffer);
23406        read_highlights
23407            .into_iter()
23408            .chain(write_highlights)
23409            .flat_map(move |ranges| {
23410                let start_ix = match ranges.binary_search_by(|probe| {
23411                    let cmp = probe.end.cmp(&left_position, buffer);
23412                    if cmp.is_ge() {
23413                        Ordering::Greater
23414                    } else {
23415                        Ordering::Less
23416                    }
23417                }) {
23418                    Ok(i) | Err(i) => i,
23419                };
23420
23421                ranges[start_ix..]
23422                    .iter()
23423                    .take_while(move |range| range.start.cmp(&right_position, buffer).is_le())
23424            })
23425    }
23426
23427    pub fn has_background_highlights(&self, key: HighlightKey) -> bool {
23428        self.background_highlights
23429            .get(&key)
23430            .is_some_and(|(_, highlights)| !highlights.is_empty())
23431    }
23432
23433    /// Returns all background highlights for a given range.
23434    ///
23435    /// The order of highlights is not deterministic, do sort the ranges if needed for the logic.
23436    pub fn background_highlights_in_range(
23437        &self,
23438        search_range: Range<Anchor>,
23439        display_snapshot: &DisplaySnapshot,
23440        theme: &Theme,
23441    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23442        let mut results = Vec::new();
23443        for (color_fetcher, ranges) in self.background_highlights.values() {
23444            let start_ix = match ranges.binary_search_by(|probe| {
23445                let cmp = probe
23446                    .end
23447                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23448                if cmp.is_gt() {
23449                    Ordering::Greater
23450                } else {
23451                    Ordering::Less
23452                }
23453            }) {
23454                Ok(i) | Err(i) => i,
23455            };
23456            for (index, range) in ranges[start_ix..].iter().enumerate() {
23457                if range
23458                    .start
23459                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23460                    .is_ge()
23461                {
23462                    break;
23463                }
23464
23465                let color = color_fetcher(&(start_ix + index), theme);
23466                let start = range.start.to_display_point(display_snapshot);
23467                let end = range.end.to_display_point(display_snapshot);
23468                results.push((start..end, color))
23469            }
23470        }
23471        results
23472    }
23473
23474    pub fn gutter_highlights_in_range(
23475        &self,
23476        search_range: Range<Anchor>,
23477        display_snapshot: &DisplaySnapshot,
23478        cx: &App,
23479    ) -> Vec<(Range<DisplayPoint>, Hsla)> {
23480        let mut results = Vec::new();
23481        for (color_fetcher, ranges) in self.gutter_highlights.values() {
23482            let color = color_fetcher(cx);
23483            let start_ix = match ranges.binary_search_by(|probe| {
23484                let cmp = probe
23485                    .end
23486                    .cmp(&search_range.start, &display_snapshot.buffer_snapshot());
23487                if cmp.is_gt() {
23488                    Ordering::Greater
23489                } else {
23490                    Ordering::Less
23491                }
23492            }) {
23493                Ok(i) | Err(i) => i,
23494            };
23495            for range in &ranges[start_ix..] {
23496                if range
23497                    .start
23498                    .cmp(&search_range.end, &display_snapshot.buffer_snapshot())
23499                    .is_ge()
23500                {
23501                    break;
23502                }
23503
23504                let start = range.start.to_display_point(display_snapshot);
23505                let end = range.end.to_display_point(display_snapshot);
23506                results.push((start..end, color))
23507            }
23508        }
23509        results
23510    }
23511
23512    /// Get the text ranges corresponding to the redaction query
23513    pub fn redacted_ranges(
23514        &self,
23515        search_range: Range<Anchor>,
23516        display_snapshot: &DisplaySnapshot,
23517        cx: &App,
23518    ) -> Vec<Range<DisplayPoint>> {
23519        display_snapshot
23520            .buffer_snapshot()
23521            .redacted_ranges(search_range, |file| {
23522                if let Some(file) = file {
23523                    file.is_private()
23524                        && EditorSettings::get(
23525                            Some(SettingsLocation {
23526                                worktree_id: file.worktree_id(cx),
23527                                path: file.path().as_ref(),
23528                            }),
23529                            cx,
23530                        )
23531                        .redact_private_values
23532                } else {
23533                    false
23534                }
23535            })
23536            .map(|range| {
23537                range.start.to_display_point(display_snapshot)
23538                    ..range.end.to_display_point(display_snapshot)
23539            })
23540            .collect()
23541    }
23542
23543    pub fn highlight_text_key(
23544        &mut self,
23545        key: HighlightKey,
23546        ranges: Vec<Range<Anchor>>,
23547        style: HighlightStyle,
23548        merge: bool,
23549        cx: &mut Context<Self>,
23550    ) {
23551        self.display_map.update(cx, |map, cx| {
23552            map.highlight_text(key, ranges, style, merge, cx);
23553        });
23554        cx.notify();
23555    }
23556
23557    pub fn highlight_text(
23558        &mut self,
23559        key: HighlightKey,
23560        ranges: Vec<Range<Anchor>>,
23561        style: HighlightStyle,
23562        cx: &mut Context<Self>,
23563    ) {
23564        self.display_map.update(cx, |map, cx| {
23565            map.highlight_text(key, ranges, style, false, cx)
23566        });
23567        cx.notify();
23568    }
23569
23570    pub fn text_highlights<'a>(
23571        &'a self,
23572        key: HighlightKey,
23573        cx: &'a App,
23574    ) -> Option<(HighlightStyle, &'a [Range<Anchor>])> {
23575        self.display_map.read(cx).text_highlights(key)
23576    }
23577
23578    pub fn clear_highlights(&mut self, key: HighlightKey, cx: &mut Context<Self>) {
23579        let cleared = self
23580            .display_map
23581            .update(cx, |map, _| map.clear_highlights(key));
23582        if cleared {
23583            cx.notify();
23584        }
23585    }
23586
23587    pub fn clear_highlights_with(
23588        &mut self,
23589        f: &mut dyn FnMut(&HighlightKey) -> bool,
23590        cx: &mut Context<Self>,
23591    ) {
23592        let cleared = self
23593            .display_map
23594            .update(cx, |map, _| map.clear_highlights_with(f));
23595        if cleared {
23596            cx.notify();
23597        }
23598    }
23599
23600    pub fn show_local_cursors(&self, window: &mut Window, cx: &mut App) -> bool {
23601        (self.read_only(cx) || self.blink_manager.read(cx).visible())
23602            && self.focus_handle.is_focused(window)
23603    }
23604
23605    pub fn set_show_cursor_when_unfocused(&mut self, is_enabled: bool, cx: &mut Context<Self>) {
23606        self.show_cursor_when_unfocused = is_enabled;
23607        cx.notify();
23608    }
23609
23610    fn on_buffer_changed(&mut self, _: Entity<MultiBuffer>, cx: &mut Context<Self>) {
23611        cx.notify();
23612    }
23613
23614    fn on_debug_session_event(
23615        &mut self,
23616        _session: Entity<Session>,
23617        event: &SessionEvent,
23618        cx: &mut Context<Self>,
23619    ) {
23620        if let SessionEvent::InvalidateInlineValue = event {
23621            self.refresh_inline_values(cx);
23622        }
23623    }
23624
23625    pub fn refresh_inline_values(&mut self, cx: &mut Context<Self>) {
23626        let Some(semantics) = self.semantics_provider.clone() else {
23627            return;
23628        };
23629
23630        if !self.inline_value_cache.enabled {
23631            let inlays = std::mem::take(&mut self.inline_value_cache.inlays);
23632            self.splice_inlays(&inlays, Vec::new(), cx);
23633            return;
23634        }
23635
23636        let current_execution_position = self
23637            .highlighted_rows
23638            .get(&TypeId::of::<ActiveDebugLine>())
23639            .and_then(|lines| lines.last().map(|line| line.range.end));
23640
23641        self.inline_value_cache.refresh_task = cx.spawn(async move |editor, cx| {
23642            let inline_values = editor
23643                .update(cx, |editor, cx| {
23644                    let Some(current_execution_position) = current_execution_position else {
23645                        return Some(Task::ready(Ok(Vec::new())));
23646                    };
23647
23648                    let buffer = editor.buffer.read_with(cx, |buffer, cx| {
23649                        let snapshot = buffer.snapshot(cx);
23650
23651                        let excerpt = snapshot.excerpt_containing(
23652                            current_execution_position..current_execution_position,
23653                        )?;
23654
23655                        editor.buffer.read(cx).buffer(excerpt.buffer_id())
23656                    })?;
23657
23658                    let range =
23659                        buffer.read(cx).anchor_before(0)..current_execution_position.text_anchor;
23660
23661                    semantics.inline_values(buffer, range, cx)
23662                })
23663                .ok()
23664                .flatten()?
23665                .await
23666                .context("refreshing debugger inlays")
23667                .log_err()?;
23668
23669            let mut buffer_inline_values: HashMap<BufferId, Vec<InlayHint>> = HashMap::default();
23670
23671            for (buffer_id, inline_value) in inline_values
23672                .into_iter()
23673                .filter_map(|hint| Some((hint.position.buffer_id?, hint)))
23674            {
23675                buffer_inline_values
23676                    .entry(buffer_id)
23677                    .or_default()
23678                    .push(inline_value);
23679            }
23680
23681            editor
23682                .update(cx, |editor, cx| {
23683                    let snapshot = editor.buffer.read(cx).snapshot(cx);
23684                    let mut new_inlays = Vec::default();
23685
23686                    for (excerpt_id, buffer_snapshot, _) in snapshot.excerpts() {
23687                        let buffer_id = buffer_snapshot.remote_id();
23688                        buffer_inline_values
23689                            .get(&buffer_id)
23690                            .into_iter()
23691                            .flatten()
23692                            .for_each(|hint| {
23693                                let inlay = Inlay::debugger(
23694                                    post_inc(&mut editor.next_inlay_id),
23695                                    Anchor::in_buffer(excerpt_id, hint.position),
23696                                    hint.text(),
23697                                );
23698                                if !inlay.text().chars().contains(&'\n') {
23699                                    new_inlays.push(inlay);
23700                                }
23701                            });
23702                    }
23703
23704                    let mut inlay_ids = new_inlays.iter().map(|inlay| inlay.id).collect();
23705                    std::mem::swap(&mut editor.inline_value_cache.inlays, &mut inlay_ids);
23706
23707                    editor.splice_inlays(&inlay_ids, new_inlays, cx);
23708                })
23709                .ok()?;
23710            Some(())
23711        });
23712    }
23713
23714    fn on_buffer_event(
23715        &mut self,
23716        multibuffer: &Entity<MultiBuffer>,
23717        event: &multi_buffer::Event,
23718        window: &mut Window,
23719        cx: &mut Context<Self>,
23720    ) {
23721        match event {
23722            multi_buffer::Event::Edited {
23723                edited_buffer,
23724                is_local,
23725            } => {
23726                self.scrollbar_marker_state.dirty = true;
23727                self.active_indent_guides_state.dirty = true;
23728                self.refresh_active_diagnostics(cx);
23729                self.refresh_code_actions(window, cx);
23730                self.refresh_single_line_folds(window, cx);
23731                let snapshot = self.snapshot(window, cx);
23732                self.refresh_matching_bracket_highlights(&snapshot, cx);
23733                self.refresh_outline_symbols_at_cursor(cx);
23734                self.refresh_sticky_headers(&snapshot, cx);
23735                if *is_local && self.has_active_edit_prediction() {
23736                    self.update_visible_edit_prediction(window, cx);
23737                }
23738
23739                // Clean up orphaned review comments after edits
23740                self.cleanup_orphaned_review_comments(cx);
23741
23742                if let Some(buffer) = edited_buffer {
23743                    if buffer.read(cx).file().is_none() {
23744                        cx.emit(EditorEvent::TitleChanged);
23745                    }
23746
23747                    if self.project.is_some() {
23748                        let buffer_id = buffer.read(cx).remote_id();
23749                        self.register_buffer(buffer_id, cx);
23750                        self.update_lsp_data(Some(buffer_id), window, cx);
23751                        self.refresh_inlay_hints(
23752                            InlayHintRefreshReason::BufferEdited(buffer_id),
23753                            cx,
23754                        );
23755                    }
23756                }
23757
23758                cx.emit(EditorEvent::BufferEdited);
23759                cx.emit(SearchEvent::MatchesInvalidated);
23760
23761                let Some(project) = &self.project else { return };
23762                let (telemetry, is_via_ssh) = {
23763                    let project = project.read(cx);
23764                    let telemetry = project.client().telemetry().clone();
23765                    let is_via_ssh = project.is_via_remote_server();
23766                    (telemetry, is_via_ssh)
23767                };
23768                telemetry.log_edit_event("editor", is_via_ssh);
23769            }
23770            multi_buffer::Event::ExcerptsAdded {
23771                buffer,
23772                predecessor,
23773                excerpts,
23774            } => {
23775                let buffer_id = buffer.read(cx).remote_id();
23776                if self.buffer.read(cx).diff_for(buffer_id).is_none()
23777                    && let Some(project) = &self.project
23778                {
23779                    update_uncommitted_diff_for_buffer(
23780                        cx.entity(),
23781                        project,
23782                        [buffer.clone()],
23783                        self.buffer.clone(),
23784                        cx,
23785                    )
23786                    .detach();
23787                }
23788                self.semantic_token_state
23789                    .invalidate_buffer(&buffer.read(cx).remote_id());
23790                self.update_lsp_data(Some(buffer_id), window, cx);
23791                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23792                self.refresh_runnables(window, cx);
23793                self.colorize_brackets(false, cx);
23794                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
23795                cx.emit(EditorEvent::ExcerptsAdded {
23796                    buffer: buffer.clone(),
23797                    predecessor: *predecessor,
23798                    excerpts: excerpts.clone(),
23799                });
23800            }
23801            multi_buffer::Event::ExcerptsRemoved {
23802                ids,
23803                removed_buffer_ids,
23804            } => {
23805                if let Some(inlay_hints) = &mut self.inlay_hints {
23806                    inlay_hints.remove_inlay_chunk_data(removed_buffer_ids);
23807                }
23808                self.refresh_inlay_hints(InlayHintRefreshReason::ExcerptsRemoved(ids.clone()), cx);
23809                for buffer_id in removed_buffer_ids {
23810                    self.registered_buffers.remove(buffer_id);
23811                    self.clear_runnables(Some(*buffer_id));
23812                    self.semantic_token_state.invalidate_buffer(buffer_id);
23813                    self.display_map.update(cx, |display_map, cx| {
23814                        display_map.invalidate_semantic_highlights(*buffer_id);
23815                        display_map.clear_lsp_folding_ranges(*buffer_id, cx);
23816                    });
23817                }
23818
23819                self.display_map.update(cx, |display_map, cx| {
23820                    display_map.unfold_buffers(removed_buffer_ids.iter().copied(), cx);
23821                });
23822
23823                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23824                cx.emit(EditorEvent::ExcerptsRemoved {
23825                    ids: ids.clone(),
23826                    removed_buffer_ids: removed_buffer_ids.clone(),
23827                });
23828            }
23829            multi_buffer::Event::ExcerptsEdited {
23830                excerpt_ids,
23831                buffer_ids,
23832            } => {
23833                self.display_map.update(cx, |map, cx| {
23834                    map.unfold_buffers(buffer_ids.iter().copied(), cx)
23835                });
23836                cx.emit(EditorEvent::ExcerptsEdited {
23837                    ids: excerpt_ids.clone(),
23838                });
23839            }
23840            multi_buffer::Event::ExcerptsExpanded { ids } => {
23841                self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
23842                self.refresh_document_highlights(cx);
23843                let snapshot = multibuffer.read(cx).snapshot(cx);
23844                for id in ids {
23845                    self.bracket_fetched_tree_sitter_chunks.remove(id);
23846                    if let Some(buffer) = snapshot.buffer_for_excerpt(*id) {
23847                        self.semantic_token_state
23848                            .invalidate_buffer(&buffer.remote_id());
23849                    }
23850                }
23851                self.colorize_brackets(false, cx);
23852                self.update_lsp_data(None, window, cx);
23853                self.refresh_runnables(window, cx);
23854                cx.emit(EditorEvent::ExcerptsExpanded { ids: ids.clone() })
23855            }
23856            multi_buffer::Event::Reparsed(buffer_id) => {
23857                self.clear_runnables(Some(*buffer_id));
23858                self.refresh_runnables(window, cx);
23859                self.refresh_selected_text_highlights(&self.display_snapshot(cx), true, window, cx);
23860                self.colorize_brackets(true, cx);
23861                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23862
23863                cx.emit(EditorEvent::Reparsed(*buffer_id));
23864            }
23865            multi_buffer::Event::DiffHunksToggled => {
23866                self.refresh_runnables(window, cx);
23867            }
23868            multi_buffer::Event::LanguageChanged(buffer_id, is_fresh_language) => {
23869                if !is_fresh_language {
23870                    self.registered_buffers.remove(&buffer_id);
23871                }
23872                jsx_tag_auto_close::refresh_enabled_in_any_buffer(self, multibuffer, cx);
23873                cx.emit(EditorEvent::Reparsed(*buffer_id));
23874                cx.notify();
23875            }
23876            multi_buffer::Event::DirtyChanged => cx.emit(EditorEvent::DirtyChanged),
23877            multi_buffer::Event::Saved => cx.emit(EditorEvent::Saved),
23878            multi_buffer::Event::FileHandleChanged
23879            | multi_buffer::Event::Reloaded
23880            | multi_buffer::Event::BufferDiffChanged => cx.emit(EditorEvent::TitleChanged),
23881            multi_buffer::Event::DiagnosticsUpdated => {
23882                self.update_diagnostics_state(window, cx);
23883            }
23884            _ => {}
23885        };
23886    }
23887
23888    fn update_diagnostics_state(&mut self, window: &mut Window, cx: &mut Context<'_, Editor>) {
23889        if !self.diagnostics_enabled() {
23890            return;
23891        }
23892        self.refresh_active_diagnostics(cx);
23893        self.refresh_inline_diagnostics(true, window, cx);
23894        self.scrollbar_marker_state.dirty = true;
23895        cx.notify();
23896    }
23897
23898    pub fn start_temporary_diff_override(&mut self) {
23899        self.load_diff_task.take();
23900        self.temporary_diff_override = true;
23901    }
23902
23903    pub fn end_temporary_diff_override(&mut self, cx: &mut Context<Self>) {
23904        self.temporary_diff_override = false;
23905        self.set_render_diff_hunk_controls(Arc::new(render_diff_hunk_controls), cx);
23906        self.buffer.update(cx, |buffer, cx| {
23907            buffer.set_all_diff_hunks_collapsed(cx);
23908        });
23909
23910        if let Some(project) = self.project.clone() {
23911            self.load_diff_task = Some(
23912                update_uncommitted_diff_for_buffer(
23913                    cx.entity(),
23914                    &project,
23915                    self.buffer.read(cx).all_buffers(),
23916                    self.buffer.clone(),
23917                    cx,
23918                )
23919                .shared(),
23920            );
23921        }
23922    }
23923
23924    fn on_display_map_changed(
23925        &mut self,
23926        _: Entity<DisplayMap>,
23927        _: &mut Window,
23928        cx: &mut Context<Self>,
23929    ) {
23930        cx.notify();
23931    }
23932
23933    fn fetch_accent_data(&self, cx: &App) -> Option<AccentData> {
23934        if !self.mode.is_full() {
23935            return None;
23936        }
23937
23938        let theme_settings = theme::ThemeSettings::get_global(cx);
23939        let theme = cx.theme();
23940        let accent_colors = theme.accents().clone();
23941
23942        let accent_overrides = theme_settings
23943            .theme_overrides
23944            .get(theme.name.as_ref())
23945            .map(|theme_style| &theme_style.accents)
23946            .into_iter()
23947            .flatten()
23948            .chain(
23949                theme_settings
23950                    .experimental_theme_overrides
23951                    .as_ref()
23952                    .map(|overrides| &overrides.accents)
23953                    .into_iter()
23954                    .flatten(),
23955            )
23956            .flat_map(|accent| accent.0.clone().map(SharedString::from))
23957            .collect();
23958
23959        Some(AccentData {
23960            colors: accent_colors,
23961            overrides: accent_overrides,
23962        })
23963    }
23964
23965    fn fetch_applicable_language_settings(
23966        &self,
23967        cx: &App,
23968    ) -> HashMap<Option<LanguageName>, LanguageSettings> {
23969        if !self.mode.is_full() {
23970            return HashMap::default();
23971        }
23972
23973        self.buffer().read(cx).all_buffers().into_iter().fold(
23974            HashMap::default(),
23975            |mut acc, buffer| {
23976                let buffer = buffer.read(cx);
23977                let language = buffer.language().map(|language| language.name());
23978                if let hash_map::Entry::Vacant(v) = acc.entry(language.clone()) {
23979                    let file = buffer.file();
23980                    v.insert(language_settings(language, file, cx).into_owned());
23981                }
23982                acc
23983            },
23984        )
23985    }
23986
23987    fn settings_changed(&mut self, window: &mut Window, cx: &mut Context<Self>) {
23988        let new_language_settings = self.fetch_applicable_language_settings(cx);
23989        let language_settings_changed = new_language_settings != self.applicable_language_settings;
23990        self.applicable_language_settings = new_language_settings;
23991
23992        let new_accents = self.fetch_accent_data(cx);
23993        let accents_changed = new_accents != self.accent_data;
23994        self.accent_data = new_accents;
23995
23996        if self.diagnostics_enabled() {
23997            let new_severity = EditorSettings::get_global(cx)
23998                .diagnostics_max_severity
23999                .unwrap_or(DiagnosticSeverity::Hint);
24000            self.set_max_diagnostics_severity(new_severity, cx);
24001        }
24002        self.refresh_runnables(window, cx);
24003        self.update_edit_prediction_settings(cx);
24004        self.refresh_edit_prediction(true, false, window, cx);
24005        self.refresh_inline_values(cx);
24006
24007        let old_cursor_shape = self.cursor_shape;
24008        let old_show_breadcrumbs = self.show_breadcrumbs;
24009
24010        {
24011            let editor_settings = EditorSettings::get_global(cx);
24012            self.scroll_manager.vertical_scroll_margin = editor_settings.vertical_scroll_margin;
24013            self.show_breadcrumbs = editor_settings.toolbar.breadcrumbs;
24014            self.cursor_shape = editor_settings.cursor_shape.unwrap_or_default();
24015            self.hide_mouse_mode = editor_settings.hide_mouse.unwrap_or_default();
24016        }
24017
24018        if old_cursor_shape != self.cursor_shape {
24019            cx.emit(EditorEvent::CursorShapeChanged);
24020        }
24021
24022        if old_show_breadcrumbs != self.show_breadcrumbs {
24023            cx.emit(EditorEvent::BreadcrumbsChanged);
24024        }
24025
24026        let (restore_unsaved_buffers, show_inline_diagnostics, inline_blame_enabled) = {
24027            let project_settings = ProjectSettings::get_global(cx);
24028            (
24029                project_settings.session.restore_unsaved_buffers,
24030                project_settings.diagnostics.inline.enabled,
24031                project_settings.git.inline_blame.enabled,
24032            )
24033        };
24034        self.buffer_serialization = self
24035            .should_serialize_buffer()
24036            .then(|| BufferSerialization::new(restore_unsaved_buffers));
24037
24038        if self.mode.is_full() {
24039            if self.show_inline_diagnostics != show_inline_diagnostics {
24040                self.show_inline_diagnostics = show_inline_diagnostics;
24041                self.refresh_inline_diagnostics(false, window, cx);
24042            }
24043
24044            if self.git_blame_inline_enabled != inline_blame_enabled {
24045                self.toggle_git_blame_inline_internal(false, window, cx);
24046            }
24047
24048            let minimap_settings = EditorSettings::get_global(cx).minimap;
24049            if self.minimap_visibility != MinimapVisibility::Disabled {
24050                if self.minimap_visibility.settings_visibility()
24051                    != minimap_settings.minimap_enabled()
24052                {
24053                    self.set_minimap_visibility(
24054                        MinimapVisibility::for_mode(self.mode(), cx),
24055                        window,
24056                        cx,
24057                    );
24058                } else if let Some(minimap_entity) = self.minimap.as_ref() {
24059                    minimap_entity.update(cx, |minimap_editor, cx| {
24060                        minimap_editor.update_minimap_configuration(minimap_settings, cx)
24061                    })
24062                }
24063            }
24064
24065            if language_settings_changed || accents_changed {
24066                self.colorize_brackets(true, cx);
24067            }
24068
24069            if language_settings_changed {
24070                self.clear_disabled_lsp_folding_ranges(window, cx);
24071                self.refresh_document_symbols(None, cx);
24072            }
24073
24074            if let Some(inlay_splice) = self.colors.as_mut().and_then(|colors| {
24075                colors.render_mode_updated(EditorSettings::get_global(cx).lsp_document_colors)
24076            }) {
24077                if !inlay_splice.is_empty() {
24078                    self.splice_inlays(&inlay_splice.to_remove, inlay_splice.to_insert, cx);
24079                }
24080                self.refresh_document_colors(None, window, cx);
24081            }
24082
24083            self.refresh_inlay_hints(
24084                InlayHintRefreshReason::SettingsChange(inlay_hint_settings(
24085                    self.selections.newest_anchor().head(),
24086                    &self.buffer.read(cx).snapshot(cx),
24087                    cx,
24088                )),
24089                cx,
24090            );
24091
24092            let new_semantic_token_rules = ProjectSettings::get_global(cx)
24093                .global_lsp_settings
24094                .semantic_token_rules
24095                .clone();
24096            let semantic_token_rules_changed = self
24097                .semantic_token_state
24098                .update_rules(new_semantic_token_rules);
24099            if language_settings_changed || semantic_token_rules_changed {
24100                self.invalidate_semantic_tokens(None);
24101                self.refresh_semantic_tokens(None, None, cx);
24102            }
24103        }
24104
24105        cx.notify();
24106    }
24107
24108    fn theme_changed(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24109        if !self.mode.is_full() {
24110            return;
24111        }
24112
24113        let new_accents = self.fetch_accent_data(cx);
24114        if new_accents != self.accent_data {
24115            self.accent_data = new_accents;
24116            self.colorize_brackets(true, cx);
24117        }
24118
24119        self.invalidate_semantic_tokens(None);
24120        self.refresh_semantic_tokens(None, None, cx);
24121    }
24122
24123    pub fn set_searchable(&mut self, searchable: bool) {
24124        self.searchable = searchable;
24125    }
24126
24127    pub fn searchable(&self) -> bool {
24128        self.searchable
24129    }
24130
24131    pub fn open_excerpts_in_split(
24132        &mut self,
24133        _: &OpenExcerptsSplit,
24134        window: &mut Window,
24135        cx: &mut Context<Self>,
24136    ) {
24137        self.open_excerpts_common(None, true, window, cx)
24138    }
24139
24140    pub fn open_excerpts(&mut self, _: &OpenExcerpts, window: &mut Window, cx: &mut Context<Self>) {
24141        self.open_excerpts_common(None, false, window, cx)
24142    }
24143
24144    pub(crate) fn open_excerpts_common(
24145        &mut self,
24146        jump_data: Option<JumpData>,
24147        split: bool,
24148        window: &mut Window,
24149        cx: &mut Context<Self>,
24150    ) {
24151        if self.buffer.read(cx).is_singleton() {
24152            cx.propagate();
24153            return;
24154        }
24155
24156        let mut new_selections_by_buffer = HashMap::default();
24157        match &jump_data {
24158            Some(JumpData::MultiBufferPoint {
24159                excerpt_id,
24160                position,
24161                anchor,
24162                line_offset_from_top,
24163            }) => {
24164                let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
24165                if let Some(buffer) = multi_buffer_snapshot
24166                    .buffer_id_for_excerpt(*excerpt_id)
24167                    .and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
24168                {
24169                    let buffer_snapshot = buffer.read(cx).snapshot();
24170                    let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
24171                        language::ToPoint::to_point(anchor, &buffer_snapshot)
24172                    } else {
24173                        buffer_snapshot.clip_point(*position, Bias::Left)
24174                    };
24175                    let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
24176                    new_selections_by_buffer.insert(
24177                        buffer,
24178                        (
24179                            vec![BufferOffset(jump_to_offset)..BufferOffset(jump_to_offset)],
24180                            Some(*line_offset_from_top),
24181                        ),
24182                    );
24183                }
24184            }
24185            Some(JumpData::MultiBufferRow {
24186                row,
24187                line_offset_from_top,
24188            }) => {
24189                let point = MultiBufferPoint::new(row.0, 0);
24190                if let Some((buffer, buffer_point, _)) =
24191                    self.buffer.read(cx).point_to_buffer_point(point, cx)
24192                {
24193                    let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
24194                    new_selections_by_buffer
24195                        .entry(buffer)
24196                        .or_insert((Vec::new(), Some(*line_offset_from_top)))
24197                        .0
24198                        .push(BufferOffset(buffer_offset)..BufferOffset(buffer_offset))
24199                }
24200            }
24201            None => {
24202                let selections = self
24203                    .selections
24204                    .all::<MultiBufferOffset>(&self.display_snapshot(cx));
24205                let multi_buffer = self.buffer.read(cx);
24206                for selection in selections {
24207                    for (snapshot, range, _, anchor) in multi_buffer
24208                        .snapshot(cx)
24209                        .range_to_buffer_ranges_with_deleted_hunks(selection.range())
24210                    {
24211                        if let Some(anchor) = anchor {
24212                            let Some(buffer_handle) = multi_buffer.buffer_for_anchor(anchor, cx)
24213                            else {
24214                                continue;
24215                            };
24216                            let offset = text::ToOffset::to_offset(
24217                                &anchor.text_anchor,
24218                                &buffer_handle.read(cx).snapshot(),
24219                            );
24220                            let range = BufferOffset(offset)..BufferOffset(offset);
24221                            new_selections_by_buffer
24222                                .entry(buffer_handle)
24223                                .or_insert((Vec::new(), None))
24224                                .0
24225                                .push(range)
24226                        } else {
24227                            let Some(buffer_handle) = multi_buffer.buffer(snapshot.remote_id())
24228                            else {
24229                                continue;
24230                            };
24231                            new_selections_by_buffer
24232                                .entry(buffer_handle)
24233                                .or_insert((Vec::new(), None))
24234                                .0
24235                                .push(range)
24236                        }
24237                    }
24238                }
24239            }
24240        }
24241
24242        if self.delegate_open_excerpts {
24243            let selections_by_buffer: HashMap<_, _> = new_selections_by_buffer
24244                .into_iter()
24245                .map(|(buffer, value)| (buffer.read(cx).remote_id(), value))
24246                .collect();
24247            if !selections_by_buffer.is_empty() {
24248                cx.emit(EditorEvent::OpenExcerptsRequested {
24249                    selections_by_buffer,
24250                    split,
24251                });
24252            }
24253            return;
24254        }
24255
24256        let Some(workspace) = self.workspace() else {
24257            cx.propagate();
24258            return;
24259        };
24260
24261        new_selections_by_buffer
24262            .retain(|buffer, _| buffer.read(cx).file().is_none_or(|file| file.can_open()));
24263
24264        if new_selections_by_buffer.is_empty() {
24265            return;
24266        }
24267
24268        Self::open_buffers_in_workspace(
24269            workspace.downgrade(),
24270            new_selections_by_buffer,
24271            split,
24272            window,
24273            cx,
24274        );
24275    }
24276
24277    pub(crate) fn open_buffers_in_workspace(
24278        workspace: WeakEntity<Workspace>,
24279        new_selections_by_buffer: HashMap<
24280            Entity<language::Buffer>,
24281            (Vec<Range<BufferOffset>>, Option<u32>),
24282        >,
24283        split: bool,
24284        window: &mut Window,
24285        cx: &mut App,
24286    ) {
24287        // We defer the pane interaction because we ourselves are a workspace item
24288        // and activating a new item causes the pane to call a method on us reentrantly,
24289        // which panics if we're on the stack.
24290        window.defer(cx, move |window, cx| {
24291            workspace
24292                .update(cx, |workspace, cx| {
24293                    let pane = if split {
24294                        workspace.adjacent_pane(window, cx)
24295                    } else {
24296                        workspace.active_pane().clone()
24297                    };
24298
24299                    for (buffer, (ranges, scroll_offset)) in new_selections_by_buffer {
24300                        let buffer_read = buffer.read(cx);
24301                        let (has_file, is_project_file) = if let Some(file) = buffer_read.file() {
24302                            (true, project::File::from_dyn(Some(file)).is_some())
24303                        } else {
24304                            (false, false)
24305                        };
24306
24307                        // If project file is none workspace.open_project_item will fail to open the excerpt
24308                        // in a pre existing workspace item if one exists, because Buffer entity_id will be None
24309                        // so we check if there's a tab match in that case first
24310                        let editor = (!has_file || !is_project_file)
24311                            .then(|| {
24312                                // Handle file-less buffers separately: those are not really the project items, so won't have a project path or entity id,
24313                                // so `workspace.open_project_item` will never find them, always opening a new editor.
24314                                // Instead, we try to activate the existing editor in the pane first.
24315                                let (editor, pane_item_index, pane_item_id) =
24316                                    pane.read(cx).items().enumerate().find_map(|(i, item)| {
24317                                        let editor = item.downcast::<Editor>()?;
24318                                        let singleton_buffer =
24319                                            editor.read(cx).buffer().read(cx).as_singleton()?;
24320                                        if singleton_buffer == buffer {
24321                                            Some((editor, i, item.item_id()))
24322                                        } else {
24323                                            None
24324                                        }
24325                                    })?;
24326                                pane.update(cx, |pane, cx| {
24327                                    pane.activate_item(pane_item_index, true, true, window, cx);
24328                                    if !PreviewTabsSettings::get_global(cx)
24329                                        .enable_preview_from_multibuffer
24330                                    {
24331                                        pane.unpreview_item_if_preview(pane_item_id);
24332                                    }
24333                                });
24334                                Some(editor)
24335                            })
24336                            .flatten()
24337                            .unwrap_or_else(|| {
24338                                let keep_old_preview = PreviewTabsSettings::get_global(cx)
24339                                    .enable_keep_preview_on_code_navigation;
24340                                let allow_new_preview = PreviewTabsSettings::get_global(cx)
24341                                    .enable_preview_from_multibuffer;
24342                                workspace.open_project_item::<Self>(
24343                                    pane.clone(),
24344                                    buffer,
24345                                    true,
24346                                    true,
24347                                    keep_old_preview,
24348                                    allow_new_preview,
24349                                    window,
24350                                    cx,
24351                                )
24352                            });
24353
24354                        editor.update(cx, |editor, cx| {
24355                            if has_file && !is_project_file {
24356                                editor.set_read_only(true);
24357                            }
24358                            let autoscroll = match scroll_offset {
24359                                Some(scroll_offset) => {
24360                                    Autoscroll::top_relative(scroll_offset as usize)
24361                                }
24362                                None => Autoscroll::newest(),
24363                            };
24364                            let nav_history = editor.nav_history.take();
24365                            let multibuffer_snapshot = editor.buffer().read(cx).snapshot(cx);
24366                            let Some((excerpt_id, _, buffer_snapshot)) =
24367                                multibuffer_snapshot.as_singleton()
24368                            else {
24369                                return;
24370                            };
24371                            editor.change_selections(
24372                                SelectionEffects::scroll(autoscroll),
24373                                window,
24374                                cx,
24375                                |s| {
24376                                    s.select_ranges(ranges.into_iter().map(|range| {
24377                                        let range = buffer_snapshot.anchor_before(range.start)
24378                                            ..buffer_snapshot.anchor_after(range.end);
24379                                        multibuffer_snapshot
24380                                            .anchor_range_in_excerpt(excerpt_id, range)
24381                                            .unwrap()
24382                                    }));
24383                                },
24384                            );
24385                            editor.nav_history = nav_history;
24386                        });
24387                    }
24388                })
24389                .ok();
24390        });
24391    }
24392
24393    fn marked_text_ranges(&self, cx: &App) -> Option<Vec<Range<MultiBufferOffsetUtf16>>> {
24394        let snapshot = self.buffer.read(cx).read(cx);
24395        let (_, ranges) = self.text_highlights(HighlightKey::InputComposition, cx)?;
24396        Some(
24397            ranges
24398                .iter()
24399                .map(move |range| {
24400                    range.start.to_offset_utf16(&snapshot)..range.end.to_offset_utf16(&snapshot)
24401                })
24402                .collect(),
24403        )
24404    }
24405
24406    fn selection_replacement_ranges(
24407        &self,
24408        range: Range<MultiBufferOffsetUtf16>,
24409        cx: &mut App,
24410    ) -> Vec<Range<MultiBufferOffsetUtf16>> {
24411        let selections = self
24412            .selections
24413            .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24414        let newest_selection = selections
24415            .iter()
24416            .max_by_key(|selection| selection.id)
24417            .unwrap();
24418        let start_delta = range.start.0.0 as isize - newest_selection.start.0.0 as isize;
24419        let end_delta = range.end.0.0 as isize - newest_selection.end.0.0 as isize;
24420        let snapshot = self.buffer.read(cx).read(cx);
24421        selections
24422            .into_iter()
24423            .map(|mut selection| {
24424                selection.start.0.0 =
24425                    (selection.start.0.0 as isize).saturating_add(start_delta) as usize;
24426                selection.end.0.0 = (selection.end.0.0 as isize).saturating_add(end_delta) as usize;
24427                snapshot.clip_offset_utf16(selection.start, Bias::Left)
24428                    ..snapshot.clip_offset_utf16(selection.end, Bias::Right)
24429            })
24430            .collect()
24431    }
24432
24433    fn report_editor_event(
24434        &self,
24435        reported_event: ReportEditorEvent,
24436        file_extension: Option<String>,
24437        cx: &App,
24438    ) {
24439        if cfg!(any(test, feature = "test-support")) {
24440            return;
24441        }
24442
24443        let Some(project) = &self.project else { return };
24444
24445        // If None, we are in a file without an extension
24446        let file = self
24447            .buffer
24448            .read(cx)
24449            .as_singleton()
24450            .and_then(|b| b.read(cx).file());
24451        let file_extension = file_extension.or(file
24452            .as_ref()
24453            .and_then(|file| Path::new(file.file_name(cx)).extension())
24454            .and_then(|e| e.to_str())
24455            .map(|a| a.to_string()));
24456
24457        let vim_mode = vim_mode_setting::VimModeSetting::try_get(cx)
24458            .map(|vim_mode| vim_mode.0)
24459            .unwrap_or(false);
24460
24461        let edit_predictions_provider = all_language_settings(file, cx).edit_predictions.provider;
24462        let copilot_enabled = edit_predictions_provider
24463            == language::language_settings::EditPredictionProvider::Copilot;
24464        let copilot_enabled_for_language = self
24465            .buffer
24466            .read(cx)
24467            .language_settings(cx)
24468            .show_edit_predictions;
24469
24470        let project = project.read(cx);
24471        let event_type = reported_event.event_type();
24472
24473        if let ReportEditorEvent::Saved { auto_saved } = reported_event {
24474            telemetry::event!(
24475                event_type,
24476                type = if auto_saved {"autosave"} else {"manual"},
24477                file_extension,
24478                vim_mode,
24479                copilot_enabled,
24480                copilot_enabled_for_language,
24481                edit_predictions_provider,
24482                is_via_ssh = project.is_via_remote_server(),
24483            );
24484        } else {
24485            telemetry::event!(
24486                event_type,
24487                file_extension,
24488                vim_mode,
24489                copilot_enabled,
24490                copilot_enabled_for_language,
24491                edit_predictions_provider,
24492                is_via_ssh = project.is_via_remote_server(),
24493            );
24494        };
24495    }
24496
24497    /// Copy the highlighted chunks to the clipboard as JSON. The format is an array of lines,
24498    /// with each line being an array of {text, highlight} objects.
24499    fn copy_highlight_json(
24500        &mut self,
24501        _: &CopyHighlightJson,
24502        window: &mut Window,
24503        cx: &mut Context<Self>,
24504    ) {
24505        #[derive(Serialize)]
24506        struct Chunk<'a> {
24507            text: String,
24508            highlight: Option<&'a str>,
24509        }
24510
24511        let snapshot = self.buffer.read(cx).snapshot(cx);
24512        let range = self
24513            .selected_text_range(false, window, cx)
24514            .and_then(|selection| {
24515                if selection.range.is_empty() {
24516                    None
24517                } else {
24518                    Some(
24519                        snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24520                            selection.range.start,
24521                        )))
24522                            ..snapshot.offset_utf16_to_offset(MultiBufferOffsetUtf16(OffsetUtf16(
24523                                selection.range.end,
24524                            ))),
24525                    )
24526                }
24527            })
24528            .unwrap_or_else(|| MultiBufferOffset(0)..snapshot.len());
24529
24530        let chunks = snapshot.chunks(range, true);
24531        let mut lines = Vec::new();
24532        let mut line: VecDeque<Chunk> = VecDeque::new();
24533
24534        let Some(style) = self.style.as_ref() else {
24535            return;
24536        };
24537
24538        for chunk in chunks {
24539            let highlight = chunk
24540                .syntax_highlight_id
24541                .and_then(|id| id.name(&style.syntax));
24542            let mut chunk_lines = chunk.text.split('\n').peekable();
24543            while let Some(text) = chunk_lines.next() {
24544                let mut merged_with_last_token = false;
24545                if let Some(last_token) = line.back_mut()
24546                    && last_token.highlight == highlight
24547                {
24548                    last_token.text.push_str(text);
24549                    merged_with_last_token = true;
24550                }
24551
24552                if !merged_with_last_token {
24553                    line.push_back(Chunk {
24554                        text: text.into(),
24555                        highlight,
24556                    });
24557                }
24558
24559                if chunk_lines.peek().is_some() {
24560                    if line.len() > 1 && line.front().unwrap().text.is_empty() {
24561                        line.pop_front();
24562                    }
24563                    if line.len() > 1 && line.back().unwrap().text.is_empty() {
24564                        line.pop_back();
24565                    }
24566
24567                    lines.push(mem::take(&mut line));
24568                }
24569            }
24570        }
24571
24572        let Some(lines) = serde_json::to_string_pretty(&lines).log_err() else {
24573            return;
24574        };
24575        cx.write_to_clipboard(ClipboardItem::new_string(lines));
24576    }
24577
24578    pub fn open_context_menu(
24579        &mut self,
24580        _: &OpenContextMenu,
24581        window: &mut Window,
24582        cx: &mut Context<Self>,
24583    ) {
24584        self.request_autoscroll(Autoscroll::newest(), cx);
24585        let position = self
24586            .selections
24587            .newest_display(&self.display_snapshot(cx))
24588            .start;
24589        mouse_context_menu::deploy_context_menu(self, None, position, window, cx);
24590    }
24591
24592    pub fn replay_insert_event(
24593        &mut self,
24594        text: &str,
24595        relative_utf16_range: Option<Range<isize>>,
24596        window: &mut Window,
24597        cx: &mut Context<Self>,
24598    ) {
24599        if !self.input_enabled {
24600            cx.emit(EditorEvent::InputIgnored { text: text.into() });
24601            return;
24602        }
24603        if let Some(relative_utf16_range) = relative_utf16_range {
24604            let selections = self
24605                .selections
24606                .all::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
24607            self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24608                let new_ranges = selections.into_iter().map(|range| {
24609                    let start = MultiBufferOffsetUtf16(OffsetUtf16(
24610                        range
24611                            .head()
24612                            .0
24613                            .0
24614                            .saturating_add_signed(relative_utf16_range.start),
24615                    ));
24616                    let end = MultiBufferOffsetUtf16(OffsetUtf16(
24617                        range
24618                            .head()
24619                            .0
24620                            .0
24621                            .saturating_add_signed(relative_utf16_range.end),
24622                    ));
24623                    start..end
24624                });
24625                s.select_ranges(new_ranges);
24626            });
24627        }
24628
24629        self.handle_input(text, window, cx);
24630    }
24631
24632    pub fn is_focused(&self, window: &Window) -> bool {
24633        self.focus_handle.is_focused(window)
24634    }
24635
24636    fn handle_focus(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24637        cx.emit(EditorEvent::Focused);
24638
24639        if let Some(descendant) = self
24640            .last_focused_descendant
24641            .take()
24642            .and_then(|descendant| descendant.upgrade())
24643        {
24644            window.focus(&descendant, cx);
24645        } else {
24646            if let Some(blame) = self.blame.as_ref() {
24647                blame.update(cx, GitBlame::focus)
24648            }
24649
24650            self.blink_manager.update(cx, BlinkManager::enable);
24651            self.show_cursor_names(window, cx);
24652            self.buffer.update(cx, |buffer, cx| {
24653                buffer.finalize_last_transaction(cx);
24654                if self.leader_id.is_none() {
24655                    buffer.set_active_selections(
24656                        &self.selections.disjoint_anchors_arc(),
24657                        self.selections.line_mode(),
24658                        self.cursor_shape,
24659                        cx,
24660                    );
24661                }
24662            });
24663
24664            if let Some(position_map) = self.last_position_map.clone() {
24665                EditorElement::mouse_moved(
24666                    self,
24667                    &MouseMoveEvent {
24668                        position: window.mouse_position(),
24669                        pressed_button: None,
24670                        modifiers: window.modifiers(),
24671                    },
24672                    &position_map,
24673                    None,
24674                    window,
24675                    cx,
24676                );
24677            }
24678        }
24679    }
24680
24681    fn handle_focus_in(&mut self, _: &mut Window, cx: &mut Context<Self>) {
24682        cx.emit(EditorEvent::FocusedIn)
24683    }
24684
24685    fn handle_focus_out(
24686        &mut self,
24687        event: FocusOutEvent,
24688        _window: &mut Window,
24689        cx: &mut Context<Self>,
24690    ) {
24691        if event.blurred != self.focus_handle {
24692            self.last_focused_descendant = Some(event.blurred);
24693        }
24694        self.selection_drag_state = SelectionDragState::None;
24695        self.refresh_inlay_hints(InlayHintRefreshReason::ModifiersChanged(false), cx);
24696    }
24697
24698    pub fn handle_blur(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24699        self.blink_manager.update(cx, BlinkManager::disable);
24700        self.buffer
24701            .update(cx, |buffer, cx| buffer.remove_active_selections(cx));
24702
24703        if let Some(blame) = self.blame.as_ref() {
24704            blame.update(cx, GitBlame::blur)
24705        }
24706        if !self.hover_state.focused(window, cx) {
24707            hide_hover(self, cx);
24708        }
24709        if !self
24710            .context_menu
24711            .borrow()
24712            .as_ref()
24713            .is_some_and(|context_menu| context_menu.focused(window, cx))
24714        {
24715            self.hide_context_menu(window, cx);
24716        }
24717        self.take_active_edit_prediction(cx);
24718        cx.emit(EditorEvent::Blurred);
24719        cx.notify();
24720    }
24721
24722    pub fn observe_pending_input(&mut self, window: &mut Window, cx: &mut Context<Self>) {
24723        let mut pending: String = window
24724            .pending_input_keystrokes()
24725            .into_iter()
24726            .flatten()
24727            .filter_map(|keystroke| keystroke.key_char.clone())
24728            .collect();
24729
24730        if !self.input_enabled || self.read_only || !self.focus_handle.is_focused(window) {
24731            pending = "".to_string();
24732        }
24733
24734        let existing_pending = self
24735            .text_highlights(HighlightKey::PendingInput, cx)
24736            .map(|(_, ranges)| ranges.to_vec());
24737        if existing_pending.is_none() && pending.is_empty() {
24738            return;
24739        }
24740        let transaction =
24741            self.transact(window, cx, |this, window, cx| {
24742                let selections = this
24743                    .selections
24744                    .all::<MultiBufferOffset>(&this.display_snapshot(cx));
24745                let edits = selections
24746                    .iter()
24747                    .map(|selection| (selection.end..selection.end, pending.clone()));
24748                this.edit(edits, cx);
24749                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
24750                    s.select_ranges(selections.into_iter().enumerate().map(|(ix, sel)| {
24751                        sel.start + ix * pending.len()..sel.end + ix * pending.len()
24752                    }));
24753                });
24754                if let Some(existing_ranges) = existing_pending {
24755                    let edits = existing_ranges.iter().map(|range| (range.clone(), ""));
24756                    this.edit(edits, cx);
24757                }
24758            });
24759
24760        let snapshot = self.snapshot(window, cx);
24761        let ranges = self
24762            .selections
24763            .all::<MultiBufferOffset>(&snapshot.display_snapshot)
24764            .into_iter()
24765            .map(|selection| {
24766                snapshot.buffer_snapshot().anchor_after(selection.end)
24767                    ..snapshot
24768                        .buffer_snapshot()
24769                        .anchor_before(selection.end + pending.len())
24770            })
24771            .collect();
24772
24773        if pending.is_empty() {
24774            self.clear_highlights(HighlightKey::PendingInput, cx);
24775        } else {
24776            self.highlight_text(
24777                HighlightKey::PendingInput,
24778                ranges,
24779                HighlightStyle {
24780                    underline: Some(UnderlineStyle {
24781                        thickness: px(1.),
24782                        color: None,
24783                        wavy: false,
24784                    }),
24785                    ..Default::default()
24786                },
24787                cx,
24788            );
24789        }
24790
24791        self.ime_transaction = self.ime_transaction.or(transaction);
24792        if let Some(transaction) = self.ime_transaction {
24793            self.buffer.update(cx, |buffer, cx| {
24794                buffer.group_until_transaction(transaction, cx);
24795            });
24796        }
24797
24798        if self
24799            .text_highlights(HighlightKey::PendingInput, cx)
24800            .is_none()
24801        {
24802            self.ime_transaction.take();
24803        }
24804    }
24805
24806    pub fn register_action_renderer(
24807        &mut self,
24808        listener: impl Fn(&Editor, &mut Window, &mut Context<Editor>) + 'static,
24809    ) -> Subscription {
24810        let id = self.next_editor_action_id.post_inc();
24811        self.editor_actions
24812            .borrow_mut()
24813            .insert(id, Box::new(listener));
24814
24815        let editor_actions = self.editor_actions.clone();
24816        Subscription::new(move || {
24817            editor_actions.borrow_mut().remove(&id);
24818        })
24819    }
24820
24821    pub fn register_action<A: Action>(
24822        &mut self,
24823        listener: impl Fn(&A, &mut Window, &mut App) + 'static,
24824    ) -> Subscription {
24825        let id = self.next_editor_action_id.post_inc();
24826        let listener = Arc::new(listener);
24827        self.editor_actions.borrow_mut().insert(
24828            id,
24829            Box::new(move |_, window, _| {
24830                let listener = listener.clone();
24831                window.on_action(TypeId::of::<A>(), move |action, phase, window, cx| {
24832                    let action = action.downcast_ref().unwrap();
24833                    if phase == DispatchPhase::Bubble {
24834                        listener(action, window, cx)
24835                    }
24836                })
24837            }),
24838        );
24839
24840        let editor_actions = self.editor_actions.clone();
24841        Subscription::new(move || {
24842            editor_actions.borrow_mut().remove(&id);
24843        })
24844    }
24845
24846    pub fn file_header_size(&self) -> u32 {
24847        FILE_HEADER_HEIGHT
24848    }
24849
24850    pub fn restore(
24851        &mut self,
24852        revert_changes: HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
24853        window: &mut Window,
24854        cx: &mut Context<Self>,
24855    ) {
24856        self.buffer().update(cx, |multi_buffer, cx| {
24857            for (buffer_id, changes) in revert_changes {
24858                if let Some(buffer) = multi_buffer.buffer(buffer_id) {
24859                    buffer.update(cx, |buffer, cx| {
24860                        buffer.edit(
24861                            changes
24862                                .into_iter()
24863                                .map(|(range, text)| (range, text.to_string())),
24864                            None,
24865                            cx,
24866                        );
24867                    });
24868                }
24869            }
24870        });
24871        self.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
24872            selections.refresh()
24873        });
24874    }
24875
24876    pub fn to_pixel_point(
24877        &mut self,
24878        source: Anchor,
24879        editor_snapshot: &EditorSnapshot,
24880        window: &mut Window,
24881        cx: &mut App,
24882    ) -> Option<gpui::Point<Pixels>> {
24883        let source_point = source.to_display_point(editor_snapshot);
24884        self.display_to_pixel_point(source_point, editor_snapshot, window, cx)
24885    }
24886
24887    pub fn display_to_pixel_point(
24888        &mut self,
24889        source: DisplayPoint,
24890        editor_snapshot: &EditorSnapshot,
24891        window: &mut Window,
24892        cx: &mut App,
24893    ) -> Option<gpui::Point<Pixels>> {
24894        let line_height = self.style(cx).text.line_height_in_pixels(window.rem_size());
24895        let text_layout_details = self.text_layout_details(window, cx);
24896        let scroll_top = text_layout_details
24897            .scroll_anchor
24898            .scroll_position(editor_snapshot)
24899            .y;
24900
24901        if source.row().as_f64() < scroll_top.floor() {
24902            return None;
24903        }
24904        let source_x = editor_snapshot.x_for_display_point(source, &text_layout_details);
24905        let source_y = line_height * (source.row().as_f64() - scroll_top) as f32;
24906        Some(gpui::Point::new(source_x, source_y))
24907    }
24908
24909    pub fn has_visible_completions_menu(&self) -> bool {
24910        !self.edit_prediction_preview_is_active()
24911            && self.context_menu.borrow().as_ref().is_some_and(|menu| {
24912                menu.visible() && matches!(menu, CodeContextMenu::Completions(_))
24913            })
24914    }
24915
24916    pub fn register_addon<T: Addon>(&mut self, instance: T) {
24917        if self.mode.is_minimap() {
24918            return;
24919        }
24920        self.addons
24921            .insert(std::any::TypeId::of::<T>(), Box::new(instance));
24922    }
24923
24924    pub fn unregister_addon<T: Addon>(&mut self) {
24925        self.addons.remove(&std::any::TypeId::of::<T>());
24926    }
24927
24928    pub fn addon<T: Addon>(&self) -> Option<&T> {
24929        let type_id = std::any::TypeId::of::<T>();
24930        self.addons
24931            .get(&type_id)
24932            .and_then(|item| item.to_any().downcast_ref::<T>())
24933    }
24934
24935    pub fn addon_mut<T: Addon>(&mut self) -> Option<&mut T> {
24936        let type_id = std::any::TypeId::of::<T>();
24937        self.addons
24938            .get_mut(&type_id)
24939            .and_then(|item| item.to_any_mut()?.downcast_mut::<T>())
24940    }
24941
24942    fn character_dimensions(&self, window: &mut Window, cx: &mut App) -> CharacterDimensions {
24943        let text_layout_details = self.text_layout_details(window, cx);
24944        let style = &text_layout_details.editor_style;
24945        let font_id = window.text_system().resolve_font(&style.text.font());
24946        let font_size = style.text.font_size.to_pixels(window.rem_size());
24947        let line_height = style.text.line_height_in_pixels(window.rem_size());
24948        let em_width = window.text_system().em_width(font_id, font_size).unwrap();
24949        let em_advance = window.text_system().em_advance(font_id, font_size).unwrap();
24950
24951        CharacterDimensions {
24952            em_width,
24953            em_advance,
24954            line_height,
24955        }
24956    }
24957
24958    pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
24959        self.load_diff_task.clone()
24960    }
24961
24962    fn read_metadata_from_db(
24963        &mut self,
24964        item_id: u64,
24965        workspace_id: WorkspaceId,
24966        window: &mut Window,
24967        cx: &mut Context<Editor>,
24968    ) {
24969        if self.buffer_kind(cx) == ItemBufferKind::Singleton
24970            && !self.mode.is_minimap()
24971            && WorkspaceSettings::get(None, cx).restore_on_startup
24972                != RestoreOnStartupBehavior::EmptyTab
24973        {
24974            let buffer_snapshot = OnceCell::new();
24975
24976            // Get file path for path-based fold lookup
24977            let file_path: Option<Arc<Path>> =
24978                self.buffer().read(cx).as_singleton().and_then(|buffer| {
24979                    project::File::from_dyn(buffer.read(cx).file())
24980                        .map(|file| Arc::from(file.abs_path(cx)))
24981                });
24982
24983            // Try file_folds (path-based) first, fallback to editor_folds (migration)
24984            let (folds, needs_migration) = if let Some(ref path) = file_path {
24985                if let Some(folds) = DB.get_file_folds(workspace_id, path).log_err()
24986                    && !folds.is_empty()
24987                {
24988                    (Some(folds), false)
24989                } else if let Some(folds) = DB.get_editor_folds(item_id, workspace_id).log_err()
24990                    && !folds.is_empty()
24991                {
24992                    // Found old editor_folds data, will migrate to file_folds
24993                    (Some(folds), true)
24994                } else {
24995                    (None, false)
24996                }
24997            } else {
24998                // No file path, try editor_folds as fallback
24999                let folds = DB.get_editor_folds(item_id, workspace_id).log_err();
25000                (folds.filter(|f| !f.is_empty()), false)
25001            };
25002
25003            if let Some(folds) = folds {
25004                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25005                let snapshot_len = snapshot.len().0;
25006
25007                // Helper: search for fingerprint in buffer, return offset if found
25008                let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25009                    // Ensure we start at a character boundary (defensive)
25010                    let search_start = snapshot
25011                        .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25012                        .0;
25013                    let search_end = snapshot_len.saturating_sub(fingerprint.len());
25014
25015                    let mut byte_offset = search_start;
25016                    for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25017                        if byte_offset > search_end {
25018                            break;
25019                        }
25020                        if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25021                            return Some(byte_offset);
25022                        }
25023                        byte_offset += ch.len_utf8();
25024                    }
25025                    None
25026                };
25027
25028                // Track search position to handle duplicate fingerprints correctly.
25029                // Folds are stored in document order, so we advance after each match.
25030                let mut search_start = 0usize;
25031
25032                // Collect db_folds for migration (only folds with valid fingerprints)
25033                let mut db_folds_for_migration: Vec<(usize, usize, String, String)> = Vec::new();
25034
25035                let valid_folds: Vec<_> = folds
25036                    .into_iter()
25037                    .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25038                        // Skip folds without fingerprints (old data before migration)
25039                        let sfp = start_fp?;
25040                        let efp = end_fp?;
25041                        let efp_len = efp.len();
25042
25043                        // Fast path: check if fingerprints match at stored offsets
25044                        // Note: end_fp is content BEFORE fold end, so check at (stored_end - efp_len)
25045                        let start_matches = stored_start < snapshot_len
25046                            && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25047                        let efp_check_pos = stored_end.saturating_sub(efp_len);
25048                        let end_matches = efp_check_pos >= stored_start
25049                            && stored_end <= snapshot_len
25050                            && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25051
25052                        let (new_start, new_end) = if start_matches && end_matches {
25053                            // Offsets unchanged, use stored values
25054                            (stored_start, stored_end)
25055                        } else if sfp == efp {
25056                            // Short fold: identical fingerprints can only match once per search
25057                            // Use stored fold length to compute new_end
25058                            let new_start = find_fingerprint(&sfp, search_start)?;
25059                            let fold_len = stored_end - stored_start;
25060                            let new_end = new_start + fold_len;
25061                            (new_start, new_end)
25062                        } else {
25063                            // Slow path: search for fingerprints in buffer
25064                            let new_start = find_fingerprint(&sfp, search_start)?;
25065                            // Search for end_fp after start, then add efp_len to get actual fold end
25066                            let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25067                            let new_end = efp_pos + efp_len;
25068                            (new_start, new_end)
25069                        };
25070
25071                        // Advance search position for next fold
25072                        search_start = new_end;
25073
25074                        // Validate fold makes sense (end must be after start)
25075                        if new_end <= new_start {
25076                            return None;
25077                        }
25078
25079                        // Collect for migration if needed
25080                        if needs_migration {
25081                            db_folds_for_migration.push((new_start, new_end, sfp, efp));
25082                        }
25083
25084                        Some(
25085                            snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25086                                ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25087                        )
25088                    })
25089                    .collect();
25090
25091                if !valid_folds.is_empty() {
25092                    self.fold_ranges(valid_folds, false, window, cx);
25093
25094                    // Migrate from editor_folds to file_folds if we loaded from old table
25095                    if needs_migration {
25096                        if let Some(ref path) = file_path {
25097                            let path = path.clone();
25098                            cx.spawn(async move |_, _| {
25099                                DB.save_file_folds(workspace_id, path, db_folds_for_migration)
25100                                    .await
25101                                    .log_err();
25102                            })
25103                            .detach();
25104                        }
25105                    }
25106                }
25107            }
25108
25109            if let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err()
25110                && !selections.is_empty()
25111            {
25112                let snapshot = buffer_snapshot.get_or_init(|| self.buffer.read(cx).snapshot(cx));
25113                // skip adding the initial selection to selection history
25114                self.selection_history.mode = SelectionHistoryMode::Skipping;
25115                self.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
25116                    s.select_ranges(selections.into_iter().map(|(start, end)| {
25117                        snapshot.clip_offset(MultiBufferOffset(start), Bias::Left)
25118                            ..snapshot.clip_offset(MultiBufferOffset(end), Bias::Right)
25119                    }));
25120                });
25121                self.selection_history.mode = SelectionHistoryMode::Normal;
25122            };
25123        }
25124
25125        self.read_scroll_position_from_db(item_id, workspace_id, window, cx);
25126    }
25127
25128    /// Load folds from the file_folds database table by file path.
25129    /// Used when manually opening a file that was previously closed.
25130    fn load_folds_from_db(
25131        &mut self,
25132        workspace_id: WorkspaceId,
25133        file_path: PathBuf,
25134        window: &mut Window,
25135        cx: &mut Context<Editor>,
25136    ) {
25137        if self.mode.is_minimap()
25138            || WorkspaceSettings::get(None, cx).restore_on_startup
25139                == RestoreOnStartupBehavior::EmptyTab
25140        {
25141            return;
25142        }
25143
25144        let Some(folds) = DB.get_file_folds(workspace_id, &file_path).log_err() else {
25145            return;
25146        };
25147        if folds.is_empty() {
25148            return;
25149        }
25150
25151        let snapshot = self.buffer.read(cx).snapshot(cx);
25152        let snapshot_len = snapshot.len().0;
25153
25154        // Helper: search for fingerprint in buffer, return offset if found
25155        let find_fingerprint = |fingerprint: &str, search_start: usize| -> Option<usize> {
25156            let search_start = snapshot
25157                .clip_offset(MultiBufferOffset(search_start), Bias::Left)
25158                .0;
25159            let search_end = snapshot_len.saturating_sub(fingerprint.len());
25160
25161            let mut byte_offset = search_start;
25162            for ch in snapshot.chars_at(MultiBufferOffset(search_start)) {
25163                if byte_offset > search_end {
25164                    break;
25165                }
25166                if snapshot.contains_str_at(MultiBufferOffset(byte_offset), fingerprint) {
25167                    return Some(byte_offset);
25168                }
25169                byte_offset += ch.len_utf8();
25170            }
25171            None
25172        };
25173
25174        let mut search_start = 0usize;
25175
25176        let valid_folds: Vec<_> = folds
25177            .into_iter()
25178            .filter_map(|(stored_start, stored_end, start_fp, end_fp)| {
25179                let sfp = start_fp?;
25180                let efp = end_fp?;
25181                let efp_len = efp.len();
25182
25183                let start_matches = stored_start < snapshot_len
25184                    && snapshot.contains_str_at(MultiBufferOffset(stored_start), &sfp);
25185                let efp_check_pos = stored_end.saturating_sub(efp_len);
25186                let end_matches = efp_check_pos >= stored_start
25187                    && stored_end <= snapshot_len
25188                    && snapshot.contains_str_at(MultiBufferOffset(efp_check_pos), &efp);
25189
25190                let (new_start, new_end) = if start_matches && end_matches {
25191                    (stored_start, stored_end)
25192                } else if sfp == efp {
25193                    let new_start = find_fingerprint(&sfp, search_start)?;
25194                    let fold_len = stored_end - stored_start;
25195                    let new_end = new_start + fold_len;
25196                    (new_start, new_end)
25197                } else {
25198                    let new_start = find_fingerprint(&sfp, search_start)?;
25199                    let efp_pos = find_fingerprint(&efp, new_start + sfp.len())?;
25200                    let new_end = efp_pos + efp_len;
25201                    (new_start, new_end)
25202                };
25203
25204                search_start = new_end;
25205
25206                if new_end <= new_start {
25207                    return None;
25208                }
25209
25210                Some(
25211                    snapshot.clip_offset(MultiBufferOffset(new_start), Bias::Left)
25212                        ..snapshot.clip_offset(MultiBufferOffset(new_end), Bias::Right),
25213                )
25214            })
25215            .collect();
25216
25217        if !valid_folds.is_empty() {
25218            self.fold_ranges(valid_folds, false, window, cx);
25219        }
25220    }
25221
25222    fn lsp_data_enabled(&self) -> bool {
25223        self.enable_lsp_data && self.mode().is_full()
25224    }
25225
25226    fn update_lsp_data(
25227        &mut self,
25228        for_buffer: Option<BufferId>,
25229        window: &mut Window,
25230        cx: &mut Context<'_, Self>,
25231    ) {
25232        if !self.lsp_data_enabled() {
25233            return;
25234        }
25235
25236        if let Some(buffer_id) = for_buffer {
25237            self.pull_diagnostics(buffer_id, window, cx);
25238        }
25239        self.refresh_semantic_tokens(for_buffer, None, cx);
25240        self.refresh_document_colors(for_buffer, window, cx);
25241        self.refresh_folding_ranges(for_buffer, window, cx);
25242        self.refresh_document_symbols(for_buffer, cx);
25243    }
25244
25245    fn register_visible_buffers(&mut self, cx: &mut Context<Self>) {
25246        if !self.lsp_data_enabled() {
25247            return;
25248        }
25249        for (_, (visible_buffer, _, _)) in self.visible_excerpts(true, cx) {
25250            self.register_buffer(visible_buffer.read(cx).remote_id(), cx);
25251        }
25252    }
25253
25254    fn register_buffer(&mut self, buffer_id: BufferId, cx: &mut Context<Self>) {
25255        if !self.lsp_data_enabled() {
25256            return;
25257        }
25258
25259        if !self.registered_buffers.contains_key(&buffer_id)
25260            && let Some(project) = self.project.as_ref()
25261        {
25262            if let Some(buffer) = self.buffer.read(cx).buffer(buffer_id) {
25263                project.update(cx, |project, cx| {
25264                    self.registered_buffers.insert(
25265                        buffer_id,
25266                        project.register_buffer_with_language_servers(&buffer, cx),
25267                    );
25268                });
25269            } else {
25270                self.registered_buffers.remove(&buffer_id);
25271            }
25272        }
25273    }
25274
25275    fn create_style(&self, cx: &App) -> EditorStyle {
25276        let settings = ThemeSettings::get_global(cx);
25277
25278        let mut text_style = match self.mode {
25279            EditorMode::SingleLine | EditorMode::AutoHeight { .. } => TextStyle {
25280                color: cx.theme().colors().editor_foreground,
25281                font_family: settings.ui_font.family.clone(),
25282                font_features: settings.ui_font.features.clone(),
25283                font_fallbacks: settings.ui_font.fallbacks.clone(),
25284                font_size: rems(0.875).into(),
25285                font_weight: settings.ui_font.weight,
25286                line_height: relative(settings.buffer_line_height.value()),
25287                ..Default::default()
25288            },
25289            EditorMode::Full { .. } | EditorMode::Minimap { .. } => TextStyle {
25290                color: cx.theme().colors().editor_foreground,
25291                font_family: settings.buffer_font.family.clone(),
25292                font_features: settings.buffer_font.features.clone(),
25293                font_fallbacks: settings.buffer_font.fallbacks.clone(),
25294                font_size: settings.buffer_font_size(cx).into(),
25295                font_weight: settings.buffer_font.weight,
25296                line_height: relative(settings.buffer_line_height.value()),
25297                ..Default::default()
25298            },
25299        };
25300        if let Some(text_style_refinement) = &self.text_style_refinement {
25301            text_style.refine(text_style_refinement)
25302        }
25303
25304        let background = match self.mode {
25305            EditorMode::SingleLine => cx.theme().system().transparent,
25306            EditorMode::AutoHeight { .. } => cx.theme().system().transparent,
25307            EditorMode::Full { .. } => cx.theme().colors().editor_background,
25308            EditorMode::Minimap { .. } => cx.theme().colors().editor_background.opacity(0.7),
25309        };
25310
25311        EditorStyle {
25312            background,
25313            border: cx.theme().colors().border,
25314            local_player: cx.theme().players().local(),
25315            text: text_style,
25316            scrollbar_width: EditorElement::SCROLLBAR_WIDTH,
25317            syntax: cx.theme().syntax().clone(),
25318            status: cx.theme().status().clone(),
25319            inlay_hints_style: make_inlay_hints_style(cx),
25320            edit_prediction_styles: make_suggestion_styles(cx),
25321            unnecessary_code_fade: settings.unnecessary_code_fade,
25322            show_underlines: self.diagnostics_enabled(),
25323        }
25324    }
25325
25326    fn breadcrumbs_inner(&self, cx: &App) -> Option<Vec<HighlightedText>> {
25327        let multibuffer = self.buffer().read(cx);
25328        let is_singleton = multibuffer.is_singleton();
25329        let (buffer_id, symbols) = self.outline_symbols_at_cursor.as_ref()?;
25330        let buffer = multibuffer.buffer(*buffer_id)?;
25331
25332        let buffer = buffer.read(cx);
25333        // In a multi-buffer layout, we don't want to include the filename in the breadcrumbs
25334        let mut breadcrumbs = if is_singleton {
25335            let text = self.breadcrumb_header.clone().unwrap_or_else(|| {
25336                buffer
25337                    .snapshot()
25338                    .resolve_file_path(
25339                        self.project
25340                            .as_ref()
25341                            .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
25342                            .unwrap_or_default(),
25343                        cx,
25344                    )
25345                    .unwrap_or_else(|| {
25346                        if multibuffer.is_singleton() {
25347                            multibuffer.title(cx).to_string()
25348                        } else {
25349                            "untitled".to_string()
25350                        }
25351                    })
25352            });
25353            vec![HighlightedText {
25354                text: text.into(),
25355                highlights: vec![],
25356            }]
25357        } else {
25358            vec![]
25359        };
25360
25361        breadcrumbs.extend(symbols.iter().map(|symbol| HighlightedText {
25362            text: symbol.text.clone().into(),
25363            highlights: symbol.highlight_ranges.clone(),
25364        }));
25365        Some(breadcrumbs)
25366    }
25367
25368    fn disable_lsp_data(&mut self) {
25369        self.enable_lsp_data = false;
25370    }
25371
25372    fn disable_runnables(&mut self) {
25373        self.enable_runnables = false;
25374    }
25375
25376    fn update_data_on_scroll(&mut self, window: &mut Window, cx: &mut Context<'_, Self>) {
25377        self.register_visible_buffers(cx);
25378        self.colorize_brackets(false, cx);
25379        self.refresh_inlay_hints(InlayHintRefreshReason::NewLinesShown, cx);
25380        if !self.buffer().read(cx).is_singleton() {
25381            self.update_lsp_data(None, window, cx);
25382            self.refresh_runnables(window, cx);
25383        }
25384    }
25385}
25386
25387fn edit_for_markdown_paste<'a>(
25388    buffer: &MultiBufferSnapshot,
25389    range: Range<MultiBufferOffset>,
25390    to_insert: &'a str,
25391    url: Option<url::Url>,
25392) -> (Range<MultiBufferOffset>, Cow<'a, str>) {
25393    if url.is_none() {
25394        return (range, Cow::Borrowed(to_insert));
25395    };
25396
25397    let old_text = buffer.text_for_range(range.clone()).collect::<String>();
25398
25399    let new_text = if range.is_empty() || url::Url::parse(&old_text).is_ok() {
25400        Cow::Borrowed(to_insert)
25401    } else {
25402        Cow::Owned(format!("[{old_text}]({to_insert})"))
25403    };
25404    (range, new_text)
25405}
25406
25407fn process_completion_for_edit(
25408    completion: &Completion,
25409    intent: CompletionIntent,
25410    buffer: &Entity<Buffer>,
25411    cursor_position: &text::Anchor,
25412    cx: &mut Context<Editor>,
25413) -> CompletionEdit {
25414    let buffer = buffer.read(cx);
25415    let buffer_snapshot = buffer.snapshot();
25416    let (snippet, new_text) = if completion.is_snippet() {
25417        let mut snippet_source = completion.new_text.clone();
25418        // Workaround for typescript language server issues so that methods don't expand within
25419        // strings and functions with type expressions. The previous point is used because the query
25420        // for function identifier doesn't match when the cursor is immediately after. See PR #30312
25421        let previous_point = text::ToPoint::to_point(cursor_position, &buffer_snapshot);
25422        let previous_point = if previous_point.column > 0 {
25423            cursor_position.to_previous_offset(&buffer_snapshot)
25424        } else {
25425            cursor_position.to_offset(&buffer_snapshot)
25426        };
25427        if let Some(scope) = buffer_snapshot.language_scope_at(previous_point)
25428            && scope.prefers_label_for_snippet_in_completion()
25429            && let Some(label) = completion.label()
25430            && matches!(
25431                completion.kind(),
25432                Some(CompletionItemKind::FUNCTION) | Some(CompletionItemKind::METHOD)
25433            )
25434        {
25435            snippet_source = label;
25436        }
25437        match Snippet::parse(&snippet_source).log_err() {
25438            Some(parsed_snippet) => (Some(parsed_snippet.clone()), parsed_snippet.text),
25439            None => (None, completion.new_text.clone()),
25440        }
25441    } else {
25442        (None, completion.new_text.clone())
25443    };
25444
25445    let mut range_to_replace = {
25446        let replace_range = &completion.replace_range;
25447        if let CompletionSource::Lsp {
25448            insert_range: Some(insert_range),
25449            ..
25450        } = &completion.source
25451        {
25452            debug_assert_eq!(
25453                insert_range.start, replace_range.start,
25454                "insert_range and replace_range should start at the same position"
25455            );
25456            debug_assert!(
25457                insert_range
25458                    .start
25459                    .cmp(cursor_position, &buffer_snapshot)
25460                    .is_le(),
25461                "insert_range should start before or at cursor position"
25462            );
25463            debug_assert!(
25464                replace_range
25465                    .start
25466                    .cmp(cursor_position, &buffer_snapshot)
25467                    .is_le(),
25468                "replace_range should start before or at cursor position"
25469            );
25470
25471            let should_replace = match intent {
25472                CompletionIntent::CompleteWithInsert => false,
25473                CompletionIntent::CompleteWithReplace => true,
25474                CompletionIntent::Complete | CompletionIntent::Compose => {
25475                    let insert_mode =
25476                        language_settings(buffer.language().map(|l| l.name()), buffer.file(), cx)
25477                            .completions
25478                            .lsp_insert_mode;
25479                    match insert_mode {
25480                        LspInsertMode::Insert => false,
25481                        LspInsertMode::Replace => true,
25482                        LspInsertMode::ReplaceSubsequence => {
25483                            let mut text_to_replace = buffer.chars_for_range(
25484                                buffer.anchor_before(replace_range.start)
25485                                    ..buffer.anchor_after(replace_range.end),
25486                            );
25487                            let mut current_needle = text_to_replace.next();
25488                            for haystack_ch in completion.label.text.chars() {
25489                                if let Some(needle_ch) = current_needle
25490                                    && haystack_ch.eq_ignore_ascii_case(&needle_ch)
25491                                {
25492                                    current_needle = text_to_replace.next();
25493                                }
25494                            }
25495                            current_needle.is_none()
25496                        }
25497                        LspInsertMode::ReplaceSuffix => {
25498                            if replace_range
25499                                .end
25500                                .cmp(cursor_position, &buffer_snapshot)
25501                                .is_gt()
25502                            {
25503                                let range_after_cursor = *cursor_position..replace_range.end;
25504                                let text_after_cursor = buffer
25505                                    .text_for_range(
25506                                        buffer.anchor_before(range_after_cursor.start)
25507                                            ..buffer.anchor_after(range_after_cursor.end),
25508                                    )
25509                                    .collect::<String>()
25510                                    .to_ascii_lowercase();
25511                                completion
25512                                    .label
25513                                    .text
25514                                    .to_ascii_lowercase()
25515                                    .ends_with(&text_after_cursor)
25516                            } else {
25517                                true
25518                            }
25519                        }
25520                    }
25521                }
25522            };
25523
25524            if should_replace {
25525                replace_range.clone()
25526            } else {
25527                insert_range.clone()
25528            }
25529        } else {
25530            replace_range.clone()
25531        }
25532    };
25533
25534    if range_to_replace
25535        .end
25536        .cmp(cursor_position, &buffer_snapshot)
25537        .is_lt()
25538    {
25539        range_to_replace.end = *cursor_position;
25540    }
25541
25542    let replace_range = range_to_replace.to_offset(buffer);
25543    CompletionEdit {
25544        new_text,
25545        replace_range: BufferOffset(replace_range.start)..BufferOffset(replace_range.end),
25546        snippet,
25547    }
25548}
25549
25550struct CompletionEdit {
25551    new_text: String,
25552    replace_range: Range<BufferOffset>,
25553    snippet: Option<Snippet>,
25554}
25555
25556fn comment_delimiter_for_newline(
25557    start_point: &Point,
25558    buffer: &MultiBufferSnapshot,
25559    language: &LanguageScope,
25560) -> Option<Arc<str>> {
25561    let delimiters = language.line_comment_prefixes();
25562    let max_len_of_delimiter = delimiters.iter().map(|delimiter| delimiter.len()).max()?;
25563    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25564
25565    let num_of_whitespaces = snapshot
25566        .chars_for_range(range.clone())
25567        .take_while(|c| c.is_whitespace())
25568        .count();
25569    let comment_candidate = snapshot
25570        .chars_for_range(range.clone())
25571        .skip(num_of_whitespaces)
25572        .take(max_len_of_delimiter + 2)
25573        .collect::<String>();
25574    let (delimiter, trimmed_len, is_repl) = delimiters
25575        .iter()
25576        .filter_map(|delimiter| {
25577            let prefix = delimiter.trim_end();
25578            if comment_candidate.starts_with(prefix) {
25579                let is_repl = if let Some(stripped_comment) = comment_candidate.strip_prefix(prefix)
25580                {
25581                    stripped_comment.starts_with(" %%")
25582                } else {
25583                    false
25584                };
25585                Some((delimiter, prefix.len(), is_repl))
25586            } else {
25587                None
25588            }
25589        })
25590        .max_by_key(|(_, len, _)| *len)?;
25591
25592    if let Some(BlockCommentConfig {
25593        start: block_start, ..
25594    }) = language.block_comment()
25595    {
25596        let block_start_trimmed = block_start.trim_end();
25597        if block_start_trimmed.starts_with(delimiter.trim_end()) {
25598            let line_content = snapshot
25599                .chars_for_range(range.clone())
25600                .skip(num_of_whitespaces)
25601                .take(block_start_trimmed.len())
25602                .collect::<String>();
25603
25604            if line_content.starts_with(block_start_trimmed) {
25605                return None;
25606            }
25607        }
25608    }
25609
25610    let cursor_is_placed_after_comment_marker =
25611        num_of_whitespaces + trimmed_len <= start_point.column as usize;
25612    if cursor_is_placed_after_comment_marker {
25613        if !is_repl {
25614            return Some(delimiter.clone());
25615        }
25616
25617        let line_content_after_cursor: String = snapshot
25618            .chars_for_range(range)
25619            .skip(start_point.column as usize)
25620            .collect();
25621
25622        if line_content_after_cursor.trim().is_empty() {
25623            return None;
25624        } else {
25625            return Some(delimiter.clone());
25626        }
25627    } else {
25628        None
25629    }
25630}
25631
25632fn documentation_delimiter_for_newline(
25633    start_point: &Point,
25634    buffer: &MultiBufferSnapshot,
25635    language: &LanguageScope,
25636    newline_config: &mut NewlineConfig,
25637) -> Option<Arc<str>> {
25638    let BlockCommentConfig {
25639        start: start_tag,
25640        end: end_tag,
25641        prefix: delimiter,
25642        tab_size: len,
25643    } = language.documentation_comment()?;
25644    let is_within_block_comment = buffer
25645        .language_scope_at(*start_point)
25646        .is_some_and(|scope| scope.override_name() == Some("comment"));
25647    if !is_within_block_comment {
25648        return None;
25649    }
25650
25651    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25652
25653    let num_of_whitespaces = snapshot
25654        .chars_for_range(range.clone())
25655        .take_while(|c| c.is_whitespace())
25656        .count();
25657
25658    // 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.
25659    let column = start_point.column;
25660    let cursor_is_after_start_tag = {
25661        let start_tag_len = start_tag.len();
25662        let start_tag_line = snapshot
25663            .chars_for_range(range.clone())
25664            .skip(num_of_whitespaces)
25665            .take(start_tag_len)
25666            .collect::<String>();
25667        if start_tag_line.starts_with(start_tag.as_ref()) {
25668            num_of_whitespaces + start_tag_len <= column as usize
25669        } else {
25670            false
25671        }
25672    };
25673
25674    let cursor_is_after_delimiter = {
25675        let delimiter_trim = delimiter.trim_end();
25676        let delimiter_line = snapshot
25677            .chars_for_range(range.clone())
25678            .skip(num_of_whitespaces)
25679            .take(delimiter_trim.len())
25680            .collect::<String>();
25681        if delimiter_line.starts_with(delimiter_trim) {
25682            num_of_whitespaces + delimiter_trim.len() <= column as usize
25683        } else {
25684            false
25685        }
25686    };
25687
25688    let mut needs_extra_line = false;
25689    let mut extra_line_additional_indent = IndentSize::spaces(0);
25690
25691    let cursor_is_before_end_tag_if_exists = {
25692        let mut char_position = 0u32;
25693        let mut end_tag_offset = None;
25694
25695        'outer: for chunk in snapshot.text_for_range(range) {
25696            if let Some(byte_pos) = chunk.find(&**end_tag) {
25697                let chars_before_match = chunk[..byte_pos].chars().count() as u32;
25698                end_tag_offset = Some(char_position + chars_before_match);
25699                break 'outer;
25700            }
25701            char_position += chunk.chars().count() as u32;
25702        }
25703
25704        if let Some(end_tag_offset) = end_tag_offset {
25705            let cursor_is_before_end_tag = column <= end_tag_offset;
25706            if cursor_is_after_start_tag {
25707                if cursor_is_before_end_tag {
25708                    needs_extra_line = true;
25709                }
25710                let cursor_is_at_start_of_end_tag = column == end_tag_offset;
25711                if cursor_is_at_start_of_end_tag {
25712                    extra_line_additional_indent.len = *len;
25713                }
25714            }
25715            cursor_is_before_end_tag
25716        } else {
25717            true
25718        }
25719    };
25720
25721    if (cursor_is_after_start_tag || cursor_is_after_delimiter)
25722        && cursor_is_before_end_tag_if_exists
25723    {
25724        let additional_indent = if cursor_is_after_start_tag {
25725            IndentSize::spaces(*len)
25726        } else {
25727            IndentSize::spaces(0)
25728        };
25729
25730        *newline_config = NewlineConfig::Newline {
25731            additional_indent,
25732            extra_line_additional_indent: if needs_extra_line {
25733                Some(extra_line_additional_indent)
25734            } else {
25735                None
25736            },
25737            prevent_auto_indent: true,
25738        };
25739        Some(delimiter.clone())
25740    } else {
25741        None
25742    }
25743}
25744
25745const ORDERED_LIST_MAX_MARKER_LEN: usize = 16;
25746
25747fn list_delimiter_for_newline(
25748    start_point: &Point,
25749    buffer: &MultiBufferSnapshot,
25750    language: &LanguageScope,
25751    newline_config: &mut NewlineConfig,
25752) -> Option<Arc<str>> {
25753    let (snapshot, range) = buffer.buffer_line_for_row(MultiBufferRow(start_point.row))?;
25754
25755    let num_of_whitespaces = snapshot
25756        .chars_for_range(range.clone())
25757        .take_while(|c| c.is_whitespace())
25758        .count();
25759
25760    let task_list_entries: Vec<_> = language
25761        .task_list()
25762        .into_iter()
25763        .flat_map(|config| {
25764            config
25765                .prefixes
25766                .iter()
25767                .map(|prefix| (prefix.as_ref(), config.continuation.as_ref()))
25768        })
25769        .collect();
25770    let unordered_list_entries: Vec<_> = language
25771        .unordered_list()
25772        .iter()
25773        .map(|marker| (marker.as_ref(), marker.as_ref()))
25774        .collect();
25775
25776    let all_entries: Vec<_> = task_list_entries
25777        .into_iter()
25778        .chain(unordered_list_entries)
25779        .collect();
25780
25781    if let Some(max_prefix_len) = all_entries.iter().map(|(p, _)| p.len()).max() {
25782        let candidate: String = snapshot
25783            .chars_for_range(range.clone())
25784            .skip(num_of_whitespaces)
25785            .take(max_prefix_len)
25786            .collect();
25787
25788        if let Some((prefix, continuation)) = all_entries
25789            .iter()
25790            .filter(|(prefix, _)| candidate.starts_with(*prefix))
25791            .max_by_key(|(prefix, _)| prefix.len())
25792        {
25793            let end_of_prefix = num_of_whitespaces + prefix.len();
25794            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25795            let has_content_after_marker = snapshot
25796                .chars_for_range(range)
25797                .skip(end_of_prefix)
25798                .any(|c| !c.is_whitespace());
25799
25800            if has_content_after_marker && cursor_is_after_prefix {
25801                return Some((*continuation).into());
25802            }
25803
25804            if start_point.column as usize == end_of_prefix {
25805                if num_of_whitespaces == 0 {
25806                    *newline_config = NewlineConfig::ClearCurrentLine;
25807                } else {
25808                    *newline_config = NewlineConfig::UnindentCurrentLine {
25809                        continuation: (*continuation).into(),
25810                    };
25811                }
25812            }
25813
25814            return None;
25815        }
25816    }
25817
25818    let candidate: String = snapshot
25819        .chars_for_range(range.clone())
25820        .skip(num_of_whitespaces)
25821        .take(ORDERED_LIST_MAX_MARKER_LEN)
25822        .collect();
25823
25824    for ordered_config in language.ordered_list() {
25825        let regex = match Regex::new(&ordered_config.pattern) {
25826            Ok(r) => r,
25827            Err(_) => continue,
25828        };
25829
25830        if let Some(captures) = regex.captures(&candidate) {
25831            let full_match = captures.get(0)?;
25832            let marker_len = full_match.len();
25833            let end_of_prefix = num_of_whitespaces + marker_len;
25834            let cursor_is_after_prefix = end_of_prefix <= start_point.column as usize;
25835
25836            let has_content_after_marker = snapshot
25837                .chars_for_range(range)
25838                .skip(end_of_prefix)
25839                .any(|c| !c.is_whitespace());
25840
25841            if has_content_after_marker && cursor_is_after_prefix {
25842                let number: u32 = captures.get(1)?.as_str().parse().ok()?;
25843                let continuation = ordered_config
25844                    .format
25845                    .replace("{1}", &(number + 1).to_string());
25846                return Some(continuation.into());
25847            }
25848
25849            if start_point.column as usize == end_of_prefix {
25850                let continuation = ordered_config.format.replace("{1}", "1");
25851                if num_of_whitespaces == 0 {
25852                    *newline_config = NewlineConfig::ClearCurrentLine;
25853                } else {
25854                    *newline_config = NewlineConfig::UnindentCurrentLine {
25855                        continuation: continuation.into(),
25856                    };
25857                }
25858            }
25859
25860            return None;
25861        }
25862    }
25863
25864    None
25865}
25866
25867fn is_list_prefix_row(
25868    row: MultiBufferRow,
25869    buffer: &MultiBufferSnapshot,
25870    language: &LanguageScope,
25871) -> bool {
25872    let Some((snapshot, range)) = buffer.buffer_line_for_row(row) else {
25873        return false;
25874    };
25875
25876    let num_of_whitespaces = snapshot
25877        .chars_for_range(range.clone())
25878        .take_while(|c| c.is_whitespace())
25879        .count();
25880
25881    let task_list_prefixes: Vec<_> = language
25882        .task_list()
25883        .into_iter()
25884        .flat_map(|config| {
25885            config
25886                .prefixes
25887                .iter()
25888                .map(|p| p.as_ref())
25889                .collect::<Vec<_>>()
25890        })
25891        .collect();
25892    let unordered_list_markers: Vec<_> = language
25893        .unordered_list()
25894        .iter()
25895        .map(|marker| marker.as_ref())
25896        .collect();
25897    let all_prefixes: Vec<_> = task_list_prefixes
25898        .into_iter()
25899        .chain(unordered_list_markers)
25900        .collect();
25901    if let Some(max_prefix_len) = all_prefixes.iter().map(|p| p.len()).max() {
25902        let candidate: String = snapshot
25903            .chars_for_range(range.clone())
25904            .skip(num_of_whitespaces)
25905            .take(max_prefix_len)
25906            .collect();
25907        if all_prefixes
25908            .iter()
25909            .any(|prefix| candidate.starts_with(*prefix))
25910        {
25911            return true;
25912        }
25913    }
25914
25915    let ordered_list_candidate: String = snapshot
25916        .chars_for_range(range)
25917        .skip(num_of_whitespaces)
25918        .take(ORDERED_LIST_MAX_MARKER_LEN)
25919        .collect();
25920    for ordered_config in language.ordered_list() {
25921        let regex = match Regex::new(&ordered_config.pattern) {
25922            Ok(r) => r,
25923            Err(_) => continue,
25924        };
25925        if let Some(captures) = regex.captures(&ordered_list_candidate) {
25926            return captures.get(0).is_some();
25927        }
25928    }
25929
25930    false
25931}
25932
25933#[derive(Debug)]
25934enum NewlineConfig {
25935    /// Insert newline with optional additional indent and optional extra blank line
25936    Newline {
25937        additional_indent: IndentSize,
25938        extra_line_additional_indent: Option<IndentSize>,
25939        prevent_auto_indent: bool,
25940    },
25941    /// Clear the current line
25942    ClearCurrentLine,
25943    /// Unindent the current line and add continuation
25944    UnindentCurrentLine { continuation: Arc<str> },
25945}
25946
25947impl NewlineConfig {
25948    fn has_extra_line(&self) -> bool {
25949        matches!(
25950            self,
25951            Self::Newline {
25952                extra_line_additional_indent: Some(_),
25953                ..
25954            }
25955        )
25956    }
25957
25958    fn insert_extra_newline_brackets(
25959        buffer: &MultiBufferSnapshot,
25960        range: Range<MultiBufferOffset>,
25961        language: &language::LanguageScope,
25962    ) -> bool {
25963        let leading_whitespace_len = buffer
25964            .reversed_chars_at(range.start)
25965            .take_while(|c| c.is_whitespace() && *c != '\n')
25966            .map(|c| c.len_utf8())
25967            .sum::<usize>();
25968        let trailing_whitespace_len = buffer
25969            .chars_at(range.end)
25970            .take_while(|c| c.is_whitespace() && *c != '\n')
25971            .map(|c| c.len_utf8())
25972            .sum::<usize>();
25973        let range = range.start - leading_whitespace_len..range.end + trailing_whitespace_len;
25974
25975        language.brackets().any(|(pair, enabled)| {
25976            let pair_start = pair.start.trim_end();
25977            let pair_end = pair.end.trim_start();
25978
25979            enabled
25980                && pair.newline
25981                && buffer.contains_str_at(range.end, pair_end)
25982                && buffer.contains_str_at(
25983                    range.start.saturating_sub_usize(pair_start.len()),
25984                    pair_start,
25985                )
25986        })
25987    }
25988
25989    fn insert_extra_newline_tree_sitter(
25990        buffer: &MultiBufferSnapshot,
25991        range: Range<MultiBufferOffset>,
25992    ) -> bool {
25993        let (buffer, range) = match buffer
25994            .range_to_buffer_ranges(range.start..=range.end)
25995            .as_slice()
25996        {
25997            [(buffer, range, _)] => (*buffer, range.clone()),
25998            _ => return false,
25999        };
26000        let pair = {
26001            let mut result: Option<BracketMatch<usize>> = None;
26002
26003            for pair in buffer
26004                .all_bracket_ranges(range.start.0..range.end.0)
26005                .filter(move |pair| {
26006                    pair.open_range.start <= range.start.0 && pair.close_range.end >= range.end.0
26007                })
26008            {
26009                let len = pair.close_range.end - pair.open_range.start;
26010
26011                if let Some(existing) = &result {
26012                    let existing_len = existing.close_range.end - existing.open_range.start;
26013                    if len > existing_len {
26014                        continue;
26015                    }
26016                }
26017
26018                result = Some(pair);
26019            }
26020
26021            result
26022        };
26023        let Some(pair) = pair else {
26024            return false;
26025        };
26026        pair.newline_only
26027            && buffer
26028                .chars_for_range(pair.open_range.end..range.start.0)
26029                .chain(buffer.chars_for_range(range.end.0..pair.close_range.start))
26030                .all(|c| c.is_whitespace() && c != '\n')
26031    }
26032}
26033
26034fn update_uncommitted_diff_for_buffer(
26035    editor: Entity<Editor>,
26036    project: &Entity<Project>,
26037    buffers: impl IntoIterator<Item = Entity<Buffer>>,
26038    buffer: Entity<MultiBuffer>,
26039    cx: &mut App,
26040) -> Task<()> {
26041    let mut tasks = Vec::new();
26042    project.update(cx, |project, cx| {
26043        for buffer in buffers {
26044            if project::File::from_dyn(buffer.read(cx).file()).is_some() {
26045                tasks.push(project.open_uncommitted_diff(buffer.clone(), cx))
26046            }
26047        }
26048    });
26049    cx.spawn(async move |cx| {
26050        let diffs = future::join_all(tasks).await;
26051        if editor.read_with(cx, |editor, _cx| editor.temporary_diff_override) {
26052            return;
26053        }
26054
26055        buffer.update(cx, |buffer, cx| {
26056            for diff in diffs.into_iter().flatten() {
26057                buffer.add_diff(diff, cx);
26058            }
26059        });
26060    })
26061}
26062
26063fn char_len_with_expanded_tabs(offset: usize, text: &str, tab_size: NonZeroU32) -> usize {
26064    let tab_size = tab_size.get() as usize;
26065    let mut width = offset;
26066
26067    for ch in text.chars() {
26068        width += if ch == '\t' {
26069            tab_size - (width % tab_size)
26070        } else {
26071            1
26072        };
26073    }
26074
26075    width - offset
26076}
26077
26078#[cfg(test)]
26079mod tests {
26080    use super::*;
26081
26082    #[test]
26083    fn test_string_size_with_expanded_tabs() {
26084        let nz = |val| NonZeroU32::new(val).unwrap();
26085        assert_eq!(char_len_with_expanded_tabs(0, "", nz(4)), 0);
26086        assert_eq!(char_len_with_expanded_tabs(0, "hello", nz(4)), 5);
26087        assert_eq!(char_len_with_expanded_tabs(0, "\thello", nz(4)), 9);
26088        assert_eq!(char_len_with_expanded_tabs(0, "abc\tab", nz(4)), 6);
26089        assert_eq!(char_len_with_expanded_tabs(0, "hello\t", nz(4)), 8);
26090        assert_eq!(char_len_with_expanded_tabs(0, "\t\t", nz(8)), 16);
26091        assert_eq!(char_len_with_expanded_tabs(0, "x\t", nz(8)), 8);
26092        assert_eq!(char_len_with_expanded_tabs(7, "x\t", nz(8)), 9);
26093    }
26094}
26095
26096/// Tokenizes a string into runs of text that should stick together, or that is whitespace.
26097struct WordBreakingTokenizer<'a> {
26098    input: &'a str,
26099}
26100
26101impl<'a> WordBreakingTokenizer<'a> {
26102    fn new(input: &'a str) -> Self {
26103        Self { input }
26104    }
26105}
26106
26107fn is_char_ideographic(ch: char) -> bool {
26108    use unicode_script::Script::*;
26109    use unicode_script::UnicodeScript;
26110    matches!(ch.script(), Han | Tangut | Yi)
26111}
26112
26113fn is_grapheme_ideographic(text: &str) -> bool {
26114    text.chars().any(is_char_ideographic)
26115}
26116
26117fn is_grapheme_whitespace(text: &str) -> bool {
26118    text.chars().any(|x| x.is_whitespace())
26119}
26120
26121fn should_stay_with_preceding_ideograph(text: &str) -> bool {
26122    text.chars()
26123        .next()
26124        .is_some_and(|ch| matches!(ch, '。' | '、' | ',' | '?' | '!' | ':' | ';' | '…'))
26125}
26126
26127#[derive(PartialEq, Eq, Debug, Clone, Copy)]
26128enum WordBreakToken<'a> {
26129    Word { token: &'a str, grapheme_len: usize },
26130    InlineWhitespace { token: &'a str, grapheme_len: usize },
26131    Newline,
26132}
26133
26134impl<'a> Iterator for WordBreakingTokenizer<'a> {
26135    /// Yields a span, the count of graphemes in the token, and whether it was
26136    /// whitespace. Note that it also breaks at word boundaries.
26137    type Item = WordBreakToken<'a>;
26138
26139    fn next(&mut self) -> Option<Self::Item> {
26140        use unicode_segmentation::UnicodeSegmentation;
26141        if self.input.is_empty() {
26142            return None;
26143        }
26144
26145        let mut iter = self.input.graphemes(true).peekable();
26146        let mut offset = 0;
26147        let mut grapheme_len = 0;
26148        if let Some(first_grapheme) = iter.next() {
26149            let is_newline = first_grapheme == "\n";
26150            let is_whitespace = is_grapheme_whitespace(first_grapheme);
26151            offset += first_grapheme.len();
26152            grapheme_len += 1;
26153            if is_grapheme_ideographic(first_grapheme) && !is_whitespace {
26154                if let Some(grapheme) = iter.peek().copied()
26155                    && should_stay_with_preceding_ideograph(grapheme)
26156                {
26157                    offset += grapheme.len();
26158                    grapheme_len += 1;
26159                }
26160            } else {
26161                let mut words = self.input[offset..].split_word_bound_indices().peekable();
26162                let mut next_word_bound = words.peek().copied();
26163                if next_word_bound.is_some_and(|(i, _)| i == 0) {
26164                    next_word_bound = words.next();
26165                }
26166                while let Some(grapheme) = iter.peek().copied() {
26167                    if next_word_bound.is_some_and(|(i, _)| i == offset) {
26168                        break;
26169                    };
26170                    if is_grapheme_whitespace(grapheme) != is_whitespace
26171                        || (grapheme == "\n") != is_newline
26172                    {
26173                        break;
26174                    };
26175                    offset += grapheme.len();
26176                    grapheme_len += 1;
26177                    iter.next();
26178                }
26179            }
26180            let token = &self.input[..offset];
26181            self.input = &self.input[offset..];
26182            if token == "\n" {
26183                Some(WordBreakToken::Newline)
26184            } else if is_whitespace {
26185                Some(WordBreakToken::InlineWhitespace {
26186                    token,
26187                    grapheme_len,
26188                })
26189            } else {
26190                Some(WordBreakToken::Word {
26191                    token,
26192                    grapheme_len,
26193                })
26194            }
26195        } else {
26196            None
26197        }
26198    }
26199}
26200
26201#[test]
26202fn test_word_breaking_tokenizer() {
26203    let tests: &[(&str, &[WordBreakToken<'static>])] = &[
26204        ("", &[]),
26205        ("  ", &[whitespace("  ", 2)]),
26206        ("Ʒ", &[word("Ʒ", 1)]),
26207        ("Ǽ", &[word("Ǽ", 1)]),
26208        ("", &[word("", 1)]),
26209        ("⋑⋑", &[word("⋑⋑", 2)]),
26210        (
26211            "原理,进而",
26212            &[word("", 1), word("理,", 2), word("", 1), word("", 1)],
26213        ),
26214        (
26215            "hello world",
26216            &[word("hello", 5), whitespace(" ", 1), word("world", 5)],
26217        ),
26218        (
26219            "hello, world",
26220            &[word("hello,", 6), whitespace(" ", 1), word("world", 5)],
26221        ),
26222        (
26223            "  hello world",
26224            &[
26225                whitespace("  ", 2),
26226                word("hello", 5),
26227                whitespace(" ", 1),
26228                word("world", 5),
26229            ],
26230        ),
26231        (
26232            "这是什么 \n 钢笔",
26233            &[
26234                word("", 1),
26235                word("", 1),
26236                word("", 1),
26237                word("", 1),
26238                whitespace(" ", 1),
26239                newline(),
26240                whitespace(" ", 1),
26241                word("", 1),
26242                word("", 1),
26243            ],
26244        ),
26245        (" mutton", &[whitespace("", 1), word("mutton", 6)]),
26246    ];
26247
26248    fn word(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26249        WordBreakToken::Word {
26250            token,
26251            grapheme_len,
26252        }
26253    }
26254
26255    fn whitespace(token: &'static str, grapheme_len: usize) -> WordBreakToken<'static> {
26256        WordBreakToken::InlineWhitespace {
26257            token,
26258            grapheme_len,
26259        }
26260    }
26261
26262    fn newline() -> WordBreakToken<'static> {
26263        WordBreakToken::Newline
26264    }
26265
26266    for (input, result) in tests {
26267        assert_eq!(
26268            WordBreakingTokenizer::new(input)
26269                .collect::<Vec<_>>()
26270                .as_slice(),
26271            *result,
26272        );
26273    }
26274}
26275
26276fn wrap_with_prefix(
26277    first_line_prefix: String,
26278    subsequent_lines_prefix: String,
26279    unwrapped_text: String,
26280    wrap_column: usize,
26281    tab_size: NonZeroU32,
26282    preserve_existing_whitespace: bool,
26283) -> String {
26284    let first_line_prefix_len = char_len_with_expanded_tabs(0, &first_line_prefix, tab_size);
26285    let subsequent_lines_prefix_len =
26286        char_len_with_expanded_tabs(0, &subsequent_lines_prefix, tab_size);
26287    let mut wrapped_text = String::new();
26288    let mut current_line = first_line_prefix;
26289    let mut is_first_line = true;
26290
26291    let tokenizer = WordBreakingTokenizer::new(&unwrapped_text);
26292    let mut current_line_len = first_line_prefix_len;
26293    let mut in_whitespace = false;
26294    for token in tokenizer {
26295        let have_preceding_whitespace = in_whitespace;
26296        match token {
26297            WordBreakToken::Word {
26298                token,
26299                grapheme_len,
26300            } => {
26301                in_whitespace = false;
26302                let current_prefix_len = if is_first_line {
26303                    first_line_prefix_len
26304                } else {
26305                    subsequent_lines_prefix_len
26306                };
26307                if current_line_len + grapheme_len > wrap_column
26308                    && current_line_len != current_prefix_len
26309                {
26310                    wrapped_text.push_str(current_line.trim_end());
26311                    wrapped_text.push('\n');
26312                    is_first_line = false;
26313                    current_line = subsequent_lines_prefix.clone();
26314                    current_line_len = subsequent_lines_prefix_len;
26315                }
26316                current_line.push_str(token);
26317                current_line_len += grapheme_len;
26318            }
26319            WordBreakToken::InlineWhitespace {
26320                mut token,
26321                mut grapheme_len,
26322            } => {
26323                in_whitespace = true;
26324                if have_preceding_whitespace && !preserve_existing_whitespace {
26325                    continue;
26326                }
26327                if !preserve_existing_whitespace {
26328                    // Keep a single whitespace grapheme as-is
26329                    if let Some(first) =
26330                        unicode_segmentation::UnicodeSegmentation::graphemes(token, true).next()
26331                    {
26332                        token = first;
26333                    } else {
26334                        token = " ";
26335                    }
26336                    grapheme_len = 1;
26337                }
26338                let current_prefix_len = if is_first_line {
26339                    first_line_prefix_len
26340                } else {
26341                    subsequent_lines_prefix_len
26342                };
26343                if current_line_len + grapheme_len > wrap_column {
26344                    wrapped_text.push_str(current_line.trim_end());
26345                    wrapped_text.push('\n');
26346                    is_first_line = false;
26347                    current_line = subsequent_lines_prefix.clone();
26348                    current_line_len = subsequent_lines_prefix_len;
26349                } else if current_line_len != current_prefix_len || preserve_existing_whitespace {
26350                    current_line.push_str(token);
26351                    current_line_len += grapheme_len;
26352                }
26353            }
26354            WordBreakToken::Newline => {
26355                in_whitespace = true;
26356                let current_prefix_len = if is_first_line {
26357                    first_line_prefix_len
26358                } else {
26359                    subsequent_lines_prefix_len
26360                };
26361                if preserve_existing_whitespace {
26362                    wrapped_text.push_str(current_line.trim_end());
26363                    wrapped_text.push('\n');
26364                    is_first_line = false;
26365                    current_line = subsequent_lines_prefix.clone();
26366                    current_line_len = subsequent_lines_prefix_len;
26367                } else if have_preceding_whitespace {
26368                    continue;
26369                } else if current_line_len + 1 > wrap_column
26370                    && current_line_len != current_prefix_len
26371                {
26372                    wrapped_text.push_str(current_line.trim_end());
26373                    wrapped_text.push('\n');
26374                    is_first_line = false;
26375                    current_line = subsequent_lines_prefix.clone();
26376                    current_line_len = subsequent_lines_prefix_len;
26377                } else if current_line_len != current_prefix_len {
26378                    current_line.push(' ');
26379                    current_line_len += 1;
26380                }
26381            }
26382        }
26383    }
26384
26385    if !current_line.is_empty() {
26386        wrapped_text.push_str(&current_line);
26387    }
26388    wrapped_text
26389}
26390
26391#[test]
26392fn test_wrap_with_prefix() {
26393    assert_eq!(
26394        wrap_with_prefix(
26395            "# ".to_string(),
26396            "# ".to_string(),
26397            "abcdefg".to_string(),
26398            4,
26399            NonZeroU32::new(4).unwrap(),
26400            false,
26401        ),
26402        "# abcdefg"
26403    );
26404    assert_eq!(
26405        wrap_with_prefix(
26406            "".to_string(),
26407            "".to_string(),
26408            "\thello world".to_string(),
26409            8,
26410            NonZeroU32::new(4).unwrap(),
26411            false,
26412        ),
26413        "hello\nworld"
26414    );
26415    assert_eq!(
26416        wrap_with_prefix(
26417            "// ".to_string(),
26418            "// ".to_string(),
26419            "xx \nyy zz aa bb cc".to_string(),
26420            12,
26421            NonZeroU32::new(4).unwrap(),
26422            false,
26423        ),
26424        "// xx yy zz\n// aa bb cc"
26425    );
26426    assert_eq!(
26427        wrap_with_prefix(
26428            String::new(),
26429            String::new(),
26430            "这是什么 \n 钢笔".to_string(),
26431            3,
26432            NonZeroU32::new(4).unwrap(),
26433            false,
26434        ),
26435        "这是什\n么 钢\n"
26436    );
26437    assert_eq!(
26438        wrap_with_prefix(
26439            String::new(),
26440            String::new(),
26441            format!("foo{}bar", '\u{2009}'), // thin space
26442            80,
26443            NonZeroU32::new(4).unwrap(),
26444            false,
26445        ),
26446        format!("foo{}bar", '\u{2009}')
26447    );
26448}
26449
26450pub trait CollaborationHub {
26451    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator>;
26452    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex>;
26453    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString>;
26454}
26455
26456impl CollaborationHub for Entity<Project> {
26457    fn collaborators<'a>(&self, cx: &'a App) -> &'a HashMap<PeerId, Collaborator> {
26458        self.read(cx).collaborators()
26459    }
26460
26461    fn user_participant_indices<'a>(&self, cx: &'a App) -> &'a HashMap<u64, ParticipantIndex> {
26462        self.read(cx).user_store().read(cx).participant_indices()
26463    }
26464
26465    fn user_names(&self, cx: &App) -> HashMap<u64, SharedString> {
26466        let this = self.read(cx);
26467        let user_ids = this.collaborators().values().map(|c| c.user_id);
26468        this.user_store().read(cx).participant_names(user_ids, cx)
26469    }
26470}
26471
26472pub trait SemanticsProvider {
26473    fn hover(
26474        &self,
26475        buffer: &Entity<Buffer>,
26476        position: text::Anchor,
26477        cx: &mut App,
26478    ) -> Option<Task<Option<Vec<project::Hover>>>>;
26479
26480    fn inline_values(
26481        &self,
26482        buffer_handle: Entity<Buffer>,
26483        range: Range<text::Anchor>,
26484        cx: &mut App,
26485    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>>;
26486
26487    fn applicable_inlay_chunks(
26488        &self,
26489        buffer: &Entity<Buffer>,
26490        ranges: &[Range<text::Anchor>],
26491        cx: &mut App,
26492    ) -> Vec<Range<BufferRow>>;
26493
26494    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App);
26495
26496    fn inlay_hints(
26497        &self,
26498        invalidate: InvalidationStrategy,
26499        buffer: Entity<Buffer>,
26500        ranges: Vec<Range<text::Anchor>>,
26501        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
26502        cx: &mut App,
26503    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>>;
26504
26505    fn semantic_tokens(
26506        &self,
26507        buffer: Entity<Buffer>,
26508        refresh: Option<RefreshForServer>,
26509        cx: &mut App,
26510    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>>;
26511
26512    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26513
26514    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool;
26515
26516    fn document_highlights(
26517        &self,
26518        buffer: &Entity<Buffer>,
26519        position: text::Anchor,
26520        cx: &mut App,
26521    ) -> Option<Task<Result<Vec<DocumentHighlight>>>>;
26522
26523    fn definitions(
26524        &self,
26525        buffer: &Entity<Buffer>,
26526        position: text::Anchor,
26527        kind: GotoDefinitionKind,
26528        cx: &mut App,
26529    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>>;
26530
26531    fn range_for_rename(
26532        &self,
26533        buffer: &Entity<Buffer>,
26534        position: text::Anchor,
26535        cx: &mut App,
26536    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>>;
26537
26538    fn perform_rename(
26539        &self,
26540        buffer: &Entity<Buffer>,
26541        position: text::Anchor,
26542        new_name: String,
26543        cx: &mut App,
26544    ) -> Option<Task<Result<ProjectTransaction>>>;
26545}
26546
26547pub trait CompletionProvider {
26548    fn completions(
26549        &self,
26550        excerpt_id: ExcerptId,
26551        buffer: &Entity<Buffer>,
26552        buffer_position: text::Anchor,
26553        trigger: CompletionContext,
26554        window: &mut Window,
26555        cx: &mut Context<Editor>,
26556    ) -> Task<Result<Vec<CompletionResponse>>>;
26557
26558    fn resolve_completions(
26559        &self,
26560        _buffer: Entity<Buffer>,
26561        _completion_indices: Vec<usize>,
26562        _completions: Rc<RefCell<Box<[Completion]>>>,
26563        _cx: &mut Context<Editor>,
26564    ) -> Task<Result<bool>> {
26565        Task::ready(Ok(false))
26566    }
26567
26568    fn apply_additional_edits_for_completion(
26569        &self,
26570        _buffer: Entity<Buffer>,
26571        _completions: Rc<RefCell<Box<[Completion]>>>,
26572        _completion_index: usize,
26573        _push_to_history: bool,
26574        _cx: &mut Context<Editor>,
26575    ) -> Task<Result<Option<language::Transaction>>> {
26576        Task::ready(Ok(None))
26577    }
26578
26579    fn is_completion_trigger(
26580        &self,
26581        buffer: &Entity<Buffer>,
26582        position: language::Anchor,
26583        text: &str,
26584        trigger_in_words: bool,
26585        cx: &mut Context<Editor>,
26586    ) -> bool;
26587
26588    fn selection_changed(&self, _mat: Option<&StringMatch>, _window: &mut Window, _cx: &mut App) {}
26589
26590    fn sort_completions(&self) -> bool {
26591        true
26592    }
26593
26594    fn filter_completions(&self) -> bool {
26595        true
26596    }
26597
26598    fn show_snippets(&self) -> bool {
26599        false
26600    }
26601}
26602
26603pub trait CodeActionProvider {
26604    fn id(&self) -> Arc<str>;
26605
26606    fn code_actions(
26607        &self,
26608        buffer: &Entity<Buffer>,
26609        range: Range<text::Anchor>,
26610        window: &mut Window,
26611        cx: &mut App,
26612    ) -> Task<Result<Vec<CodeAction>>>;
26613
26614    fn apply_code_action(
26615        &self,
26616        buffer_handle: Entity<Buffer>,
26617        action: CodeAction,
26618        excerpt_id: ExcerptId,
26619        push_to_history: bool,
26620        window: &mut Window,
26621        cx: &mut App,
26622    ) -> Task<Result<ProjectTransaction>>;
26623}
26624
26625impl CodeActionProvider for Entity<Project> {
26626    fn id(&self) -> Arc<str> {
26627        "project".into()
26628    }
26629
26630    fn code_actions(
26631        &self,
26632        buffer: &Entity<Buffer>,
26633        range: Range<text::Anchor>,
26634        _window: &mut Window,
26635        cx: &mut App,
26636    ) -> Task<Result<Vec<CodeAction>>> {
26637        self.update(cx, |project, cx| {
26638            let code_lens_actions = project.code_lens_actions(buffer, range.clone(), cx);
26639            let code_actions = project.code_actions(buffer, range, None, cx);
26640            cx.background_spawn(async move {
26641                let (code_lens_actions, code_actions) = join(code_lens_actions, code_actions).await;
26642                Ok(code_lens_actions
26643                    .context("code lens fetch")?
26644                    .into_iter()
26645                    .flatten()
26646                    .chain(
26647                        code_actions
26648                            .context("code action fetch")?
26649                            .into_iter()
26650                            .flatten(),
26651                    )
26652                    .collect())
26653            })
26654        })
26655    }
26656
26657    fn apply_code_action(
26658        &self,
26659        buffer_handle: Entity<Buffer>,
26660        action: CodeAction,
26661        _excerpt_id: ExcerptId,
26662        push_to_history: bool,
26663        _window: &mut Window,
26664        cx: &mut App,
26665    ) -> Task<Result<ProjectTransaction>> {
26666        self.update(cx, |project, cx| {
26667            project.apply_code_action(buffer_handle, action, push_to_history, cx)
26668        })
26669    }
26670}
26671
26672fn snippet_completions(
26673    project: &Project,
26674    buffer: &Entity<Buffer>,
26675    buffer_anchor: text::Anchor,
26676    classifier: CharClassifier,
26677    cx: &mut App,
26678) -> Task<Result<CompletionResponse>> {
26679    let languages = buffer.read(cx).languages_at(buffer_anchor);
26680    let snippet_store = project.snippets().read(cx);
26681
26682    let scopes: Vec<_> = languages
26683        .iter()
26684        .filter_map(|language| {
26685            let language_name = language.lsp_id();
26686            let snippets = snippet_store.snippets_for(Some(language_name), cx);
26687
26688            if snippets.is_empty() {
26689                None
26690            } else {
26691                Some((language.default_scope(), snippets))
26692            }
26693        })
26694        .collect();
26695
26696    if scopes.is_empty() {
26697        return Task::ready(Ok(CompletionResponse {
26698            completions: vec![],
26699            display_options: CompletionDisplayOptions::default(),
26700            is_incomplete: false,
26701        }));
26702    }
26703
26704    let snapshot = buffer.read(cx).text_snapshot();
26705    let executor = cx.background_executor().clone();
26706
26707    cx.background_spawn(async move {
26708        let is_word_char = |c| classifier.is_word(c);
26709
26710        let mut is_incomplete = false;
26711        let mut completions: Vec<Completion> = Vec::new();
26712
26713        const MAX_PREFIX_LEN: usize = 128;
26714        let buffer_offset = text::ToOffset::to_offset(&buffer_anchor, &snapshot);
26715        let window_start = buffer_offset.saturating_sub(MAX_PREFIX_LEN);
26716        let window_start = snapshot.clip_offset(window_start, Bias::Left);
26717
26718        let max_buffer_window: String = snapshot
26719            .text_for_range(window_start..buffer_offset)
26720            .collect();
26721
26722        if max_buffer_window.is_empty() {
26723            return Ok(CompletionResponse {
26724                completions: vec![],
26725                display_options: CompletionDisplayOptions::default(),
26726                is_incomplete: true,
26727            });
26728        }
26729
26730        for (_scope, snippets) in scopes.into_iter() {
26731            // Sort snippets by word count to match longer snippet prefixes first.
26732            let mut sorted_snippet_candidates = snippets
26733                .iter()
26734                .enumerate()
26735                .flat_map(|(snippet_ix, snippet)| {
26736                    snippet
26737                        .prefix
26738                        .iter()
26739                        .enumerate()
26740                        .map(move |(prefix_ix, prefix)| {
26741                            let word_count =
26742                                snippet_candidate_suffixes(prefix, &is_word_char).count();
26743                            ((snippet_ix, prefix_ix), prefix, word_count)
26744                        })
26745                })
26746                .collect_vec();
26747            sorted_snippet_candidates
26748                .sort_unstable_by_key(|(_, _, word_count)| Reverse(*word_count));
26749
26750            // Each prefix may be matched multiple times; the completion menu must filter out duplicates.
26751
26752            let buffer_windows = snippet_candidate_suffixes(&max_buffer_window, &is_word_char)
26753                .take(
26754                    sorted_snippet_candidates
26755                        .first()
26756                        .map(|(_, _, word_count)| *word_count)
26757                        .unwrap_or_default(),
26758                )
26759                .collect_vec();
26760
26761            const MAX_RESULTS: usize = 100;
26762            // Each match also remembers how many characters from the buffer it consumed
26763            let mut matches: Vec<(StringMatch, usize)> = vec![];
26764
26765            let mut snippet_list_cutoff_index = 0;
26766            for (buffer_index, buffer_window) in buffer_windows.iter().enumerate().rev() {
26767                let word_count = buffer_index + 1;
26768                // Increase `snippet_list_cutoff_index` until we have all of the
26769                // snippets with sufficiently many words.
26770                while sorted_snippet_candidates
26771                    .get(snippet_list_cutoff_index)
26772                    .is_some_and(|(_ix, _prefix, snippet_word_count)| {
26773                        *snippet_word_count >= word_count
26774                    })
26775                {
26776                    snippet_list_cutoff_index += 1;
26777                }
26778
26779                // Take only the candidates with at least `word_count` many words
26780                let snippet_candidates_at_word_len =
26781                    &sorted_snippet_candidates[..snippet_list_cutoff_index];
26782
26783                let candidates = snippet_candidates_at_word_len
26784                    .iter()
26785                    .map(|(_snippet_ix, prefix, _snippet_word_count)| prefix)
26786                    .enumerate() // index in `sorted_snippet_candidates`
26787                    // First char must match
26788                    .filter(|(_ix, prefix)| {
26789                        itertools::equal(
26790                            prefix
26791                                .chars()
26792                                .next()
26793                                .into_iter()
26794                                .flat_map(|c| c.to_lowercase()),
26795                            buffer_window
26796                                .chars()
26797                                .next()
26798                                .into_iter()
26799                                .flat_map(|c| c.to_lowercase()),
26800                        )
26801                    })
26802                    .map(|(ix, prefix)| StringMatchCandidate::new(ix, prefix))
26803                    .collect::<Vec<StringMatchCandidate>>();
26804
26805                matches.extend(
26806                    fuzzy::match_strings(
26807                        &candidates,
26808                        &buffer_window,
26809                        buffer_window.chars().any(|c| c.is_uppercase()),
26810                        true,
26811                        MAX_RESULTS - matches.len(), // always prioritize longer snippets
26812                        &Default::default(),
26813                        executor.clone(),
26814                    )
26815                    .await
26816                    .into_iter()
26817                    .map(|string_match| (string_match, buffer_window.len())),
26818                );
26819
26820                if matches.len() >= MAX_RESULTS {
26821                    break;
26822                }
26823            }
26824
26825            let to_lsp = |point: &text::Anchor| {
26826                let end = text::ToPointUtf16::to_point_utf16(point, &snapshot);
26827                point_to_lsp(end)
26828            };
26829            let lsp_end = to_lsp(&buffer_anchor);
26830
26831            if matches.len() >= MAX_RESULTS {
26832                is_incomplete = true;
26833            }
26834
26835            completions.extend(matches.iter().map(|(string_match, buffer_window_len)| {
26836                let ((snippet_index, prefix_index), matching_prefix, _snippet_word_count) =
26837                    sorted_snippet_candidates[string_match.candidate_id];
26838                let snippet = &snippets[snippet_index];
26839                let start = buffer_offset - buffer_window_len;
26840                let start = snapshot.anchor_before(start);
26841                let range = start..buffer_anchor;
26842                let lsp_start = to_lsp(&start);
26843                let lsp_range = lsp::Range {
26844                    start: lsp_start,
26845                    end: lsp_end,
26846                };
26847                Completion {
26848                    replace_range: range,
26849                    new_text: snippet.body.clone(),
26850                    source: CompletionSource::Lsp {
26851                        insert_range: None,
26852                        server_id: LanguageServerId(usize::MAX),
26853                        resolved: true,
26854                        lsp_completion: Box::new(lsp::CompletionItem {
26855                            label: snippet.prefix.first().unwrap().clone(),
26856                            kind: Some(CompletionItemKind::SNIPPET),
26857                            label_details: snippet.description.as_ref().map(|description| {
26858                                lsp::CompletionItemLabelDetails {
26859                                    detail: Some(description.clone()),
26860                                    description: None,
26861                                }
26862                            }),
26863                            insert_text_format: Some(InsertTextFormat::SNIPPET),
26864                            text_edit: Some(lsp::CompletionTextEdit::InsertAndReplace(
26865                                lsp::InsertReplaceEdit {
26866                                    new_text: snippet.body.clone(),
26867                                    insert: lsp_range,
26868                                    replace: lsp_range,
26869                                },
26870                            )),
26871                            filter_text: Some(snippet.body.clone()),
26872                            sort_text: Some(char::MAX.to_string()),
26873                            ..lsp::CompletionItem::default()
26874                        }),
26875                        lsp_defaults: None,
26876                    },
26877                    label: CodeLabel {
26878                        text: matching_prefix.clone(),
26879                        runs: Vec::new(),
26880                        filter_range: 0..matching_prefix.len(),
26881                    },
26882                    icon_path: None,
26883                    documentation: Some(CompletionDocumentation::SingleLineAndMultiLinePlainText {
26884                        single_line: snippet.name.clone().into(),
26885                        plain_text: snippet
26886                            .description
26887                            .clone()
26888                            .map(|description| description.into()),
26889                    }),
26890                    insert_text_mode: None,
26891                    confirm: None,
26892                    match_start: Some(start),
26893                    snippet_deduplication_key: Some((snippet_index, prefix_index)),
26894                }
26895            }));
26896        }
26897
26898        Ok(CompletionResponse {
26899            completions,
26900            display_options: CompletionDisplayOptions::default(),
26901            is_incomplete,
26902        })
26903    })
26904}
26905
26906impl CompletionProvider for Entity<Project> {
26907    fn completions(
26908        &self,
26909        _excerpt_id: ExcerptId,
26910        buffer: &Entity<Buffer>,
26911        buffer_position: text::Anchor,
26912        options: CompletionContext,
26913        _window: &mut Window,
26914        cx: &mut Context<Editor>,
26915    ) -> Task<Result<Vec<CompletionResponse>>> {
26916        self.update(cx, |project, cx| {
26917            let task = project.completions(buffer, buffer_position, options, cx);
26918            cx.background_spawn(task)
26919        })
26920    }
26921
26922    fn resolve_completions(
26923        &self,
26924        buffer: Entity<Buffer>,
26925        completion_indices: Vec<usize>,
26926        completions: Rc<RefCell<Box<[Completion]>>>,
26927        cx: &mut Context<Editor>,
26928    ) -> Task<Result<bool>> {
26929        self.update(cx, |project, cx| {
26930            project.lsp_store().update(cx, |lsp_store, cx| {
26931                lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
26932            })
26933        })
26934    }
26935
26936    fn apply_additional_edits_for_completion(
26937        &self,
26938        buffer: Entity<Buffer>,
26939        completions: Rc<RefCell<Box<[Completion]>>>,
26940        completion_index: usize,
26941        push_to_history: bool,
26942        cx: &mut Context<Editor>,
26943    ) -> Task<Result<Option<language::Transaction>>> {
26944        self.update(cx, |project, cx| {
26945            project.lsp_store().update(cx, |lsp_store, cx| {
26946                lsp_store.apply_additional_edits_for_completion(
26947                    buffer,
26948                    completions,
26949                    completion_index,
26950                    push_to_history,
26951                    cx,
26952                )
26953            })
26954        })
26955    }
26956
26957    fn is_completion_trigger(
26958        &self,
26959        buffer: &Entity<Buffer>,
26960        position: language::Anchor,
26961        text: &str,
26962        trigger_in_words: bool,
26963        cx: &mut Context<Editor>,
26964    ) -> bool {
26965        let mut chars = text.chars();
26966        let char = if let Some(char) = chars.next() {
26967            char
26968        } else {
26969            return false;
26970        };
26971        if chars.next().is_some() {
26972            return false;
26973        }
26974
26975        let buffer = buffer.read(cx);
26976        let snapshot = buffer.snapshot();
26977        let classifier = snapshot
26978            .char_classifier_at(position)
26979            .scope_context(Some(CharScopeContext::Completion));
26980        if trigger_in_words && classifier.is_word(char) {
26981            return true;
26982        }
26983
26984        buffer.completion_triggers().contains(text)
26985    }
26986
26987    fn show_snippets(&self) -> bool {
26988        true
26989    }
26990}
26991
26992impl SemanticsProvider for WeakEntity<Project> {
26993    fn hover(
26994        &self,
26995        buffer: &Entity<Buffer>,
26996        position: text::Anchor,
26997        cx: &mut App,
26998    ) -> Option<Task<Option<Vec<project::Hover>>>> {
26999        self.update(cx, |project, cx| project.hover(buffer, position, cx))
27000            .ok()
27001    }
27002
27003    fn document_highlights(
27004        &self,
27005        buffer: &Entity<Buffer>,
27006        position: text::Anchor,
27007        cx: &mut App,
27008    ) -> Option<Task<Result<Vec<DocumentHighlight>>>> {
27009        self.update(cx, |project, cx| {
27010            project.document_highlights(buffer, position, cx)
27011        })
27012        .ok()
27013    }
27014
27015    fn definitions(
27016        &self,
27017        buffer: &Entity<Buffer>,
27018        position: text::Anchor,
27019        kind: GotoDefinitionKind,
27020        cx: &mut App,
27021    ) -> Option<Task<Result<Option<Vec<LocationLink>>>>> {
27022        self.update(cx, |project, cx| match kind {
27023            GotoDefinitionKind::Symbol => project.definitions(buffer, position, cx),
27024            GotoDefinitionKind::Declaration => project.declarations(buffer, position, cx),
27025            GotoDefinitionKind::Type => project.type_definitions(buffer, position, cx),
27026            GotoDefinitionKind::Implementation => project.implementations(buffer, position, cx),
27027        })
27028        .ok()
27029    }
27030
27031    fn supports_inlay_hints(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27032        self.update(cx, |project, cx| {
27033            if project
27034                .active_debug_session(cx)
27035                .is_some_and(|(session, _)| session.read(cx).any_stopped_thread())
27036            {
27037                return true;
27038            }
27039
27040            buffer.update(cx, |buffer, cx| {
27041                project.any_language_server_supports_inlay_hints(buffer, cx)
27042            })
27043        })
27044        .unwrap_or(false)
27045    }
27046
27047    fn supports_semantic_tokens(&self, buffer: &Entity<Buffer>, cx: &mut App) -> bool {
27048        self.update(cx, |project, cx| {
27049            buffer.update(cx, |buffer, cx| {
27050                project.any_language_server_supports_semantic_tokens(buffer, cx)
27051            })
27052        })
27053        .unwrap_or(false)
27054    }
27055
27056    fn inline_values(
27057        &self,
27058        buffer_handle: Entity<Buffer>,
27059        range: Range<text::Anchor>,
27060        cx: &mut App,
27061    ) -> Option<Task<anyhow::Result<Vec<InlayHint>>>> {
27062        self.update(cx, |project, cx| {
27063            let (session, active_stack_frame) = project.active_debug_session(cx)?;
27064
27065            Some(project.inline_values(session, active_stack_frame, buffer_handle, range, cx))
27066        })
27067        .ok()
27068        .flatten()
27069    }
27070
27071    fn applicable_inlay_chunks(
27072        &self,
27073        buffer: &Entity<Buffer>,
27074        ranges: &[Range<text::Anchor>],
27075        cx: &mut App,
27076    ) -> Vec<Range<BufferRow>> {
27077        self.update(cx, |project, cx| {
27078            project.lsp_store().update(cx, |lsp_store, cx| {
27079                lsp_store.applicable_inlay_chunks(buffer, ranges, cx)
27080            })
27081        })
27082        .unwrap_or_default()
27083    }
27084
27085    fn invalidate_inlay_hints(&self, for_buffers: &HashSet<BufferId>, cx: &mut App) {
27086        self.update(cx, |project, cx| {
27087            project.lsp_store().update(cx, |lsp_store, _| {
27088                lsp_store.invalidate_inlay_hints(for_buffers)
27089            })
27090        })
27091        .ok();
27092    }
27093
27094    fn inlay_hints(
27095        &self,
27096        invalidate: InvalidationStrategy,
27097        buffer: Entity<Buffer>,
27098        ranges: Vec<Range<text::Anchor>>,
27099        known_chunks: Option<(clock::Global, HashSet<Range<BufferRow>>)>,
27100        cx: &mut App,
27101    ) -> Option<HashMap<Range<BufferRow>, Task<Result<CacheInlayHints>>>> {
27102        self.update(cx, |project, cx| {
27103            project.lsp_store().update(cx, |lsp_store, cx| {
27104                lsp_store.inlay_hints(invalidate, buffer, ranges, known_chunks, cx)
27105            })
27106        })
27107        .ok()
27108    }
27109
27110    fn semantic_tokens(
27111        &self,
27112        buffer: Entity<Buffer>,
27113        refresh: Option<RefreshForServer>,
27114        cx: &mut App,
27115    ) -> Option<Shared<Task<std::result::Result<BufferSemanticTokens, Arc<anyhow::Error>>>>> {
27116        self.update(cx, |this, cx| {
27117            this.lsp_store().update(cx, |lsp_store, cx| {
27118                lsp_store.semantic_tokens(buffer, refresh, cx)
27119            })
27120        })
27121        .ok()
27122    }
27123
27124    fn range_for_rename(
27125        &self,
27126        buffer: &Entity<Buffer>,
27127        position: text::Anchor,
27128        cx: &mut App,
27129    ) -> Option<Task<Result<Option<Range<text::Anchor>>>>> {
27130        self.update(cx, |project, cx| {
27131            let buffer = buffer.clone();
27132            let task = project.prepare_rename(buffer.clone(), position, cx);
27133            cx.spawn(async move |_, cx| {
27134                Ok(match task.await? {
27135                    PrepareRenameResponse::Success(range) => Some(range),
27136                    PrepareRenameResponse::InvalidPosition => None,
27137                    PrepareRenameResponse::OnlyUnpreparedRenameSupported => {
27138                        // Fallback on using TreeSitter info to determine identifier range
27139                        buffer.read_with(cx, |buffer, _| {
27140                            let snapshot = buffer.snapshot();
27141                            let (range, kind) = snapshot.surrounding_word(position, None);
27142                            if kind != Some(CharKind::Word) {
27143                                return None;
27144                            }
27145                            Some(
27146                                snapshot.anchor_before(range.start)
27147                                    ..snapshot.anchor_after(range.end),
27148                            )
27149                        })
27150                    }
27151                })
27152            })
27153        })
27154        .ok()
27155    }
27156
27157    fn perform_rename(
27158        &self,
27159        buffer: &Entity<Buffer>,
27160        position: text::Anchor,
27161        new_name: String,
27162        cx: &mut App,
27163    ) -> Option<Task<Result<ProjectTransaction>>> {
27164        self.update(cx, |project, cx| {
27165            project.perform_rename(buffer.clone(), position, new_name, cx)
27166        })
27167        .ok()
27168    }
27169}
27170
27171fn consume_contiguous_rows(
27172    contiguous_row_selections: &mut Vec<Selection<Point>>,
27173    selection: &Selection<Point>,
27174    display_map: &DisplaySnapshot,
27175    selections: &mut Peekable<std::slice::Iter<Selection<Point>>>,
27176) -> (MultiBufferRow, MultiBufferRow) {
27177    contiguous_row_selections.push(selection.clone());
27178    let start_row = starting_row(selection, display_map);
27179    let mut end_row = ending_row(selection, display_map);
27180
27181    while let Some(next_selection) = selections.peek() {
27182        if next_selection.start.row <= end_row.0 {
27183            end_row = ending_row(next_selection, display_map);
27184            contiguous_row_selections.push(selections.next().unwrap().clone());
27185        } else {
27186            break;
27187        }
27188    }
27189    (start_row, end_row)
27190}
27191
27192fn starting_row(selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27193    if selection.start.column > 0 {
27194        MultiBufferRow(display_map.prev_line_boundary(selection.start).0.row)
27195    } else {
27196        MultiBufferRow(selection.start.row)
27197    }
27198}
27199
27200fn ending_row(next_selection: &Selection<Point>, display_map: &DisplaySnapshot) -> MultiBufferRow {
27201    if next_selection.end.column > 0 || next_selection.is_empty() {
27202        MultiBufferRow(display_map.next_line_boundary(next_selection.end).0.row + 1)
27203    } else {
27204        MultiBufferRow(next_selection.end.row)
27205    }
27206}
27207
27208impl EditorSnapshot {
27209    pub fn remote_selections_in_range<'a>(
27210        &'a self,
27211        range: &'a Range<Anchor>,
27212        collaboration_hub: &dyn CollaborationHub,
27213        cx: &'a App,
27214    ) -> impl 'a + Iterator<Item = RemoteSelection> {
27215        let participant_names = collaboration_hub.user_names(cx);
27216        let participant_indices = collaboration_hub.user_participant_indices(cx);
27217        let collaborators_by_peer_id = collaboration_hub.collaborators(cx);
27218        let collaborators_by_replica_id = collaborators_by_peer_id
27219            .values()
27220            .map(|collaborator| (collaborator.replica_id, collaborator))
27221            .collect::<HashMap<_, _>>();
27222        self.buffer_snapshot()
27223            .selections_in_range(range, false)
27224            .filter_map(move |(replica_id, line_mode, cursor_shape, selection)| {
27225                if replica_id == ReplicaId::AGENT {
27226                    Some(RemoteSelection {
27227                        replica_id,
27228                        selection,
27229                        cursor_shape,
27230                        line_mode,
27231                        collaborator_id: CollaboratorId::Agent,
27232                        user_name: Some("Agent".into()),
27233                        color: cx.theme().players().agent(),
27234                    })
27235                } else {
27236                    let collaborator = collaborators_by_replica_id.get(&replica_id)?;
27237                    let participant_index = participant_indices.get(&collaborator.user_id).copied();
27238                    let user_name = participant_names.get(&collaborator.user_id).cloned();
27239                    Some(RemoteSelection {
27240                        replica_id,
27241                        selection,
27242                        cursor_shape,
27243                        line_mode,
27244                        collaborator_id: CollaboratorId::PeerId(collaborator.peer_id),
27245                        user_name,
27246                        color: if let Some(index) = participant_index {
27247                            cx.theme().players().color_for_participant(index.0)
27248                        } else {
27249                            cx.theme().players().absent()
27250                        },
27251                    })
27252                }
27253            })
27254    }
27255
27256    pub fn hunks_for_ranges(
27257        &self,
27258        ranges: impl IntoIterator<Item = Range<Point>>,
27259    ) -> Vec<MultiBufferDiffHunk> {
27260        let mut hunks = Vec::new();
27261        let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
27262            HashMap::default();
27263        for query_range in ranges {
27264            let query_rows =
27265                MultiBufferRow(query_range.start.row)..MultiBufferRow(query_range.end.row + 1);
27266            for hunk in self.buffer_snapshot().diff_hunks_in_range(
27267                Point::new(query_rows.start.0, 0)..Point::new(query_rows.end.0, 0),
27268            ) {
27269                // Include deleted hunks that are adjacent to the query range, because
27270                // otherwise they would be missed.
27271                let mut intersects_range = hunk.row_range.overlaps(&query_rows);
27272                if hunk.status().is_deleted() {
27273                    intersects_range |= hunk.row_range.start == query_rows.end;
27274                    intersects_range |= hunk.row_range.end == query_rows.start;
27275                }
27276                if intersects_range {
27277                    if !processed_buffer_rows
27278                        .entry(hunk.buffer_id)
27279                        .or_default()
27280                        .insert(hunk.buffer_range.start..hunk.buffer_range.end)
27281                    {
27282                        continue;
27283                    }
27284                    hunks.push(hunk);
27285                }
27286            }
27287        }
27288
27289        hunks
27290    }
27291
27292    fn display_diff_hunks_for_rows<'a>(
27293        &'a self,
27294        display_rows: Range<DisplayRow>,
27295        folded_buffers: &'a HashSet<BufferId>,
27296    ) -> impl 'a + Iterator<Item = DisplayDiffHunk> {
27297        let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(self);
27298        let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(self);
27299
27300        self.buffer_snapshot()
27301            .diff_hunks_in_range(buffer_start..buffer_end)
27302            .filter_map(|hunk| {
27303                if folded_buffers.contains(&hunk.buffer_id)
27304                    || (hunk.row_range.is_empty() && self.buffer.all_diff_hunks_expanded())
27305                {
27306                    return None;
27307                }
27308
27309                let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
27310                let hunk_end_point = if hunk.row_range.end > hunk.row_range.start {
27311                    let last_row = MultiBufferRow(hunk.row_range.end.0 - 1);
27312                    let line_len = self.buffer_snapshot().line_len(last_row);
27313                    Point::new(last_row.0, line_len)
27314                } else {
27315                    Point::new(hunk.row_range.end.0, 0)
27316                };
27317
27318                let hunk_display_start = self.point_to_display_point(hunk_start_point, Bias::Left);
27319                let hunk_display_end = self.point_to_display_point(hunk_end_point, Bias::Right);
27320
27321                let display_hunk = if hunk_display_start.column() != 0 {
27322                    DisplayDiffHunk::Folded {
27323                        display_row: hunk_display_start.row(),
27324                    }
27325                } else {
27326                    let mut end_row = hunk_display_end.row();
27327                    if hunk.row_range.end > hunk.row_range.start || hunk_display_end.column() > 0 {
27328                        end_row.0 += 1;
27329                    }
27330                    let is_created_file = hunk.is_created_file();
27331
27332                    DisplayDiffHunk::Unfolded {
27333                        status: hunk.status(),
27334                        diff_base_byte_range: hunk.diff_base_byte_range.start.0
27335                            ..hunk.diff_base_byte_range.end.0,
27336                        word_diffs: hunk.word_diffs,
27337                        display_row_range: hunk_display_start.row()..end_row,
27338                        multi_buffer_range: Anchor::range_in_buffer(
27339                            hunk.excerpt_id,
27340                            hunk.buffer_range,
27341                        ),
27342                        is_created_file,
27343                    }
27344                };
27345
27346                Some(display_hunk)
27347            })
27348    }
27349
27350    pub fn language_at<T: ToOffset>(&self, position: T) -> Option<&Arc<Language>> {
27351        self.display_snapshot
27352            .buffer_snapshot()
27353            .language_at(position)
27354    }
27355
27356    pub fn is_focused(&self) -> bool {
27357        self.is_focused
27358    }
27359
27360    pub fn placeholder_text(&self) -> Option<String> {
27361        self.placeholder_display_snapshot
27362            .as_ref()
27363            .map(|display_map| display_map.text())
27364    }
27365
27366    pub fn scroll_position(&self) -> gpui::Point<ScrollOffset> {
27367        self.scroll_anchor.scroll_position(&self.display_snapshot)
27368    }
27369
27370    pub fn gutter_dimensions(
27371        &self,
27372        font_id: FontId,
27373        font_size: Pixels,
27374        style: &EditorStyle,
27375        window: &mut Window,
27376        cx: &App,
27377    ) -> GutterDimensions {
27378        if self.show_gutter
27379            && let Some(ch_width) = cx.text_system().ch_width(font_id, font_size).log_err()
27380            && let Some(ch_advance) = cx.text_system().ch_advance(font_id, font_size).log_err()
27381        {
27382            let show_git_gutter = self.show_git_diff_gutter.unwrap_or_else(|| {
27383                matches!(
27384                    ProjectSettings::get_global(cx).git.git_gutter,
27385                    GitGutterSetting::TrackedFiles
27386                )
27387            });
27388            let gutter_settings = EditorSettings::get_global(cx).gutter;
27389            let show_line_numbers = self
27390                .show_line_numbers
27391                .unwrap_or(gutter_settings.line_numbers);
27392            let line_gutter_width = if show_line_numbers {
27393                // Avoid flicker-like gutter resizes when the line number gains another digit by
27394                // only resizing the gutter on files with > 10**min_line_number_digits lines.
27395                let min_width_for_number_on_gutter =
27396                    ch_advance * gutter_settings.min_line_number_digits as f32;
27397                self.max_line_number_width(style, window)
27398                    .max(min_width_for_number_on_gutter)
27399            } else {
27400                0.0.into()
27401            };
27402
27403            let show_runnables = self.show_runnables.unwrap_or(gutter_settings.runnables);
27404            let show_breakpoints = self.show_breakpoints.unwrap_or(gutter_settings.breakpoints);
27405
27406            let git_blame_entries_width =
27407                self.git_blame_gutter_max_author_length
27408                    .map(|max_author_length| {
27409                        let renderer = cx.global::<GlobalBlameRenderer>().0.clone();
27410                        const MAX_RELATIVE_TIMESTAMP: &str = "60 minutes ago";
27411
27412                        /// The number of characters to dedicate to gaps and margins.
27413                        const SPACING_WIDTH: usize = 4;
27414
27415                        let max_char_count = max_author_length.min(renderer.max_author_length())
27416                            + ::git::SHORT_SHA_LENGTH
27417                            + MAX_RELATIVE_TIMESTAMP.len()
27418                            + SPACING_WIDTH;
27419
27420                        ch_advance * max_char_count
27421                    });
27422
27423            let is_singleton = self.buffer_snapshot().is_singleton();
27424
27425            let mut left_padding = git_blame_entries_width.unwrap_or(Pixels::ZERO);
27426            left_padding += if !is_singleton {
27427                ch_width * 4.0
27428            } else if show_runnables || show_breakpoints {
27429                ch_width * 3.0
27430            } else if show_git_gutter && show_line_numbers {
27431                ch_width * 2.0
27432            } else if show_git_gutter || show_line_numbers {
27433                ch_width
27434            } else {
27435                px(0.)
27436            };
27437
27438            let shows_folds = is_singleton && gutter_settings.folds;
27439
27440            let right_padding = if shows_folds && show_line_numbers {
27441                ch_width * 4.0
27442            } else if shows_folds || (!is_singleton && show_line_numbers) {
27443                ch_width * 3.0
27444            } else if show_line_numbers {
27445                ch_width
27446            } else {
27447                px(0.)
27448            };
27449
27450            GutterDimensions {
27451                left_padding,
27452                right_padding,
27453                width: line_gutter_width + left_padding + right_padding,
27454                margin: GutterDimensions::default_gutter_margin(font_id, font_size, cx),
27455                git_blame_entries_width,
27456            }
27457        } else if self.offset_content {
27458            GutterDimensions::default_with_margin(font_id, font_size, cx)
27459        } else {
27460            GutterDimensions::default()
27461        }
27462    }
27463
27464    pub fn render_crease_toggle(
27465        &self,
27466        buffer_row: MultiBufferRow,
27467        row_contains_cursor: bool,
27468        editor: Entity<Editor>,
27469        window: &mut Window,
27470        cx: &mut App,
27471    ) -> Option<AnyElement> {
27472        let folded = self.is_line_folded(buffer_row);
27473        let mut is_foldable = false;
27474
27475        if let Some(crease) = self
27476            .crease_snapshot
27477            .query_row(buffer_row, self.buffer_snapshot())
27478        {
27479            is_foldable = true;
27480            match crease {
27481                Crease::Inline { render_toggle, .. } | Crease::Block { render_toggle, .. } => {
27482                    if let Some(render_toggle) = render_toggle {
27483                        let toggle_callback =
27484                            Arc::new(move |folded, window: &mut Window, cx: &mut App| {
27485                                if folded {
27486                                    editor.update(cx, |editor, cx| {
27487                                        editor.fold_at(buffer_row, window, cx)
27488                                    });
27489                                } else {
27490                                    editor.update(cx, |editor, cx| {
27491                                        editor.unfold_at(buffer_row, window, cx)
27492                                    });
27493                                }
27494                            });
27495                        return Some((render_toggle)(
27496                            buffer_row,
27497                            folded,
27498                            toggle_callback,
27499                            window,
27500                            cx,
27501                        ));
27502                    }
27503                }
27504            }
27505        }
27506
27507        is_foldable |= !self.use_lsp_folding_ranges && self.starts_indent(buffer_row);
27508
27509        if folded || (is_foldable && (row_contains_cursor || self.gutter_hovered)) {
27510            Some(
27511                Disclosure::new(("gutter_crease", buffer_row.0), !folded)
27512                    .toggle_state(folded)
27513                    .on_click(window.listener_for(&editor, move |this, _e, window, cx| {
27514                        if folded {
27515                            this.unfold_at(buffer_row, window, cx);
27516                        } else {
27517                            this.fold_at(buffer_row, window, cx);
27518                        }
27519                    }))
27520                    .into_any_element(),
27521            )
27522        } else {
27523            None
27524        }
27525    }
27526
27527    pub fn render_crease_trailer(
27528        &self,
27529        buffer_row: MultiBufferRow,
27530        window: &mut Window,
27531        cx: &mut App,
27532    ) -> Option<AnyElement> {
27533        let folded = self.is_line_folded(buffer_row);
27534        if let Crease::Inline { render_trailer, .. } = self
27535            .crease_snapshot
27536            .query_row(buffer_row, self.buffer_snapshot())?
27537        {
27538            let render_trailer = render_trailer.as_ref()?;
27539            Some(render_trailer(buffer_row, folded, window, cx))
27540        } else {
27541            None
27542        }
27543    }
27544
27545    pub fn max_line_number_width(&self, style: &EditorStyle, window: &mut Window) -> Pixels {
27546        let digit_count = self.widest_line_number().ilog10() + 1;
27547        column_pixels(style, digit_count as usize, window)
27548    }
27549
27550    /// Returns the line delta from `base` to `line` in the multibuffer, ignoring wrapped lines.
27551    ///
27552    /// This is positive if `base` is before `line`.
27553    fn relative_line_delta(
27554        &self,
27555        current_selection_head: DisplayRow,
27556        first_visible_row: DisplayRow,
27557        consider_wrapped_lines: bool,
27558    ) -> i64 {
27559        let current_selection_head = current_selection_head.as_display_point().to_point(self);
27560        let first_visible_row = first_visible_row.as_display_point().to_point(self);
27561
27562        if consider_wrapped_lines {
27563            let wrap_snapshot = self.wrap_snapshot();
27564            let base_wrap_row = wrap_snapshot
27565                .make_wrap_point(current_selection_head, Bias::Left)
27566                .row();
27567            let wrap_row = wrap_snapshot
27568                .make_wrap_point(first_visible_row, Bias::Left)
27569                .row();
27570
27571            wrap_row.0 as i64 - base_wrap_row.0 as i64
27572        } else {
27573            let fold_snapshot = self.fold_snapshot();
27574            let base_fold_row = fold_snapshot
27575                .to_fold_point(self.to_inlay_point(current_selection_head), Bias::Left)
27576                .row();
27577            let fold_row = fold_snapshot
27578                .to_fold_point(self.to_inlay_point(first_visible_row), Bias::Left)
27579                .row();
27580
27581            fold_row as i64 - base_fold_row as i64
27582        }
27583    }
27584
27585    /// Returns the unsigned relative line number to display for each row in `rows`.
27586    ///
27587    /// Wrapped rows are excluded from the hashmap if `count_relative_lines` is `false`.
27588    pub fn calculate_relative_line_numbers(
27589        &self,
27590        rows: &Range<DisplayRow>,
27591        current_selection_head: DisplayRow,
27592        count_wrapped_lines: bool,
27593    ) -> HashMap<DisplayRow, u32> {
27594        let initial_offset =
27595            self.relative_line_delta(current_selection_head, rows.start, count_wrapped_lines);
27596
27597        self.row_infos(rows.start)
27598            .take(rows.len())
27599            .enumerate()
27600            .map(|(i, row_info)| (DisplayRow(rows.start.0 + i as u32), row_info))
27601            .filter(|(_row, row_info)| {
27602                row_info.buffer_row.is_some()
27603                    || (count_wrapped_lines && row_info.wrapped_buffer_row.is_some())
27604            })
27605            .enumerate()
27606            .filter_map(|(i, (row, row_info))| {
27607                // We want to ensure here that the current line has absolute
27608                // numbering, even if we are in a soft-wrapped line. With the
27609                // exception that if we are in a deleted line, we should number this
27610                // relative with 0, as otherwise it would have no line number at all
27611                let relative_line_number = (initial_offset + i as i64).unsigned_abs() as u32;
27612
27613                (relative_line_number != 0
27614                    || row_info
27615                        .diff_status
27616                        .is_some_and(|status| status.is_deleted()))
27617                .then_some((row, relative_line_number))
27618            })
27619            .collect()
27620    }
27621}
27622
27623pub fn column_pixels(style: &EditorStyle, column: usize, window: &Window) -> Pixels {
27624    let font_size = style.text.font_size.to_pixels(window.rem_size());
27625    let layout = window.text_system().shape_line(
27626        SharedString::from(" ".repeat(column)),
27627        font_size,
27628        &[TextRun {
27629            len: column,
27630            font: style.text.font(),
27631            color: Hsla::default(),
27632            ..Default::default()
27633        }],
27634        None,
27635    );
27636
27637    layout.width
27638}
27639
27640impl Deref for EditorSnapshot {
27641    type Target = DisplaySnapshot;
27642
27643    fn deref(&self) -> &Self::Target {
27644        &self.display_snapshot
27645    }
27646}
27647
27648#[derive(Clone, Debug, PartialEq, Eq)]
27649pub enum EditorEvent {
27650    /// Emitted when the stored review comments change (added, removed, or updated).
27651    ReviewCommentsChanged {
27652        /// The new total count of review comments.
27653        total_count: usize,
27654    },
27655    InputIgnored {
27656        text: Arc<str>,
27657    },
27658    InputHandled {
27659        utf16_range_to_replace: Option<Range<isize>>,
27660        text: Arc<str>,
27661    },
27662    ExcerptsAdded {
27663        buffer: Entity<Buffer>,
27664        predecessor: ExcerptId,
27665        excerpts: Vec<(ExcerptId, ExcerptRange<language::Anchor>)>,
27666    },
27667    ExcerptsRemoved {
27668        ids: Vec<ExcerptId>,
27669        removed_buffer_ids: Vec<BufferId>,
27670    },
27671    BufferFoldToggled {
27672        ids: Vec<ExcerptId>,
27673        folded: bool,
27674    },
27675    ExcerptsEdited {
27676        ids: Vec<ExcerptId>,
27677    },
27678    ExcerptsExpanded {
27679        ids: Vec<ExcerptId>,
27680    },
27681    ExpandExcerptsRequested {
27682        excerpt_ids: Vec<ExcerptId>,
27683        lines: u32,
27684        direction: ExpandExcerptDirection,
27685    },
27686    StageOrUnstageRequested {
27687        stage: bool,
27688        hunks: Vec<MultiBufferDiffHunk>,
27689    },
27690    OpenExcerptsRequested {
27691        selections_by_buffer: HashMap<BufferId, (Vec<Range<BufferOffset>>, Option<u32>)>,
27692        split: bool,
27693    },
27694    RestoreRequested {
27695        hunks: Vec<MultiBufferDiffHunk>,
27696    },
27697    BufferEdited,
27698    Edited {
27699        transaction_id: clock::Lamport,
27700    },
27701    Reparsed(BufferId),
27702    Focused,
27703    FocusedIn,
27704    Blurred,
27705    DirtyChanged,
27706    Saved,
27707    TitleChanged,
27708    SelectionsChanged {
27709        local: bool,
27710    },
27711    ScrollPositionChanged {
27712        local: bool,
27713        autoscroll: bool,
27714    },
27715    TransactionUndone {
27716        transaction_id: clock::Lamport,
27717    },
27718    TransactionBegun {
27719        transaction_id: clock::Lamport,
27720    },
27721    CursorShapeChanged,
27722    BreadcrumbsChanged,
27723    OutlineSymbolsChanged,
27724    PushedToNavHistory {
27725        anchor: Anchor,
27726        is_deactivate: bool,
27727    },
27728}
27729
27730impl EventEmitter<EditorEvent> for Editor {}
27731
27732impl Focusable for Editor {
27733    fn focus_handle(&self, _cx: &App) -> FocusHandle {
27734        self.focus_handle.clone()
27735    }
27736}
27737
27738impl Render for Editor {
27739    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
27740        EditorElement::new(&cx.entity(), self.create_style(cx))
27741    }
27742}
27743
27744impl EntityInputHandler for Editor {
27745    fn text_for_range(
27746        &mut self,
27747        range_utf16: Range<usize>,
27748        adjusted_range: &mut Option<Range<usize>>,
27749        _: &mut Window,
27750        cx: &mut Context<Self>,
27751    ) -> Option<String> {
27752        let snapshot = self.buffer.read(cx).read(cx);
27753        let start = snapshot.clip_offset_utf16(
27754            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)),
27755            Bias::Left,
27756        );
27757        let end = snapshot.clip_offset_utf16(
27758            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end)),
27759            Bias::Right,
27760        );
27761        if (start.0.0..end.0.0) != range_utf16 {
27762            adjusted_range.replace(start.0.0..end.0.0);
27763        }
27764        Some(snapshot.text_for_range(start..end).collect())
27765    }
27766
27767    fn selected_text_range(
27768        &mut self,
27769        ignore_disabled_input: bool,
27770        _: &mut Window,
27771        cx: &mut Context<Self>,
27772    ) -> Option<UTF16Selection> {
27773        // Prevent the IME menu from appearing when holding down an alphabetic key
27774        // while input is disabled.
27775        if !ignore_disabled_input && !self.input_enabled {
27776            return None;
27777        }
27778
27779        let selection = self
27780            .selections
27781            .newest::<MultiBufferOffsetUtf16>(&self.display_snapshot(cx));
27782        let range = selection.range();
27783
27784        Some(UTF16Selection {
27785            range: range.start.0.0..range.end.0.0,
27786            reversed: selection.reversed,
27787        })
27788    }
27789
27790    fn marked_text_range(&self, _: &mut Window, cx: &mut Context<Self>) -> Option<Range<usize>> {
27791        let snapshot = self.buffer.read(cx).read(cx);
27792        let range = self
27793            .text_highlights(HighlightKey::InputComposition, cx)?
27794            .1
27795            .first()?;
27796        Some(range.start.to_offset_utf16(&snapshot).0.0..range.end.to_offset_utf16(&snapshot).0.0)
27797    }
27798
27799    fn unmark_text(&mut self, _: &mut Window, cx: &mut Context<Self>) {
27800        self.clear_highlights(HighlightKey::InputComposition, cx);
27801        self.ime_transaction.take();
27802    }
27803
27804    fn replace_text_in_range(
27805        &mut self,
27806        range_utf16: Option<Range<usize>>,
27807        text: &str,
27808        window: &mut Window,
27809        cx: &mut Context<Self>,
27810    ) {
27811        if !self.input_enabled {
27812            cx.emit(EditorEvent::InputIgnored { text: text.into() });
27813            return;
27814        }
27815
27816        self.transact(window, cx, |this, window, cx| {
27817            let new_selected_ranges = if let Some(range_utf16) = range_utf16 {
27818                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27819                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27820                Some(this.selection_replacement_ranges(range_utf16, cx))
27821            } else {
27822                this.marked_text_ranges(cx)
27823            };
27824
27825            let range_to_replace = new_selected_ranges.as_ref().and_then(|ranges_to_replace| {
27826                let newest_selection_id = this.selections.newest_anchor().id;
27827                this.selections
27828                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27829                    .iter()
27830                    .zip(ranges_to_replace.iter())
27831                    .find_map(|(selection, range)| {
27832                        if selection.id == newest_selection_id {
27833                            Some(
27834                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27835                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27836                            )
27837                        } else {
27838                            None
27839                        }
27840                    })
27841            });
27842
27843            cx.emit(EditorEvent::InputHandled {
27844                utf16_range_to_replace: range_to_replace,
27845                text: text.into(),
27846            });
27847
27848            if let Some(new_selected_ranges) = new_selected_ranges {
27849                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27850                    selections.select_ranges(new_selected_ranges)
27851                });
27852                this.backspace(&Default::default(), window, cx);
27853            }
27854
27855            this.handle_input(text, window, cx);
27856        });
27857
27858        if let Some(transaction) = self.ime_transaction {
27859            self.buffer.update(cx, |buffer, cx| {
27860                buffer.group_until_transaction(transaction, cx);
27861            });
27862        }
27863
27864        self.unmark_text(window, cx);
27865    }
27866
27867    fn replace_and_mark_text_in_range(
27868        &mut self,
27869        range_utf16: Option<Range<usize>>,
27870        text: &str,
27871        new_selected_range_utf16: Option<Range<usize>>,
27872        window: &mut Window,
27873        cx: &mut Context<Self>,
27874    ) {
27875        if !self.input_enabled {
27876            return;
27877        }
27878
27879        let transaction = self.transact(window, cx, |this, window, cx| {
27880            let ranges_to_replace = if let Some(mut marked_ranges) = this.marked_text_ranges(cx) {
27881                let snapshot = this.buffer.read(cx).read(cx);
27882                if let Some(relative_range_utf16) = range_utf16.as_ref() {
27883                    for marked_range in &mut marked_ranges {
27884                        marked_range.end = marked_range.start + relative_range_utf16.end;
27885                        marked_range.start += relative_range_utf16.start;
27886                        marked_range.start =
27887                            snapshot.clip_offset_utf16(marked_range.start, Bias::Left);
27888                        marked_range.end =
27889                            snapshot.clip_offset_utf16(marked_range.end, Bias::Right);
27890                    }
27891                }
27892                Some(marked_ranges)
27893            } else if let Some(range_utf16) = range_utf16 {
27894                let range_utf16 = MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start))
27895                    ..MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.end));
27896                Some(this.selection_replacement_ranges(range_utf16, cx))
27897            } else {
27898                None
27899            };
27900
27901            let range_to_replace = ranges_to_replace.as_ref().and_then(|ranges_to_replace| {
27902                let newest_selection_id = this.selections.newest_anchor().id;
27903                this.selections
27904                    .all::<MultiBufferOffsetUtf16>(&this.display_snapshot(cx))
27905                    .iter()
27906                    .zip(ranges_to_replace.iter())
27907                    .find_map(|(selection, range)| {
27908                        if selection.id == newest_selection_id {
27909                            Some(
27910                                (range.start.0.0 as isize - selection.head().0.0 as isize)
27911                                    ..(range.end.0.0 as isize - selection.head().0.0 as isize),
27912                            )
27913                        } else {
27914                            None
27915                        }
27916                    })
27917            });
27918
27919            cx.emit(EditorEvent::InputHandled {
27920                utf16_range_to_replace: range_to_replace,
27921                text: text.into(),
27922            });
27923
27924            if let Some(ranges) = ranges_to_replace {
27925                this.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
27926                    s.select_ranges(ranges)
27927                });
27928            }
27929
27930            let marked_ranges = {
27931                let snapshot = this.buffer.read(cx).read(cx);
27932                this.selections
27933                    .disjoint_anchors_arc()
27934                    .iter()
27935                    .map(|selection| {
27936                        selection.start.bias_left(&snapshot)..selection.end.bias_right(&snapshot)
27937                    })
27938                    .collect::<Vec<_>>()
27939            };
27940
27941            if text.is_empty() {
27942                this.unmark_text(window, cx);
27943            } else {
27944                this.highlight_text(
27945                    HighlightKey::InputComposition,
27946                    marked_ranges.clone(),
27947                    HighlightStyle {
27948                        underline: Some(UnderlineStyle {
27949                            thickness: px(1.),
27950                            color: None,
27951                            wavy: false,
27952                        }),
27953                        ..Default::default()
27954                    },
27955                    cx,
27956                );
27957            }
27958
27959            // Disable auto-closing when composing text (i.e. typing a `"` on a Brazilian keyboard)
27960            let use_autoclose = this.use_autoclose;
27961            let use_auto_surround = this.use_auto_surround;
27962            this.set_use_autoclose(false);
27963            this.set_use_auto_surround(false);
27964            this.handle_input(text, window, cx);
27965            this.set_use_autoclose(use_autoclose);
27966            this.set_use_auto_surround(use_auto_surround);
27967
27968            if let Some(new_selected_range) = new_selected_range_utf16 {
27969                let snapshot = this.buffer.read(cx).read(cx);
27970                let new_selected_ranges = marked_ranges
27971                    .into_iter()
27972                    .map(|marked_range| {
27973                        let insertion_start = marked_range.start.to_offset_utf16(&snapshot).0;
27974                        let new_start = MultiBufferOffsetUtf16(OffsetUtf16(
27975                            insertion_start.0 + new_selected_range.start,
27976                        ));
27977                        let new_end = MultiBufferOffsetUtf16(OffsetUtf16(
27978                            insertion_start.0 + new_selected_range.end,
27979                        ));
27980                        snapshot.clip_offset_utf16(new_start, Bias::Left)
27981                            ..snapshot.clip_offset_utf16(new_end, Bias::Right)
27982                    })
27983                    .collect::<Vec<_>>();
27984
27985                drop(snapshot);
27986                this.change_selections(SelectionEffects::no_scroll(), window, cx, |selections| {
27987                    selections.select_ranges(new_selected_ranges)
27988                });
27989            }
27990        });
27991
27992        self.ime_transaction = self.ime_transaction.or(transaction);
27993        if let Some(transaction) = self.ime_transaction {
27994            self.buffer.update(cx, |buffer, cx| {
27995                buffer.group_until_transaction(transaction, cx);
27996            });
27997        }
27998
27999        if self
28000            .text_highlights(HighlightKey::InputComposition, cx)
28001            .is_none()
28002        {
28003            self.ime_transaction.take();
28004        }
28005    }
28006
28007    fn bounds_for_range(
28008        &mut self,
28009        range_utf16: Range<usize>,
28010        element_bounds: gpui::Bounds<Pixels>,
28011        window: &mut Window,
28012        cx: &mut Context<Self>,
28013    ) -> Option<gpui::Bounds<Pixels>> {
28014        let text_layout_details = self.text_layout_details(window, cx);
28015        let CharacterDimensions {
28016            em_width,
28017            em_advance,
28018            line_height,
28019        } = self.character_dimensions(window, cx);
28020
28021        let snapshot = self.snapshot(window, cx);
28022        let scroll_position = snapshot.scroll_position();
28023        let scroll_left = scroll_position.x * ScrollOffset::from(em_advance);
28024
28025        let start =
28026            MultiBufferOffsetUtf16(OffsetUtf16(range_utf16.start)).to_display_point(&snapshot);
28027        let x = Pixels::from(
28028            ScrollOffset::from(
28029                snapshot.x_for_display_point(start, &text_layout_details)
28030                    + self.gutter_dimensions.full_width(),
28031            ) - scroll_left,
28032        );
28033        let y = line_height * (start.row().as_f64() - scroll_position.y) as f32;
28034
28035        Some(Bounds {
28036            origin: element_bounds.origin + point(x, y),
28037            size: size(em_width, line_height),
28038        })
28039    }
28040
28041    fn character_index_for_point(
28042        &mut self,
28043        point: gpui::Point<Pixels>,
28044        _window: &mut Window,
28045        _cx: &mut Context<Self>,
28046    ) -> Option<usize> {
28047        let position_map = self.last_position_map.as_ref()?;
28048        if !position_map.text_hitbox.contains(&point) {
28049            return None;
28050        }
28051        let display_point = position_map.point_for_position(point).previous_valid;
28052        let anchor = position_map
28053            .snapshot
28054            .display_point_to_anchor(display_point, Bias::Left);
28055        let utf16_offset = anchor.to_offset_utf16(&position_map.snapshot.buffer_snapshot());
28056        Some(utf16_offset.0.0)
28057    }
28058
28059    fn accepts_text_input(&self, _window: &mut Window, _cx: &mut Context<Self>) -> bool {
28060        self.expects_character_input
28061    }
28062}
28063
28064trait SelectionExt {
28065    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint>;
28066    fn spanned_rows(
28067        &self,
28068        include_end_if_at_line_start: bool,
28069        map: &DisplaySnapshot,
28070    ) -> Range<MultiBufferRow>;
28071}
28072
28073impl<T: ToPoint + ToOffset> SelectionExt for Selection<T> {
28074    fn display_range(&self, map: &DisplaySnapshot) -> Range<DisplayPoint> {
28075        let start = self
28076            .start
28077            .to_point(map.buffer_snapshot())
28078            .to_display_point(map);
28079        let end = self
28080            .end
28081            .to_point(map.buffer_snapshot())
28082            .to_display_point(map);
28083        if self.reversed {
28084            end..start
28085        } else {
28086            start..end
28087        }
28088    }
28089
28090    fn spanned_rows(
28091        &self,
28092        include_end_if_at_line_start: bool,
28093        map: &DisplaySnapshot,
28094    ) -> Range<MultiBufferRow> {
28095        let start = self.start.to_point(map.buffer_snapshot());
28096        let mut end = self.end.to_point(map.buffer_snapshot());
28097        if !include_end_if_at_line_start && start.row != end.row && end.column == 0 {
28098            end.row -= 1;
28099        }
28100
28101        let buffer_start = map.prev_line_boundary(start).0;
28102        let buffer_end = map.next_line_boundary(end).0;
28103        MultiBufferRow(buffer_start.row)..MultiBufferRow(buffer_end.row + 1)
28104    }
28105}
28106
28107impl<T: InvalidationRegion> InvalidationStack<T> {
28108    fn invalidate<S>(&mut self, selections: &[Selection<S>], buffer: &MultiBufferSnapshot)
28109    where
28110        S: Clone + ToOffset,
28111    {
28112        while let Some(region) = self.last() {
28113            let all_selections_inside_invalidation_ranges =
28114                if selections.len() == region.ranges().len() {
28115                    selections
28116                        .iter()
28117                        .zip(region.ranges().iter().map(|r| r.to_offset(buffer)))
28118                        .all(|(selection, invalidation_range)| {
28119                            let head = selection.head().to_offset(buffer);
28120                            invalidation_range.start <= head && invalidation_range.end >= head
28121                        })
28122                } else {
28123                    false
28124                };
28125
28126            if all_selections_inside_invalidation_ranges {
28127                break;
28128            } else {
28129                self.pop();
28130            }
28131        }
28132    }
28133}
28134
28135#[derive(Clone)]
28136struct ErasedEditorImpl(Entity<Editor>);
28137
28138impl ui_input::ErasedEditor for ErasedEditorImpl {
28139    fn text(&self, cx: &App) -> String {
28140        self.0.read(cx).text(cx)
28141    }
28142
28143    fn set_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28144        self.0.update(cx, |this, cx| {
28145            this.set_text(text, window, cx);
28146        })
28147    }
28148
28149    fn clear(&self, window: &mut Window, cx: &mut App) {
28150        self.0.update(cx, |this, cx| this.clear(window, cx));
28151    }
28152
28153    fn set_placeholder_text(&self, text: &str, window: &mut Window, cx: &mut App) {
28154        self.0.update(cx, |this, cx| {
28155            this.set_placeholder_text(text, window, cx);
28156        });
28157    }
28158
28159    fn focus_handle(&self, cx: &App) -> FocusHandle {
28160        self.0.read(cx).focus_handle(cx)
28161    }
28162
28163    fn render(&self, _: &mut Window, cx: &App) -> AnyElement {
28164        let settings = ThemeSettings::get_global(cx);
28165        let theme_color = cx.theme().colors();
28166
28167        let text_style = TextStyle {
28168            font_family: settings.ui_font.family.clone(),
28169            font_features: settings.ui_font.features.clone(),
28170            font_size: rems(0.875).into(),
28171            font_weight: settings.ui_font.weight,
28172            font_style: FontStyle::Normal,
28173            line_height: relative(1.2),
28174            color: theme_color.text,
28175            ..Default::default()
28176        };
28177        let editor_style = EditorStyle {
28178            background: theme_color.ghost_element_background,
28179            local_player: cx.theme().players().local(),
28180            syntax: cx.theme().syntax().clone(),
28181            text: text_style,
28182            ..Default::default()
28183        };
28184        EditorElement::new(&self.0, editor_style).into_any()
28185    }
28186
28187    fn as_any(&self) -> &dyn Any {
28188        &self.0
28189    }
28190
28191    fn move_selection_to_end(&self, window: &mut Window, cx: &mut App) {
28192        self.0.update(cx, |editor, cx| {
28193            let editor_offset = editor.buffer().read(cx).len(cx);
28194            editor.change_selections(
28195                SelectionEffects::scroll(Autoscroll::Next),
28196                window,
28197                cx,
28198                |s| s.select_ranges(Some(editor_offset..editor_offset)),
28199            );
28200        });
28201    }
28202
28203    fn subscribe(
28204        &self,
28205        mut callback: Box<dyn FnMut(ui_input::ErasedEditorEvent, &mut Window, &mut App) + 'static>,
28206        window: &mut Window,
28207        cx: &mut App,
28208    ) -> Subscription {
28209        window.subscribe(&self.0, cx, move |_, event: &EditorEvent, window, cx| {
28210            let event = match event {
28211                EditorEvent::BufferEdited => ui_input::ErasedEditorEvent::BufferEdited,
28212                EditorEvent::Blurred => ui_input::ErasedEditorEvent::Blurred,
28213                _ => return,
28214            };
28215            (callback)(event, window, cx);
28216        })
28217    }
28218
28219    fn set_masked(&self, masked: bool, _window: &mut Window, cx: &mut App) {
28220        self.0.update(cx, |editor, cx| {
28221            editor.set_masked(masked, cx);
28222        });
28223    }
28224}
28225impl<T> Default for InvalidationStack<T> {
28226    fn default() -> Self {
28227        Self(Default::default())
28228    }
28229}
28230
28231impl<T> Deref for InvalidationStack<T> {
28232    type Target = Vec<T>;
28233
28234    fn deref(&self) -> &Self::Target {
28235        &self.0
28236    }
28237}
28238
28239impl<T> DerefMut for InvalidationStack<T> {
28240    fn deref_mut(&mut self) -> &mut Self::Target {
28241        &mut self.0
28242    }
28243}
28244
28245impl InvalidationRegion for SnippetState {
28246    fn ranges(&self) -> &[Range<Anchor>] {
28247        &self.ranges[self.active_index]
28248    }
28249}
28250
28251fn edit_prediction_edit_text(
28252    current_snapshot: &BufferSnapshot,
28253    edits: &[(Range<Anchor>, impl AsRef<str>)],
28254    edit_preview: &EditPreview,
28255    include_deletions: bool,
28256    cx: &App,
28257) -> HighlightedText {
28258    let edits = edits
28259        .iter()
28260        .map(|(anchor, text)| (anchor.start.text_anchor..anchor.end.text_anchor, text))
28261        .collect::<Vec<_>>();
28262
28263    edit_preview.highlight_edits(current_snapshot, &edits, include_deletions, cx)
28264}
28265
28266fn edit_prediction_fallback_text(edits: &[(Range<Anchor>, Arc<str>)], cx: &App) -> HighlightedText {
28267    // Fallback for providers that don't provide edit_preview (like Copilot)
28268    // Just show the raw edit text with basic styling
28269    let mut text = String::new();
28270    let mut highlights = Vec::new();
28271
28272    let insertion_highlight_style = HighlightStyle {
28273        color: Some(cx.theme().colors().text),
28274        ..Default::default()
28275    };
28276
28277    for (_, edit_text) in edits {
28278        let start_offset = text.len();
28279        text.push_str(edit_text);
28280        let end_offset = text.len();
28281
28282        if start_offset < end_offset {
28283            highlights.push((start_offset..end_offset, insertion_highlight_style));
28284        }
28285    }
28286
28287    HighlightedText {
28288        text: text.into(),
28289        highlights,
28290    }
28291}
28292
28293pub fn diagnostic_style(severity: lsp::DiagnosticSeverity, colors: &StatusColors) -> Hsla {
28294    match severity {
28295        lsp::DiagnosticSeverity::ERROR => colors.error,
28296        lsp::DiagnosticSeverity::WARNING => colors.warning,
28297        lsp::DiagnosticSeverity::INFORMATION => colors.info,
28298        lsp::DiagnosticSeverity::HINT => colors.info,
28299        _ => colors.ignored,
28300    }
28301}
28302
28303pub fn styled_runs_for_code_label<'a>(
28304    label: &'a CodeLabel,
28305    syntax_theme: &'a theme::SyntaxTheme,
28306    local_player: &'a theme::PlayerColor,
28307) -> impl 'a + Iterator<Item = (Range<usize>, HighlightStyle)> {
28308    let fade_out = HighlightStyle {
28309        fade_out: Some(0.35),
28310        ..Default::default()
28311    };
28312
28313    let mut prev_end = label.filter_range.end;
28314    label
28315        .runs
28316        .iter()
28317        .enumerate()
28318        .flat_map(move |(ix, (range, highlight_id))| {
28319            let style = if *highlight_id == language::HighlightId::TABSTOP_INSERT_ID {
28320                HighlightStyle {
28321                    color: Some(local_player.cursor),
28322                    ..Default::default()
28323                }
28324            } else if *highlight_id == language::HighlightId::TABSTOP_REPLACE_ID {
28325                HighlightStyle {
28326                    background_color: Some(local_player.selection),
28327                    ..Default::default()
28328                }
28329            } else if let Some(style) = highlight_id.style(syntax_theme) {
28330                style
28331            } else {
28332                return Default::default();
28333            };
28334            let muted_style = style.highlight(fade_out);
28335
28336            let mut runs = SmallVec::<[(Range<usize>, HighlightStyle); 3]>::new();
28337            if range.start >= label.filter_range.end {
28338                if range.start > prev_end {
28339                    runs.push((prev_end..range.start, fade_out));
28340                }
28341                runs.push((range.clone(), muted_style));
28342            } else if range.end <= label.filter_range.end {
28343                runs.push((range.clone(), style));
28344            } else {
28345                runs.push((range.start..label.filter_range.end, style));
28346                runs.push((label.filter_range.end..range.end, muted_style));
28347            }
28348            prev_end = cmp::max(prev_end, range.end);
28349
28350            if ix + 1 == label.runs.len() && label.text.len() > prev_end {
28351                runs.push((prev_end..label.text.len(), fade_out));
28352            }
28353
28354            runs
28355        })
28356}
28357
28358pub(crate) fn split_words(text: &str) -> impl std::iter::Iterator<Item = &str> + '_ {
28359    let mut prev_index = 0;
28360    let mut prev_codepoint: Option<char> = None;
28361    text.char_indices()
28362        .chain([(text.len(), '\0')])
28363        .filter_map(move |(index, codepoint)| {
28364            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28365            let is_boundary = index == text.len()
28366                || !prev_codepoint.is_uppercase() && codepoint.is_uppercase()
28367                || !prev_codepoint.is_alphanumeric() && codepoint.is_alphanumeric();
28368            if is_boundary {
28369                let chunk = &text[prev_index..index];
28370                prev_index = index;
28371                Some(chunk)
28372            } else {
28373                None
28374            }
28375        })
28376}
28377
28378/// Given a string of text immediately before the cursor, iterates over possible
28379/// strings a snippet could match to. More precisely: returns an iterator over
28380/// suffixes of `text` created by splitting at word boundaries (before & after
28381/// every non-word character).
28382///
28383/// Shorter suffixes are returned first.
28384pub(crate) fn snippet_candidate_suffixes<'a>(
28385    text: &'a str,
28386    is_word_char: &'a dyn Fn(char) -> bool,
28387) -> impl std::iter::Iterator<Item = &'a str> + 'a {
28388    let mut prev_index = text.len();
28389    let mut prev_codepoint = None;
28390    text.char_indices()
28391        .rev()
28392        .chain([(0, '\0')])
28393        .filter_map(move |(index, codepoint)| {
28394            let prev_index = std::mem::replace(&mut prev_index, index);
28395            let prev_codepoint = prev_codepoint.replace(codepoint)?;
28396            if is_word_char(prev_codepoint) && is_word_char(codepoint) {
28397                None
28398            } else {
28399                let chunk = &text[prev_index..]; // go to end of string
28400                Some(chunk)
28401            }
28402        })
28403}
28404
28405pub trait RangeToAnchorExt: Sized {
28406    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor>;
28407
28408    fn to_display_points(self, snapshot: &EditorSnapshot) -> Range<DisplayPoint> {
28409        let anchor_range = self.to_anchors(&snapshot.buffer_snapshot());
28410        anchor_range.start.to_display_point(snapshot)..anchor_range.end.to_display_point(snapshot)
28411    }
28412}
28413
28414impl<T: ToOffset> RangeToAnchorExt for Range<T> {
28415    fn to_anchors(self, snapshot: &MultiBufferSnapshot) -> Range<Anchor> {
28416        let start_offset = self.start.to_offset(snapshot);
28417        let end_offset = self.end.to_offset(snapshot);
28418        if start_offset == end_offset {
28419            snapshot.anchor_before(start_offset)..snapshot.anchor_before(end_offset)
28420        } else {
28421            snapshot.anchor_after(self.start)..snapshot.anchor_before(self.end)
28422        }
28423    }
28424}
28425
28426pub trait RowExt {
28427    fn as_f64(&self) -> f64;
28428
28429    fn next_row(&self) -> Self;
28430
28431    fn previous_row(&self) -> Self;
28432
28433    fn minus(&self, other: Self) -> u32;
28434}
28435
28436impl RowExt for DisplayRow {
28437    fn as_f64(&self) -> f64 {
28438        self.0 as _
28439    }
28440
28441    fn next_row(&self) -> Self {
28442        Self(self.0 + 1)
28443    }
28444
28445    fn previous_row(&self) -> Self {
28446        Self(self.0.saturating_sub(1))
28447    }
28448
28449    fn minus(&self, other: Self) -> u32 {
28450        self.0 - other.0
28451    }
28452}
28453
28454impl RowExt for MultiBufferRow {
28455    fn as_f64(&self) -> f64 {
28456        self.0 as _
28457    }
28458
28459    fn next_row(&self) -> Self {
28460        Self(self.0 + 1)
28461    }
28462
28463    fn previous_row(&self) -> Self {
28464        Self(self.0.saturating_sub(1))
28465    }
28466
28467    fn minus(&self, other: Self) -> u32 {
28468        self.0 - other.0
28469    }
28470}
28471
28472trait RowRangeExt {
28473    type Row;
28474
28475    fn len(&self) -> usize;
28476
28477    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = Self::Row>;
28478}
28479
28480impl RowRangeExt for Range<MultiBufferRow> {
28481    type Row = MultiBufferRow;
28482
28483    fn len(&self) -> usize {
28484        (self.end.0 - self.start.0) as usize
28485    }
28486
28487    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = MultiBufferRow> {
28488        (self.start.0..self.end.0).map(MultiBufferRow)
28489    }
28490}
28491
28492impl RowRangeExt for Range<DisplayRow> {
28493    type Row = DisplayRow;
28494
28495    fn len(&self) -> usize {
28496        (self.end.0 - self.start.0) as usize
28497    }
28498
28499    fn iter_rows(&self) -> impl DoubleEndedIterator<Item = DisplayRow> {
28500        (self.start.0..self.end.0).map(DisplayRow)
28501    }
28502}
28503
28504/// If select range has more than one line, we
28505/// just point the cursor to range.start.
28506fn collapse_multiline_range(range: Range<Point>) -> Range<Point> {
28507    if range.start.row == range.end.row {
28508        range
28509    } else {
28510        range.start..range.start
28511    }
28512}
28513pub struct KillRing(ClipboardItem);
28514impl Global for KillRing {}
28515
28516const UPDATE_DEBOUNCE: Duration = Duration::from_millis(50);
28517
28518enum BreakpointPromptEditAction {
28519    Log,
28520    Condition,
28521    HitCondition,
28522}
28523
28524struct BreakpointPromptEditor {
28525    pub(crate) prompt: Entity<Editor>,
28526    editor: WeakEntity<Editor>,
28527    breakpoint_anchor: Anchor,
28528    breakpoint: Breakpoint,
28529    edit_action: BreakpointPromptEditAction,
28530    block_ids: HashSet<CustomBlockId>,
28531    editor_margins: Arc<Mutex<EditorMargins>>,
28532    _subscriptions: Vec<Subscription>,
28533}
28534
28535impl BreakpointPromptEditor {
28536    const MAX_LINES: u8 = 4;
28537
28538    fn new(
28539        editor: WeakEntity<Editor>,
28540        breakpoint_anchor: Anchor,
28541        breakpoint: Breakpoint,
28542        edit_action: BreakpointPromptEditAction,
28543        window: &mut Window,
28544        cx: &mut Context<Self>,
28545    ) -> Self {
28546        let base_text = match edit_action {
28547            BreakpointPromptEditAction::Log => breakpoint.message.as_ref(),
28548            BreakpointPromptEditAction::Condition => breakpoint.condition.as_ref(),
28549            BreakpointPromptEditAction::HitCondition => breakpoint.hit_condition.as_ref(),
28550        }
28551        .map(|msg| msg.to_string())
28552        .unwrap_or_default();
28553
28554        let buffer = cx.new(|cx| Buffer::local(base_text, cx));
28555        let buffer = cx.new(|cx| MultiBuffer::singleton(buffer, cx));
28556
28557        let prompt = cx.new(|cx| {
28558            let mut prompt = Editor::new(
28559                EditorMode::AutoHeight {
28560                    min_lines: 1,
28561                    max_lines: Some(Self::MAX_LINES as usize),
28562                },
28563                buffer,
28564                None,
28565                window,
28566                cx,
28567            );
28568            prompt.set_soft_wrap_mode(language::language_settings::SoftWrap::EditorWidth, cx);
28569            prompt.set_show_cursor_when_unfocused(false, cx);
28570            prompt.set_placeholder_text(
28571                match edit_action {
28572                    BreakpointPromptEditAction::Log => "Message to log when a breakpoint is hit. Expressions within {} are interpolated.",
28573                    BreakpointPromptEditAction::Condition => "Condition when a breakpoint is hit. Expressions within {} are interpolated.",
28574                    BreakpointPromptEditAction::HitCondition => "How many breakpoint hits to ignore",
28575                },
28576                window,
28577                cx,
28578            );
28579
28580            prompt
28581        });
28582
28583        Self {
28584            prompt,
28585            editor,
28586            breakpoint_anchor,
28587            breakpoint,
28588            edit_action,
28589            editor_margins: Arc::new(Mutex::new(EditorMargins::default())),
28590            block_ids: Default::default(),
28591            _subscriptions: vec![],
28592        }
28593    }
28594
28595    pub(crate) fn add_block_ids(&mut self, block_ids: Vec<CustomBlockId>) {
28596        self.block_ids.extend(block_ids)
28597    }
28598
28599    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
28600        if let Some(editor) = self.editor.upgrade() {
28601            let message = self
28602                .prompt
28603                .read(cx)
28604                .buffer
28605                .read(cx)
28606                .as_singleton()
28607                .expect("A multi buffer in breakpoint prompt isn't possible")
28608                .read(cx)
28609                .as_rope()
28610                .to_string();
28611
28612            editor.update(cx, |editor, cx| {
28613                editor.edit_breakpoint_at_anchor(
28614                    self.breakpoint_anchor,
28615                    self.breakpoint.clone(),
28616                    match self.edit_action {
28617                        BreakpointPromptEditAction::Log => {
28618                            BreakpointEditAction::EditLogMessage(message.into())
28619                        }
28620                        BreakpointPromptEditAction::Condition => {
28621                            BreakpointEditAction::EditCondition(message.into())
28622                        }
28623                        BreakpointPromptEditAction::HitCondition => {
28624                            BreakpointEditAction::EditHitCondition(message.into())
28625                        }
28626                    },
28627                    cx,
28628                );
28629
28630                editor.remove_blocks(self.block_ids.clone(), None, cx);
28631                cx.focus_self(window);
28632            });
28633        }
28634    }
28635
28636    fn cancel(&mut self, _: &menu::Cancel, window: &mut Window, cx: &mut Context<Self>) {
28637        self.editor
28638            .update(cx, |editor, cx| {
28639                editor.remove_blocks(self.block_ids.clone(), None, cx);
28640                window.focus(&editor.focus_handle, cx);
28641            })
28642            .log_err();
28643    }
28644
28645    fn render_prompt_editor(&self, cx: &mut Context<Self>) -> impl IntoElement {
28646        let settings = ThemeSettings::get_global(cx);
28647        let text_style = TextStyle {
28648            color: if self.prompt.read(cx).read_only(cx) {
28649                cx.theme().colors().text_disabled
28650            } else {
28651                cx.theme().colors().text
28652            },
28653            font_family: settings.buffer_font.family.clone(),
28654            font_fallbacks: settings.buffer_font.fallbacks.clone(),
28655            font_size: settings.buffer_font_size(cx).into(),
28656            font_weight: settings.buffer_font.weight,
28657            line_height: relative(settings.buffer_line_height.value()),
28658            ..Default::default()
28659        };
28660        EditorElement::new(
28661            &self.prompt,
28662            EditorStyle {
28663                background: cx.theme().colors().editor_background,
28664                local_player: cx.theme().players().local(),
28665                text: text_style,
28666                ..Default::default()
28667            },
28668        )
28669    }
28670
28671    fn render_close_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
28672        let focus_handle = self.prompt.focus_handle(cx);
28673        IconButton::new("cancel", IconName::Close)
28674            .icon_color(Color::Muted)
28675            .shape(IconButtonShape::Square)
28676            .tooltip(move |_window, cx| {
28677                Tooltip::for_action_in("Cancel", &menu::Cancel, &focus_handle, cx)
28678            })
28679            .on_click(cx.listener(|this, _, window, cx| {
28680                this.cancel(&menu::Cancel, window, cx);
28681            }))
28682    }
28683
28684    fn render_confirm_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
28685        let focus_handle = self.prompt.focus_handle(cx);
28686        IconButton::new("confirm", IconName::Return)
28687            .icon_color(Color::Muted)
28688            .shape(IconButtonShape::Square)
28689            .tooltip(move |_window, cx| {
28690                Tooltip::for_action_in("Confirm", &menu::Confirm, &focus_handle, cx)
28691            })
28692            .on_click(cx.listener(|this, _, window, cx| {
28693                this.confirm(&menu::Confirm, window, cx);
28694            }))
28695    }
28696}
28697
28698impl Render for BreakpointPromptEditor {
28699    fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28700        let ui_font_size = ThemeSettings::get_global(cx).ui_font_size(cx);
28701        let editor_margins = *self.editor_margins.lock();
28702        let gutter_dimensions = editor_margins.gutter;
28703        let left_gutter_width = gutter_dimensions.full_width() + (gutter_dimensions.margin / 2.0);
28704        let right_padding = editor_margins.right + px(9.);
28705        h_flex()
28706            .key_context("Editor")
28707            .bg(cx.theme().colors().editor_background)
28708            .border_y_1()
28709            .border_color(cx.theme().status().info_border)
28710            .size_full()
28711            .py(window.line_height() / 2.5)
28712            .pr(right_padding)
28713            .on_action(cx.listener(Self::confirm))
28714            .on_action(cx.listener(Self::cancel))
28715            .child(
28716                WithRemSize::new(ui_font_size)
28717                    .h_full()
28718                    .w(left_gutter_width)
28719                    .flex()
28720                    .flex_row()
28721                    .flex_shrink_0()
28722                    .items_center()
28723                    .justify_center()
28724                    .gap_1()
28725                    .child(self.render_close_button(cx)),
28726            )
28727            .child(
28728                h_flex()
28729                    .w_full()
28730                    .justify_between()
28731                    .child(div().flex_1().child(self.render_prompt_editor(cx)))
28732                    .child(
28733                        WithRemSize::new(ui_font_size)
28734                            .flex()
28735                            .flex_row()
28736                            .items_center()
28737                            .child(self.render_confirm_button(cx)),
28738                    ),
28739            )
28740    }
28741}
28742
28743impl Focusable for BreakpointPromptEditor {
28744    fn focus_handle(&self, cx: &App) -> FocusHandle {
28745        self.prompt.focus_handle(cx)
28746    }
28747}
28748
28749fn all_edits_insertions_or_deletions(
28750    edits: &Vec<(Range<Anchor>, Arc<str>)>,
28751    snapshot: &MultiBufferSnapshot,
28752) -> bool {
28753    let mut all_insertions = true;
28754    let mut all_deletions = true;
28755
28756    for (range, new_text) in edits.iter() {
28757        let range_is_empty = range.to_offset(snapshot).is_empty();
28758        let text_is_empty = new_text.is_empty();
28759
28760        if range_is_empty != text_is_empty {
28761            if range_is_empty {
28762                all_deletions = false;
28763            } else {
28764                all_insertions = false;
28765            }
28766        } else {
28767            return false;
28768        }
28769
28770        if !all_insertions && !all_deletions {
28771            return false;
28772        }
28773    }
28774    all_insertions || all_deletions
28775}
28776
28777struct MissingEditPredictionKeybindingTooltip;
28778
28779impl Render for MissingEditPredictionKeybindingTooltip {
28780    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
28781        ui::tooltip_container(cx, |container, cx| {
28782            container
28783                .flex_shrink_0()
28784                .max_w_80()
28785                .min_h(rems_from_px(124.))
28786                .justify_between()
28787                .child(
28788                    v_flex()
28789                        .flex_1()
28790                        .text_ui_sm(cx)
28791                        .child(Label::new("Conflict with Accept Keybinding"))
28792                        .child("Your keymap currently overrides the default accept keybinding. To continue, assign one keybinding for the `editor::AcceptEditPrediction` action.")
28793                )
28794                .child(
28795                    h_flex()
28796                        .pb_1()
28797                        .gap_1()
28798                        .items_end()
28799                        .w_full()
28800                        .child(Button::new("open-keymap", "Assign Keybinding").size(ButtonSize::Compact).on_click(|_ev, window, cx| {
28801                            window.dispatch_action(zed_actions::OpenKeymapFile.boxed_clone(), cx)
28802                        }))
28803                        .child(Button::new("see-docs", "See Docs").size(ButtonSize::Compact).on_click(|_ev, _window, cx| {
28804                            cx.open_url("https://zed.dev/docs/completions#edit-predictions-missing-keybinding");
28805                        })),
28806                )
28807        })
28808    }
28809}
28810
28811#[derive(Debug, Clone, Copy, PartialEq)]
28812pub struct LineHighlight {
28813    pub background: Background,
28814    pub border: Option<gpui::Hsla>,
28815    pub include_gutter: bool,
28816    pub type_id: Option<TypeId>,
28817}
28818
28819struct LineManipulationResult {
28820    pub new_text: String,
28821    pub line_count_before: usize,
28822    pub line_count_after: usize,
28823}
28824
28825fn render_diff_hunk_controls(
28826    row: u32,
28827    status: &DiffHunkStatus,
28828    hunk_range: Range<Anchor>,
28829    is_created_file: bool,
28830    line_height: Pixels,
28831    editor: &Entity<Editor>,
28832    _window: &mut Window,
28833    cx: &mut App,
28834) -> AnyElement {
28835    h_flex()
28836        .h(line_height)
28837        .mr_1()
28838        .gap_1()
28839        .px_0p5()
28840        .pb_1()
28841        .border_x_1()
28842        .border_b_1()
28843        .border_color(cx.theme().colors().border_variant)
28844        .rounded_b_lg()
28845        .bg(cx.theme().colors().editor_background)
28846        .gap_1()
28847        .block_mouse_except_scroll()
28848        .shadow_md()
28849        .child(if status.has_secondary_hunk() {
28850            Button::new(("stage", row as u64), "Stage")
28851                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28852                .tooltip({
28853                    let focus_handle = editor.focus_handle(cx);
28854                    move |_window, cx| {
28855                        Tooltip::for_action_in(
28856                            "Stage Hunk",
28857                            &::git::ToggleStaged,
28858                            &focus_handle,
28859                            cx,
28860                        )
28861                    }
28862                })
28863                .on_click({
28864                    let editor = editor.clone();
28865                    move |_event, _window, cx| {
28866                        editor.update(cx, |editor, cx| {
28867                            editor.stage_or_unstage_diff_hunks(
28868                                true,
28869                                vec![hunk_range.start..hunk_range.start],
28870                                cx,
28871                            );
28872                        });
28873                    }
28874                })
28875        } else {
28876            Button::new(("unstage", row as u64), "Unstage")
28877                .alpha(if status.is_pending() { 0.66 } else { 1.0 })
28878                .tooltip({
28879                    let focus_handle = editor.focus_handle(cx);
28880                    move |_window, cx| {
28881                        Tooltip::for_action_in(
28882                            "Unstage Hunk",
28883                            &::git::ToggleStaged,
28884                            &focus_handle,
28885                            cx,
28886                        )
28887                    }
28888                })
28889                .on_click({
28890                    let editor = editor.clone();
28891                    move |_event, _window, cx| {
28892                        editor.update(cx, |editor, cx| {
28893                            editor.stage_or_unstage_diff_hunks(
28894                                false,
28895                                vec![hunk_range.start..hunk_range.start],
28896                                cx,
28897                            );
28898                        });
28899                    }
28900                })
28901        })
28902        .child(
28903            Button::new(("restore", row as u64), "Restore")
28904                .tooltip({
28905                    let focus_handle = editor.focus_handle(cx);
28906                    move |_window, cx| {
28907                        Tooltip::for_action_in("Restore Hunk", &::git::Restore, &focus_handle, cx)
28908                    }
28909                })
28910                .on_click({
28911                    let editor = editor.clone();
28912                    move |_event, window, cx| {
28913                        editor.update(cx, |editor, cx| {
28914                            let snapshot = editor.snapshot(window, cx);
28915                            let point = hunk_range.start.to_point(&snapshot.buffer_snapshot());
28916                            editor.restore_hunks_in_ranges(vec![point..point], window, cx);
28917                        });
28918                    }
28919                })
28920                .disabled(is_created_file),
28921        )
28922        .when(
28923            !editor.read(cx).buffer().read(cx).all_diff_hunks_expanded(),
28924            |el| {
28925                el.child(
28926                    IconButton::new(("next-hunk", row as u64), IconName::ArrowDown)
28927                        .shape(IconButtonShape::Square)
28928                        .icon_size(IconSize::Small)
28929                        // .disabled(!has_multiple_hunks)
28930                        .tooltip({
28931                            let focus_handle = editor.focus_handle(cx);
28932                            move |_window, cx| {
28933                                Tooltip::for_action_in("Next Hunk", &GoToHunk, &focus_handle, cx)
28934                            }
28935                        })
28936                        .on_click({
28937                            let editor = editor.clone();
28938                            move |_event, window, cx| {
28939                                editor.update(cx, |editor, cx| {
28940                                    let snapshot = editor.snapshot(window, cx);
28941                                    let position =
28942                                        hunk_range.end.to_point(&snapshot.buffer_snapshot());
28943                                    editor.go_to_hunk_before_or_after_position(
28944                                        &snapshot,
28945                                        position,
28946                                        Direction::Next,
28947                                        true,
28948                                        window,
28949                                        cx,
28950                                    );
28951                                    editor.expand_selected_diff_hunks(cx);
28952                                });
28953                            }
28954                        }),
28955                )
28956                .child(
28957                    IconButton::new(("prev-hunk", row as u64), IconName::ArrowUp)
28958                        .shape(IconButtonShape::Square)
28959                        .icon_size(IconSize::Small)
28960                        // .disabled(!has_multiple_hunks)
28961                        .tooltip({
28962                            let focus_handle = editor.focus_handle(cx);
28963                            move |_window, cx| {
28964                                Tooltip::for_action_in(
28965                                    "Previous Hunk",
28966                                    &GoToPreviousHunk,
28967                                    &focus_handle,
28968                                    cx,
28969                                )
28970                            }
28971                        })
28972                        .on_click({
28973                            let editor = editor.clone();
28974                            move |_event, window, cx| {
28975                                editor.update(cx, |editor, cx| {
28976                                    let snapshot = editor.snapshot(window, cx);
28977                                    let point =
28978                                        hunk_range.start.to_point(&snapshot.buffer_snapshot());
28979                                    editor.go_to_hunk_before_or_after_position(
28980                                        &snapshot,
28981                                        point,
28982                                        Direction::Prev,
28983                                        true,
28984                                        window,
28985                                        cx,
28986                                    );
28987                                    editor.expand_selected_diff_hunks(cx);
28988                                });
28989                            }
28990                        }),
28991                )
28992            },
28993        )
28994        .into_any_element()
28995}
28996
28997pub fn multibuffer_context_lines(cx: &App) -> u32 {
28998    EditorSettings::try_get(cx)
28999        .map(|settings| settings.excerpt_context_lines)
29000        .unwrap_or(2)
29001        .min(32)
29002}